summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine Beaupré <anarcat@debian.org>2017-08-23 16:14:38 -0400
committerAntoine Beaupré <anarcat@debian.org>2017-08-23 16:14:38 -0400
commit6d1022cf63ae836f70a8c9aa3706686e78ee26c8 (patch)
treef5cfba2c2c9382564d94a1a0e7df70c35e4ccfab
parent4b6727023b6bdf312f371e591b45ec607b539dfb (diff)
parent66e6a9296b651d82a4f46bd381f0edef7bdd84d3 (diff)
Merge tag 'upstream/5.4.68'
-rw-r--r--CMakeLists.txt35
-rw-r--r--modules/FindXComposite.cmake26
-rw-r--r--modules/FindXRender.cmake47
-rw-r--r--src/image.cpp89
-rw-r--r--src/image.hpp9
-rw-r--r--src/main.cpp39
-rw-r--r--src/x.cpp338
-rw-r--r--src/x.hpp16
8 files changed, 452 insertions, 147 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3586193..132410a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -18,7 +18,7 @@ else()
set( MANTARGET "maim.1" )
endif()
-add_definitions(-DMAIM_VERSION="v5.4.64")
+add_definitions(-DMAIM_VERSION="v5.4.68")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_SOURCE_DIR}/bin/")
@@ -35,13 +35,15 @@ add_executable( "${BIN_TARGET}" ${source} )
# Obtain library paths and make sure they exist.
set( CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_SOURCE_DIR}/modules" )
-find_package( PNG REQUIRED )
-find_package( JPEG REQUIRED )
-find_package( XRandr REQUIRED )
-find_package( XFixes REQUIRED )
-find_package( X11 REQUIRED )
-find_package( SLOP REQUIRED )
-find_package( Threads REQUIRED )
+find_package( PNG REQUIRED )
+find_package( JPEG REQUIRED )
+find_package( XRandr REQUIRED )
+find_package( XRender REQUIRED )
+find_package( XFixes REQUIRED )
+find_package( XComposite REQUIRED )
+find_package( X11 REQUIRED )
+find_package( SLOP REQUIRED )
+find_package( Threads REQUIRED )
set_property(TARGET ${BIN_TARGET} PROPERTY CXX_STANDARD_REQUIRED ON)
set_property(TARGET ${BIN_TARGET} PROPERTY CXX_STANDARD 11)
@@ -51,8 +53,10 @@ include_directories( ${XRANDR_INCLUDE_DIR}
${X11_INCLUDE_DIR}
${SLOP_INCLUDE_DIR}
${XFIXES_INCLUDE_DIR}
+ ${XCOMPOSITE_INCLUDE_DIR}
${JPEG_INCLUDE_DIR}
${XRANDR_INCLUDE_DIR}
+ ${XRENDER_INCLUDE_DIR}
${PNG_INCLUDE_DIRS} )
# Libraries
@@ -61,10 +65,25 @@ target_link_libraries( ${BIN_TARGET}
${X11_LIBRARIES}
${PNG_LIBRARIES}
${XFIXES_LIBRARY}
+ ${XCOMPOSITE_LIBRARY}
${XRANDR_LIBRARY}
${JPEG_LIBRARIES}
+ ${XRENDER_LIBRARY}
${SLOP_LIBRARIES} )
+if( CMAKE<3.7 )
+ message( WARNING "CMake version is below 3.7, CMake version >= 3.7 is required for unicode support." )
+else()
+ find_package(ICU COMPONENTS uc)
+ set( MAIM_UNICODE TRUE CACHE BOOL "To enable or disable unicode support." )
+ if ( MAIM_UNICODE AND ICU_FOUND )
+ # ICU is required for old nvidia drivers to work for whatever reason.
+ add_definitions(-DCXXOPTS_USE_UNICODE)
+ include_directories( ${ICU_INCLUDE_DIR} )
+ target_link_libraries( ${BIN_TARGET} ${ICU_UC_LIBRARIES} )
+ endif()
+endif()
+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g")
install( TARGETS ${BIN_TARGET} DESTINATION "${CMAKE_INSTALL_PREFIX}/bin" )
diff --git a/modules/FindXComposite.cmake b/modules/FindXComposite.cmake
new file mode 100644
index 0000000..53c22df
--- /dev/null
+++ b/modules/FindXComposite.cmake
@@ -0,0 +1,26 @@
+# - Find XComposite
+# Find the XComposite libraries
+#
+# This module defines the following variables:
+# XCOMPOSITE_FOUND - 1 if XCOMPOSITE_INCLUDE_DIR & XCOMPOSITE_LIBRARY are found, 0 otherwise
+# XCOMPOSITE_INCLUDE_DIR - where to find Xlib.h, etc.
+# XCOMPOSITE_LIBRARY - the X11 library
+#
+
+find_path( XCOMPOSITE_INCLUDE_DIR
+ NAMES X11/extensions/Xcomposite.h
+ PATH_SUFFIXES X11/extensions
+ DOC "The XComposite include directory" )
+
+find_library( XCOMPOSITE_LIBRARY
+ NAMES Xcomposite
+ PATHS /usr/lib /lib
+ DOC "The XComposite library" )
+
+if( XCOMPOSITE_INCLUDE_DIR AND XCOMPOSITE_LIBRARY )
+ set( XCOMPOSITE_FOUND 1 )
+else()
+ set( XCOMPOSITE_FOUND 0 )
+endif()
+
+mark_as_advanced( XCOMPOSITE_INCLUDE_DIR XCOMPOSITE_LIBRARY )
diff --git a/modules/FindXRender.cmake b/modules/FindXRender.cmake
new file mode 100644
index 0000000..8fb45af
--- /dev/null
+++ b/modules/FindXRender.cmake
@@ -0,0 +1,47 @@
+# - Find XRender
+# Find the XRender libraries
+#
+# This module defines the following variables:
+# XRENDER_FOUND - true if XRENDER_INCLUDE_DIR & XRENDER_LIBRARY are found
+# XRENDER_LIBRARIES - Set when Xrender_LIBRARY is found
+# XRENDER_INCLUDE_DIRS - Set when Xrender_INCLUDE_DIR is found
+#
+# XRENDER_INCLUDE_DIR - where to find Xrender.h, etc.
+# XRENDER_LIBRARY - the Xrender library
+#
+
+#=============================================================================
+# Copyright 2013 Corey Clayton <can.of.tuna@gmail.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#=============================================================================
+
+find_path(XRENDER_INCLUDE_DIR NAMES X11/extensions/Xrender.h
+ PATHS /opt/X11/include
+ DOC "The Xrender include directory")
+
+find_library(XRENDER_LIBRARY NAMES Xrender
+ PATHS /opt/X11/lib
+ DOC "The Xrender library")
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Xrender DEFAULT_MSG XRENDER_LIBRARY XRENDER_INCLUDE_DIR)
+
+if(XRENDER_FOUND)
+
+ set(XRENDER_LIBRARIES ${XRENDER_LIBRARY})
+ set(XRENDER_INCLUDE_DIRS ${XRENDER_INCLUDE_DIR})
+
+endif()
+
+mark_as_advanced(XRENDER_INCLUDE_DIR XRENDER_LIBRARY)
diff --git a/src/image.cpp b/src/image.cpp
index 7d103e0..a40880a 100644
--- a/src/image.cpp
+++ b/src/image.cpp
@@ -9,7 +9,7 @@ ARGBImage::ARGBImage( XImage* image, glm::ivec2 iloc, glm::ivec4 selectionrect,
this->imagey = iloc.y;
this->channels = channels;
glm::ivec2 spos = glm::ivec2( selectionrect.x, selectionrect.y );
- glm::ivec2 offset = spos-iloc;
+ offset = spos-iloc;
long long int alpha_mask = ~(image->red_mask|image->green_mask|image->blue_mask);
long long int roffset = get_shift(image->red_mask);
long long int goffset = get_shift(image->green_mask);
@@ -116,16 +116,16 @@ void ARGBImage::writePNG( std::ostream& streamout, int quality ) {
throw new std::invalid_argument("Quality argument must be between 1 and 10");
}
png_structp png = NULL;
- png_infop info = NULL;
- png_bytep *rows = new png_bytep[height];
+ png_infop info = NULL;
+ png_bytep *rows = new png_bytep[height];
- png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if(!png) throw new std::runtime_error( "Failed to write png image" );
- info = png_create_info_struct(png);
- if(!info) throw new std::runtime_error( "Failed to write png image" );
+ png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+ if(!png) throw new std::runtime_error( "Failed to write png image" );
+ info = png_create_info_struct(png);
+ if(!info) throw new std::runtime_error( "Failed to write png image" );
png_set_error_fn(png, png_get_error_ptr(png), user_error_fn, user_warning_fn);
png_set_write_fn(png, &streamout, png_write_ostream, png_flush_ostream);
- png_set_compression_level(png, quality-1);
+ png_set_compression_level(png, quality-1);
if ( channels == 4 ) {
png_set_IHDR(png, info, width, height,
8, PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
@@ -150,7 +150,7 @@ void init_buffer(jpeg_compress_struct* cinfo) {}
* happen since we allocated our buffer to be big to start with
*/
boolean empty_buffer(jpeg_compress_struct* cinfo) {
- return TRUE;
+ return TRUE;
}
/* finalize the buffer and do any cleanup stuff */
@@ -160,45 +160,45 @@ void ARGBImage::writeJPEG( std::ostream& streamout, int quality ) {
if ( channels != 3 ) {
throw new std::runtime_error( "JPEG tried to save image with more than 3 channels." );
}
- struct jpeg_compress_struct cinfo;
- struct jpeg_error_mgr jerr;
- struct jpeg_destination_mgr dmgr;
+ struct jpeg_compress_struct cinfo;
+ struct jpeg_error_mgr jerr;
+ struct jpeg_destination_mgr dmgr;
- /* create our in-memory output buffer to hold the jpeg */
- JOCTET * out_buffer = new JOCTET[width * height *3];
+ /* create our in-memory output buffer to hold the jpeg */
+ JOCTET * out_buffer = new JOCTET[width * height *3];
- /* here is the magic */
- dmgr.init_destination = init_buffer;
- dmgr.empty_output_buffer = empty_buffer;
- dmgr.term_destination = term_buffer;
- dmgr.next_output_byte = out_buffer;
- dmgr.free_in_buffer = width * height *3;
+ /* here is the magic */
+ dmgr.init_destination = init_buffer;
+ dmgr.empty_output_buffer = empty_buffer;
+ dmgr.term_destination = term_buffer;
+ dmgr.next_output_byte = out_buffer;
+ dmgr.free_in_buffer = width * height *3;
- cinfo.err = jpeg_std_error(&jerr);
- jpeg_create_compress(&cinfo);
+ cinfo.err = jpeg_std_error(&jerr);
+ jpeg_create_compress(&cinfo);
- /* make sure we tell it about our manager */
- cinfo.dest = &dmgr;
+ /* make sure we tell it about our manager */
+ cinfo.dest = &dmgr;
- cinfo.image_width = width;
- cinfo.image_height = height;
- cinfo.input_components = 3;
- cinfo.in_color_space = JCS_RGB;
+ cinfo.image_width = width;
+ cinfo.image_height = height;
+ cinfo.input_components = 3;
+ cinfo.in_color_space = JCS_RGB;
- jpeg_set_defaults(&cinfo);
+ jpeg_set_defaults(&cinfo);
// Convert quality from scale 1-10 to 0-100
- jpeg_set_quality (&cinfo, (int)((float)quality-1.f)*(100.f/9.f), true);
- jpeg_start_compress(&cinfo, true);
+ jpeg_set_quality (&cinfo, (int)((float)quality-1.f)*(100.f/9.f), true);
+ jpeg_start_compress(&cinfo, true);
- JSAMPROW row_pointer;
- unsigned char* buffer = (unsigned char*)data;
+ JSAMPROW row_pointer;
+ unsigned char* buffer = (unsigned char*)data;
- /* main code to write jpeg data */
- while (cinfo.next_scanline < cinfo.image_height) {
- row_pointer = (JSAMPROW) &buffer[cinfo.next_scanline * 3*width];
- jpeg_write_scanlines(&cinfo, &row_pointer, 1);
- }
- jpeg_finish_compress(&cinfo);
+ /* main code to write jpeg data */
+ while (cinfo.next_scanline < cinfo.image_height) {
+ row_pointer = (JSAMPROW) &buffer[cinfo.next_scanline * 3*width];
+ jpeg_write_scanlines(&cinfo, &row_pointer, 1);
+ }
+ jpeg_finish_compress(&cinfo);
streamout.write( (const char*)out_buffer, cinfo.dest->next_output_byte - out_buffer );
delete[] out_buffer;
@@ -267,6 +267,9 @@ void ARGBImage::mask(X11* x11) {
}
void ARGBImage::blendCursor( X11* x11 ) {
+ if ( !x11->haveXFixes ) {
+ return;
+ }
XFixesCursorImage* xcursor = XFixesGetCursorImage( x11->display );
if ( !xcursor ) {
return;
@@ -276,8 +279,8 @@ void ARGBImage::blendCursor( X11* x11 ) {
for ( unsigned int i=0;i<xcursor->width*xcursor->height;i++ ) {
((unsigned int*)pixels)[ i ] = (unsigned int)xcursor->pixels[ i ];
}
- xcursor->y -= xcursor->yhot;
- xcursor->x -= xcursor->xhot;
+ xcursor->y -= xcursor->yhot + offset.x;
+ xcursor->x -= xcursor->xhot + offset.y;
for ( int y = glm::max(0,xcursor->y-imagey); y<glm::min((int)height,xcursor->y+xcursor->height-imagey);y++ ) {
for ( int x = glm::max(0,xcursor->x-imagex); x < glm::min((int)width,xcursor->x+xcursor->width-imagex);x++ ) {
int cx = x-(xcursor->x-imagex);
@@ -286,6 +289,10 @@ void ARGBImage::blendCursor( X11* x11 ) {
data[(y*width+x)*channels] = data[(y*width+x)*channels]*(1-alpha) + pixels[(cy*xcursor->width+cx)*4+2]*alpha;
data[(y*width+x)*channels+1] = data[(y*width+x)*channels+1]*(1-alpha) + pixels[(cy*xcursor->width+cx)*4+1]*alpha;
data[(y*width+x)*channels+2] = data[(y*width+x)*channels+2]*(1-alpha) + pixels[(cy*xcursor->width+cx)*4]*alpha;
+ // If the original image has alpha, we need to override it.
+ if ( channels == 4 ) {
+ data[(y*width+x)*channels+3] = glm::min(data[(y*width+x)*channels+3]+pixels[(cy*xcursor->width+cx)*4+3],255);
+ }
}
}
}
diff --git a/src/image.hpp b/src/image.hpp
index 7ede7f8..895521a 100644
--- a/src/image.hpp
+++ b/src/image.hpp
@@ -32,16 +32,17 @@
#include "x.hpp"
static inline unsigned char computeRGBPixel(unsigned char* data, XImage* image, int x, int y, int roffset, int goffset, int boffset, int width, glm::ivec2 offset ) {
- unsigned int real = XGetPixel(image, x, y);
int curpixel = ((y-offset.y)*width+((x-offset.x)))*3;
+ unsigned int real = XGetPixel(image, x, y);
data[curpixel] = (unsigned char)((real & image->red_mask) >> roffset);
data[curpixel+1] = (unsigned char)((real & image->green_mask) >> goffset);
data[curpixel+2] = (unsigned char)((real & image->blue_mask) >> boffset);
}
static inline unsigned char computeRGBAPixel(unsigned char* data, XImage* image, int x, int y, int roffset, int goffset, int boffset, int aoffset, int width, glm::ivec2 offset ) {
+ int curpixel = ((y-offset.y)*width+(x-offset.x))*4;
+ //unsigned int real = ((unsigned int*)image->data)[curpixel/4];
unsigned int real = XGetPixel(image, x, y);
- int curpixel = ((y-offset.y)*width+((x-offset.x)))*4;
data[curpixel] = (unsigned char)((real & image->red_mask) >> roffset);
data[curpixel+1] = (unsigned char)((real & image->green_mask) >> goffset);
data[curpixel+2] = (unsigned char)((real & image->blue_mask) >> boffset);
@@ -49,8 +50,9 @@ static inline unsigned char computeRGBAPixel(unsigned char* data, XImage* image,
}
static inline unsigned char computeRGBAPixel(unsigned char* data, XImage* image, int x, int y, int roffset, int goffset, int boffset, int width, glm::ivec2 offset ) {
- unsigned int real = XGetPixel(image, x, y);
int curpixel = ((y-offset.y)*width+((x-offset.x)))*4;
+ //unsigned int real = ((unsigned int*)image->data)[curpixel/4];
+ unsigned int real = XGetPixel(image, x, y);
data[curpixel] = (unsigned char)((real & image->red_mask) >> roffset);
data[curpixel+1] = (unsigned char)((real & image->green_mask) >> goffset);
data[curpixel+2] = (unsigned char)((real & image->blue_mask) >> boffset);
@@ -74,6 +76,7 @@ private:
unsigned int height;
unsigned int channels;
int imagex, imagey;
+ glm::ivec2 offset;
bool intersect( XRRCrtcInfo* a, glm::vec4 b );
bool containsCompletely( XRRCrtcInfo* a, glm::vec4 b );
public:
diff --git a/src/main.cpp b/src/main.cpp
index 3ba1cd3..3fa31ae 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -216,7 +216,7 @@ MaimOptions* getMaimOptions( cxxopts::Options& options, X11* x11 ) {
slop::SlopOptions* getSlopOptions( cxxopts::Options& options ) {
slop::SlopOptions* foo = new slop::SlopOptions();
if ( options.count( "bordersize" ) > 0 ) {
- foo->borderSize = options["bordersize"].as<float>();
+ foo->border = options["bordersize"].as<float>();
}
if ( options.count( "padding" ) > 0 ) {
foo->padding = options["padding"].as<float>();
@@ -235,16 +235,25 @@ slop::SlopOptions* getSlopOptions( cxxopts::Options& options ) {
if ( options.count( "nokeyboard" ) > 0 ) {
foo->nokeyboard = options["nokeyboard"].as<bool>();
}
+ if ( options.count( "noopengl" ) > 0 ) {
+ foo->noopengl = options["noopengl"].as<bool>();
+ }
if ( options.count( "xdisplay" ) > 0 ) {
- foo->xdisplay = options["xdisplay"].as<std::string>();
+ std::string xdisplay = options["xdisplay"].as<std::string>();
+ char* cxdisplay = new char[xdisplay.length()+1];
+ memcpy( cxdisplay, xdisplay.c_str(), xdisplay.length() );
+ cxdisplay[xdisplay.length()]='\0';
+ foo->xdisplay = cxdisplay;
}
- std::string shaders = "textured";
if ( options.count( "shader" ) > 0 ) {
- shaders = options["shader"].as<std::string>();
+ std::string shaders = options["shader"].as<std::string>();
+ char* cshaders = new char[shaders.length()+1];
+ memcpy( cshaders, shaders.c_str(), shaders.length() );
+ cshaders[shaders.length()]='\0';
+ foo->shaders = cshaders;
}
- foo->shaders = split( shaders, ',' );
- if ( options.count( "noopengl" ) > 0 ) {
- foo->noopengl = options["noopengl"].as<bool>();
+ if ( options.count( "quiet" ) > 0 ) {
+ foo->quiet = options["quiet"].as<bool>();
}
if ( options.count( "highlight" ) > 0 ) {
foo->highlight = options["highlight"].as<bool>();
@@ -429,15 +438,14 @@ int app( int argc, char** argv ) {
help();
return 0;
}
- bool cancelled = false;
- slop::SlopSelection selection(0,0,0,0,0);
+ slop::SlopSelection selection(0,0,0,0,0,true);
if ( maimOptions->select ) {
if ( maimOptions->windowGiven || maimOptions->parentGiven || maimOptions->geometryGiven ) {
throw new std::invalid_argument( "Interactive mode (--select) doesn't support the following parameters: --window, --parent, --geometry." );
}
- selection = SlopSelect(slopOptions, &cancelled, maimOptions->quiet);
- if ( cancelled ) {
+ selection = SlopSelect(slopOptions);
+ if ( selection.cancelled ) {
if ( !maimOptions->quiet ) {
std::cerr << "Selection was cancelled by keystroke or right-click.\n";
}
@@ -551,6 +559,7 @@ int app( int argc, char** argv ) {
// Then output it in the desired format.
convert.writeJPEG(*out, maimOptions->quality );
}
+ XDestroyImage( image );
if ( maimOptions->savepathGiven ) {
std::ofstream* file = (std::ofstream*)out;
@@ -559,9 +568,15 @@ int app( int argc, char** argv ) {
}
delete x11;
delete maimOptions;
+ if ( options.count( "xdisplay" ) > 0 ) {
+ delete slopOptions->xdisplay;
+ }
+ if ( options.count( "shader" ) > 0 ) {
+ delete slopOptions->shaders;
+ }
delete slopOptions;
- return 0;
+ return 0;
}
int main( int argc, char** argv ) {
diff --git a/src/x.cpp b/src/x.cpp
index 0dd3011..f4168d4 100644
--- a/src/x.cpp
+++ b/src/x.cpp
@@ -6,31 +6,79 @@ TmpXError(Display * d, XErrorEvent * ev) {
_x_err = 1;
return 0;
}
-/*
-glm::ivec4 getWindowGeometry( X11* x11, Window win ) {
- XWindowAttributes attr;
- XGetWindowAttributes( x11->display, win, &attr );
- unsigned int width = attr.width;
- unsigned int height = attr.height;
- unsigned int border = attr.border_width;
- int x, y;
- Window junk;
- XTranslateCoordinates( x11->display, win, attr.root, 0, 0, &x, &y, &junk );
- return glm::vec4( x, y, width, height );
-}
-*/
+
glm::ivec4 getWindowGeometry( X11* x11, Window win ) {
- XWindowAttributes attr;
- XGetWindowAttributes( x11->display, win, &attr );
- unsigned int width = attr.width;
- unsigned int height = attr.height;
- unsigned int border = attr.border_width;
- int x, y;
- Window junk;
- XTranslateCoordinates( x11->display, win, attr.root, -attr.border_width, -attr.border_width, &x, &y, &junk );
- width += border*2;
- height += border*2;
- return glm::vec4( x, y, width, height );
+ // First lets check for if we're a window manager frame.
+ Window root, parent;
+ Window* children;
+ unsigned int num_children;
+ XQueryTree( x11->display, win, &root, &parent, &children, &num_children);
+
+ // To do that, we check if our top level child happens to have the _NET_FRAME_EXTENTS atom.
+ unsigned char *data;
+ Atom type_return;
+ unsigned long nitems_return;
+ unsigned long bytes_after_return;
+ int format_return;
+ bool window_frame = false;
+ Window actualWindow = win;
+ if ( num_children > 0 && XGetWindowProperty( x11->display, children[num_children-1],
+ XInternAtom( x11->display, "_NET_FRAME_EXTENTS", False),
+ 0, LONG_MAX, False, XA_CARDINAL, &type_return,
+ &format_return, &nitems_return, &bytes_after_return,
+ &data) == Success ) {
+ if ((type_return == XA_CARDINAL) && (format_return == 32) && (nitems_return == 4) && (data)) {
+ actualWindow = children[num_children-1];
+ window_frame = true;
+ }
+ }
+ XFree( children );
+
+ // If we're a window frame, we actually get the dimensions of the child window, then add the _NET_FRAME_EXTENTS to it.
+ // (then add the border width of the window frame after that.)
+ if ( window_frame ) {
+ // First lets grab the border width.
+ XWindowAttributes frameattr;
+ XGetWindowAttributes( x11->display, win, &frameattr );
+ // Then lets grab the dims of the child window.
+ XWindowAttributes attr;
+ XGetWindowAttributes( x11->display, actualWindow, &attr );
+ unsigned int width = attr.width;
+ unsigned int height = attr.height;
+ // We combine both border widths.
+ unsigned int border = attr.border_width+frameattr.border_width;
+ int x, y;
+ // Gotta translate them into root coords, we can adjust for the border width here.
+ Window junk;
+ XTranslateCoordinates( x11->display, actualWindow, attr.root, -border, -border, &x, &y, &junk );
+ width += border*2;
+ height += border*2;
+ // Now uh, remember that _NET_FRAME_EXTENTS stuff? That's the window frame information.
+ // We HAVE to do this because mutter likes to mess with window sizes with shadows and stuff.
+ unsigned long* ldata = (unsigned long*)data;
+ width += ldata[0] + ldata[1];
+ height += ldata[2] + ldata[3];
+ x -= ldata[0];
+ y -= ldata[2];
+ XFree( data );
+ return glm::vec4( x, y, width, height );
+ } else {
+ // Either the WM is malfunctioning, or the window secified isn't a window manager frame.
+ // so we just rely on X.
+ XWindowAttributes attr;
+ XGetWindowAttributes( x11->display, win, &attr );
+ unsigned int width = attr.width;
+ unsigned int height = attr.height;
+ // We combine both border widths.
+ unsigned int border = attr.border_width;
+ int x, y;
+ // Gotta translate them into root coords, we can adjust for the border width here.
+ Window junk;
+ XTranslateCoordinates( x11->display, win, attr.root, -border, -border, &x, &y, &junk );
+ width += border*2;
+ height += border*2;
+ return glm::vec4( x, y, width, height );
+ }
}
std::vector<XRRCrtcInfo*> X11::getCRTCS() {
@@ -51,35 +99,49 @@ void X11::freeCRTCS( std::vector<XRRCrtcInfo*> monitors ) {
}
X11::X11( std::string displayName ) {
- // Initialize display
- display = XOpenDisplay( displayName.c_str() );
- if ( !display ) {
- throw new std::runtime_error(std::string("Error: Failed to open X display: ") + displayName );
- }
- screen = ScreenOfDisplay( display, DefaultScreen( display ) );
- visual = DefaultVisual( display, XScreenNumberOfScreen( screen ) );
- root = DefaultRootWindow( display );
+ // Initialize display
+ display = XOpenDisplay( displayName.c_str() );
+ if ( !display ) {
+ throw new std::runtime_error(std::string("Error: Failed to open X display: ") + displayName );
+ }
+ screen = ScreenOfDisplay( display, DefaultScreen( display ) );
+ visual = DefaultVisual( display, XScreenNumberOfScreen( screen ) );
+ root = DefaultRootWindow( display );
int major = 0;
int minor = 0;
Bool pixmaps = true;
- haveXShm = XShmQueryVersion( display, &major, &minor, &pixmaps );
+ haveXShm = (True == XShmQueryVersion( display, &major, &minor, &pixmaps ));
haveXShm = (haveXShm && pixmaps );
+ major = 2;
+ minor = 0;
+ haveXFixes = (True == XFixesQueryVersion ( display, &major, &minor ));
+ major = 0;
+ minor = 0;
+ haveXRR = (True == XRRQueryVersion( display, &major, &minor ) );
+ major = 0;
+ minor = 2;
+ haveXComposite = (True == XCompositeQueryVersion( display, &major, &minor ));
major = 0;
minor = 0;
- haveXRR = XRRQueryVersion( display, &major, &minor );
+ haveXRender = (True == XRenderQueryVersion( display, &major, &minor ));
+
if ( haveXRR ) {
res = XRRGetScreenResourcesCurrent( display, root );
}
}
X11::~X11() {
- XCloseDisplay( display );
+ if ( haveXRR ) {
+ XRRFreeScreenResources( res );
+ }
+ XCloseDisplay( display );
}
XImage* X11::getImage( Window draw, int x, int y, int w, int h, glm::ivec2& imageloc ) {
glm::ivec4 sourceGeo = getWindowGeometry( this, draw );
// We need to clamp the selection to fit within the
// provided window.
+
x = glm::clamp( x, sourceGeo.x, sourceGeo.x+sourceGeo.z );
y = glm::clamp( y, sourceGeo.y, sourceGeo.y+sourceGeo.w );
w = glm::clamp( w, 1, sourceGeo.x+sourceGeo.z-x );
@@ -87,57 +149,173 @@ XImage* X11::getImage( Window draw, int x, int y, int w, int h, glm::ivec2& imag
imageloc = glm::ivec2( x, y );
+ // Translate the newly clamped selection to local coordinates.
+ int localx, localy;
+ Window junk;
+ XTranslateCoordinates( this->display, this->root, draw, x, y, &localx, &localy, &junk);
- // This is a HUGE no-no, but it keeps the image from changing under our feet.
- XGrabServer(display);
- if ( haveXShm ) {
- // Try to grab the image through shared memory, if we fail try another method.
- XErrorHandler ph = XSetErrorHandler(TmpXError);
- XImage* image = getImageShm( draw, x, y, w, h );
- XSetErrorHandler(ph);
- if ( !_x_err && image != None ) {
- XUngrabServer(display);
- return image;
+ if ( haveXComposite ) {
+ // We redirect all the pixmaps offscreen, so that they won't be corrupted if obscured.
+ for ( int i = 0; i < ScreenCount( display ); i++ ) {
+ XCompositeRedirectSubwindows( display, RootWindow( display, i ), CompositeRedirectAutomatic );
}
+ // We don't have to worry about undoing the redirect, since as soon as maim closes X knows to undo it.
}
- Window junk;
- XTranslateCoordinates( this->display, this->root, draw, x, y, &x, &y, &junk);
- XUngrabServer(display);
- return XGetImage( display, draw, x, y, w, h, AllPlanes, ZPixmap );
+ if ( haveXRender && haveXFixes ) {
+ return getImageUsingXRender( draw, localx, localy, w, h );
+ }
+ // This stuff doesn't work very well...
+ //if ( haveXShm ) {
+ //XErrorHandler ph = XSetErrorHandler(TmpXError);
+ //XImage* check = getImageUsingXShm( draw, localx, localy, w, h );
+ //XSetErrorHandler(ph);
+ //if ( !_x_err && check != None ) {
+ //return check;
+ //}
+ //}
+ return XGetImage( display, draw, localx, localy, w, h, AllPlanes, ZPixmap );
}
-// Basically a faster image grabber.
-XImage* X11::getImageShm(Window draw, int x, int y, int w, int h) {
- XImage* xim;
- XShmSegmentInfo thing;
+XImage* X11::getImageUsingXRender( Window draw, int localx, int localy, int w, int h ) {
+ // We use XRender to grab the drawable, since it'll save it in a format we like.
+ XWindowAttributes attr;
+ XGetWindowAttributes( display, draw, &attr );
+ XRenderPictFormat *format = XRenderFindVisualFormat( display, attr.visual );
+ bool hasAlpha = ( format->type == PictTypeDirect && format->direct.alphaMask );
+ XRenderPictureAttributes pa;
+ pa.subwindow_mode = IncludeInferiors;
+ Picture picture = XRenderCreatePicture( display, draw, format, CPSubwindowMode, &pa );
+ if ( draw != root ) {
+ XserverRegion region = findRegion( draw );
+ // Also we use XRender because of this neato function here.
+ XFixesSetPictureClipRegion( display, picture, 0, 0, region );
+ XFixesDestroyRegion( display, region );
+ }
- XWindowAttributes xattr;
- Status s = XGetWindowAttributes (display, draw, &xattr);
+ Pixmap pixmap = XCreatePixmap(display, root, w, h, 32);
+ XRenderPictureAttributes pa2;
- /* try create an shm image */
- xim = XShmCreateImage(display, xattr.visual, xattr.depth, ZPixmap, 0, &thing, w, h);
- if (!xim) {
- return None;
- }
-
- /* get an shm id of this image */
- thing.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, IPC_CREAT | 0666);
- /* if the get succeeds */
- if (thing.shmid != -1) {
- /* set the params for the shm segment */
- thing.readOnly = False;
- thing.shmaddr = xim->data = (char*)shmat(thing.shmid, 0, 0);
- /* get the shm addr for this data chunk */
- if (xim->data != (char *)-1) {
- XShmAttach(display, &thing);
- XShmGetImage(display, draw, xim, x, y, 0xffffffff);
- return xim;
- //shmdt(thing.shmaddr);
+ XRenderPictFormat *format2 = XRenderFindStandardFormat(display, PictStandardARGB32);
+ Picture pixmapPicture = XRenderCreatePicture( display, pixmap, format2, 0, &pa2 );
+ XRenderColor c;
+ c.red = 0x0000;
+ c.green = 0x0000;
+ c.blue = 0x0000;
+ c.alpha = 0x0000;
+ XRenderFillRectangle (display, PictOpSrc, pixmapPicture, &c, 0, 0, w, h);
+ XRenderComposite(display, hasAlpha ? PictOpOver : PictOpSrc, picture, 0,
+ pixmapPicture, localx, localy, 0, 0, 0, 0,
+ w, h);
+ XImage* temp = XGetImage( display, pixmap, 0, 0, w, h, AllPlanes, ZPixmap );
+ temp->red_mask = format2->direct.redMask << format2->direct.red;
+ temp->green_mask = format2->direct.greenMask << format2->direct.green;
+ temp->blue_mask = format2->direct.blueMask << format2->direct.blue;
+ temp->depth = format2->depth;
+ return temp;
+}
+
+bool X11::hasClipping( Window d ) {
+ int bShaped, xbs, ybs, cShaped, xcs, ycs;
+ unsigned int wbs, hbs, wcs, hcs;
+ XShapeQueryExtents ( display, d, &bShaped, &xbs, &ybs, &wbs, &hbs, &cShaped, &xcs, &ycs, &wcs, &hcs );
+ return bShaped;
+}
+
+XserverRegion X11::findRegion( Window d ) {
+ XserverRegion rootRegion = XFixesCreateRegionFromWindow( display, d, WindowRegionBounding );
+ glm::vec4 rootgeo = getWindowGeometry( this, d );
+ XFixesTranslateRegion( display, rootRegion, rootgeo.x, rootgeo.y ); // Regions are in respect to the root window by default.
+ unionClippingRegions( rootRegion, d );
+ unionBorderRegions( rootRegion, d );
+ return rootRegion;
+}
+
+void X11::unionBorderRegions( XserverRegion rootRegion, Window d ) {
+ glm::vec4 bordergeo = getWindowGeometry( this, d );
+ XRectangle* rects = new XRectangle[1];
+ rects[0].x = bordergeo.x;
+ rects[0].y = bordergeo.y;
+ rects[0].width = bordergeo.z;
+ rects[0].height = bordergeo.w;
+ XserverRegion borderRegionRect = XFixesCreateRegion( display, rects, 1 );
+ XWindowAttributes attr;
+ XGetWindowAttributes( display, d, &attr );
+ rects[0].x += attr.border_width;
+ rects[0].y += attr.border_width;
+ rects[0].width -= attr.border_width*2;
+ rects[0].height -= attr.border_width*2;
+ XserverRegion regionRect = XFixesCreateRegion( display, rects, 1 );
+ XFixesSubtractRegion( display, regionRect, borderRegionRect, regionRect );
+ delete[] rects;
+ XFixesUnionRegion( display, rootRegion, rootRegion, regionRect );
+ XFixesDestroyRegion( display, regionRect );
+ XFixesDestroyRegion( display, borderRegionRect );
+}
+
+void X11::unionClippingRegions( XserverRegion rootRegion, Window child ) {
+ Window root, parent;
+ Window* children;
+ unsigned int num_children;
+ XQueryTree( display, child, &root, &parent, &children, &num_children);
+ for ( unsigned int i=0;i<num_children;i++ ) {
+ if ( hasClipping( children[i] ) ) {
+ Window clippingWindow = children[i];
+ glm::vec4 geo = getWindowGeometry( this, clippingWindow );
+ XRectangle* rects = new XRectangle[1];
+ rects[0].x = geo.x;
+ rects[0].y = geo.y;
+ rects[0].width = geo.z;
+ rects[0].height = geo.w;
+ // We have to keep the parent's region from interfering the clipping region.
+ XserverRegion clippingWindowRect = XFixesCreateRegion( display, rects, 1 );
+ delete[] rects;
+ // So we cut a neat hole the size of the child window where the clipping happens.
+ XFixesSubtractRegion( display, rootRegion, rootRegion, clippingWindowRect );
+ XFixesDestroyRegion( display, clippingWindowRect );
+ XserverRegion childRegion = XFixesCreateRegionFromWindow( display, clippingWindow, WindowRegionBounding );
+ XFixesTranslateRegion( display, childRegion, geo.x, geo.y ); // Regions are in respect to the root window by default.
+ XFixesUnionRegion( display, rootRegion, rootRegion, childRegion );
+ XFixesDestroyRegion( display, childRegion );
+ // We don't desend deeper down the tree looking for more clipping regions, I just don't want to support
+ // applications that do that...
+ } else {
+ unionClippingRegions( rootRegion, children[i] );
+ }
}
- /* get failed - out of shm id's or shm segment too big ? */
- /* remove the shm id we created */
- shmctl(thing.shmid, IPC_RMID, 0);
- shmdt(thing.shmaddr);
- }
- return None;
+ XFree( children );
+}
+
+XImage* X11::getImageUsingXShm(Window draw, int localx, int localy, int w, int h) {
+ XImage* xim;
+ XShmSegmentInfo thing;
+
+ XWindowAttributes xattr;
+ Status s = XGetWindowAttributes (display, draw, &xattr);
+
+ /* try create an shm image */
+ xim = XShmCreateImage(display, xattr.visual, xattr.depth, ZPixmap, 0, &thing, w, h);
+ if (!xim) {
+ return None;
+ }
+
+ /* get an shm id of this image */
+ thing.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, IPC_CREAT | 0777);
+ /* if the get succeeds */
+ if (thing.shmid != -1) {
+ /* set the params for the shm segment */
+ thing.readOnly = False;
+ thing.shmaddr = xim->data = (char*)shmat(thing.shmid, 0, 0);
+ /* get the shm addr for this data chunk */
+ if (xim->data != (char *)-1) {
+ XShmAttach(display, &thing);
+ XShmGetImage(display, draw, xim, localx, localy, AllPlanes);
+ return xim;
+ //shmdt(thing.shmaddr);
+ }
+ /* get failed - out of shm id's or shm segment too big ? */
+ /* remove the shm id we created */
+ shmctl(thing.shmid, IPC_RMID, 0);
+ shmdt(thing.shmaddr);
+ }
+ return None;
}
diff --git a/src/x.hpp b/src/x.hpp
index de36cb4..d54bc65 100644
--- a/src/x.hpp
+++ b/src/x.hpp
@@ -23,10 +23,13 @@
#include <iostream>
#include <X11/Xlib.h>
+#include <X11/Xatom.h>
#include <X11/extensions/XShm.h>
#include <X11/extensions/Xrender.h>
+#include <X11/extensions/shape.h>
#include <X11/extensions/Xcomposite.h>
#include <X11/extensions/Xrandr.h>
+//#include <meta/meta-shadow-factory.h>
#include <sys/shm.h>
#include <string>
#include <vector>
@@ -35,9 +38,17 @@
class X11 {
private:
- bool haveXShm;
- XImage* getImageShm( Window d, int x, int y, int w, int h );
+ bool hasClipping( Window d );
+ XserverRegion findRegion( Window d );
+ void unionClippingRegions( XserverRegion rootRegion, Window child );
+ void unionBorderRegions( XserverRegion rootRegion, Window d );
+ XImage* getImageUsingXRender( Window draw, int localx, int localy, int w, int h );
+ XImage* getImageUsingXShm( Window draw, int localx, int localy, int w, int h );
public:
+ bool haveXComposite;
+ bool haveXRender;
+ bool haveXShm;
+ bool haveXFixes;
bool haveXRR;
X11( std::string displayName );
~X11();
@@ -52,6 +63,5 @@ public:
};
glm::ivec4 getWindowGeometry( X11* x11, Window win );
-//glm::ivec4 getWindowGeometryWithoutBorder( X11* x11, Window win );
#endif