I have made another delayed NMU for the 5.4.68 release, because the
latest slop upload breaks it as well...

A.

diff -Nru maim-5.4.64/CMakeLists.txt maim-5.4.68/CMakeLists.txt
--- maim-5.4.64/CMakeLists.txt  2017-07-20 10:05:29.000000000 -0400
+++ maim-5.4.68/CMakeLists.txt  2017-08-15 21:35:19.000000000 -0400
@@ -18,7 +18,7 @@
     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 @@
 
 # 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 @@
                      ${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 @@
                        ${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 -Nru maim-5.4.64/debian/changelog maim-5.4.68/debian/changelog
--- maim-5.4.64/debian/changelog        2017-07-29 10:45:07.000000000 -0400
+++ maim-5.4.68/debian/changelog        2017-08-23 16:14:51.000000000 -0400
@@ -1,3 +1,10 @@
+maim (5.4.68-1.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * New upstream release
+
+ -- Antoine Beaupré <anar...@debian.org>  Wed, 23 Aug 2017 16:14:51 -0400
+
 maim (5.4.64-1.1) unstable; urgency=medium
 
   * Non-maintainer upload.
diff -Nru maim-5.4.64/modules/FindXComposite.cmake 
maim-5.4.68/modules/FindXComposite.cmake
--- maim-5.4.64/modules/FindXComposite.cmake    1969-12-31 19:00:00.000000000 
-0500
+++ maim-5.4.68/modules/FindXComposite.cmake    2017-08-15 21:35:19.000000000 
-0400
@@ -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 -Nru maim-5.4.64/modules/FindXRender.cmake 
maim-5.4.68/modules/FindXRender.cmake
--- maim-5.4.64/modules/FindXRender.cmake       1969-12-31 19:00:00.000000000 
-0500
+++ maim-5.4.68/modules/FindXRender.cmake       2017-08-15 21:35:19.000000000 
-0400
@@ -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.t...@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 -Nru maim-5.4.64/src/image.cpp maim-5.4.68/src/image.cpp
--- maim-5.4.64/src/image.cpp   2017-07-20 10:05:29.000000000 -0400
+++ maim-5.4.68/src/image.cpp   2017-08-15 21:35:19.000000000 -0400
@@ -9,7 +9,7 @@
     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 @@
         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 @@
  * 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 @@
     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;
- 
-       /* 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;
- 
-       cinfo.err = jpeg_std_error(&jerr);
-       jpeg_create_compress(&cinfo);
- 
-       /* 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;
+    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];
+ 
+    /* 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);
+ 
+    /* 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;
  
-       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::blendCursor( X11* x11 ) {
+    if ( !x11->haveXFixes ) {
+        return;
+    }
     XFixesCursorImage* xcursor = XFixesGetCursorImage( x11->display );
     if ( !xcursor ) {
         return;
@@ -276,8 +279,8 @@
     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 @@
             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 -Nru maim-5.4.64/src/image.hpp maim-5.4.68/src/image.hpp
--- maim-5.4.64/src/image.hpp   2017-07-20 10:05:29.000000000 -0400
+++ maim-5.4.68/src/image.hpp   2017-08-15 21:35:19.000000000 -0400
@@ -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, 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 @@
     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 -Nru maim-5.4.64/src/main.cpp maim-5.4.68/src/main.cpp
--- maim-5.4.64/src/main.cpp    2017-07-20 10:05:29.000000000 -0400
+++ maim-5.4.68/src/main.cpp    2017-08-15 21:35:19.000000000 -0400
@@ -216,7 +216,7 @@
 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 @@
     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 @@
         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 @@
         // 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 @@
     }
     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 -Nru maim-5.4.64/src/x.cpp maim-5.4.68/src/x.cpp
--- maim-5.4.64/src/x.cpp       2017-07-20 10:05:29.000000000 -0400
+++ maim-5.4.68/src/x.cpp       2017-08-15 21:35:19.000000000 -0400
@@ -6,31 +6,79 @@
     _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 @@
 }
 
 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 = XRRQueryVersion( display, &major, &minor );
+    haveXRR = (True == XRRQueryVersion( display, &major, &minor ) );
+    major = 0;
+    minor = 2;
+    haveXComposite = (True == XCompositeQueryVersion( display, &major, &minor 
));
+    major = 0;
+    minor = 0;
+    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 @@
 
     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 );
-}
-
-// Basically a faster image grabber.
-XImage* X11::getImageShm(Window draw, int x, int y, 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;
-  }
+    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 
);
+}
 
-  /* 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);
-    }
-    /* 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;
+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 );
+    }
+
+    Pixmap pixmap = XCreatePixmap(display, root, w, h, 32);
+    XRenderPictureAttributes pa2;
+
+    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] );
+        }
+    }
+    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 -Nru maim-5.4.64/src/x.hpp maim-5.4.68/src/x.hpp
--- maim-5.4.64/src/x.hpp       2017-07-20 10:05:29.000000000 -0400
+++ maim-5.4.68/src/x.hpp       2017-08-15 21:35:19.000000000 -0400
@@ -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 @@
 };
 
 glm::ivec4 getWindowGeometry( X11* x11, Window win );
-//glm::ivec4 getWindowGeometryWithoutBorder( X11* x11, Window win );
 
 #endif

Attachment: signature.asc
Description: PGP signature

Reply via email to