diff --git a/Makefile.am b/Makefile.am index c50b9e3..703a761 100644 --- a/Makefile.am +++ b/Makefile.am @@ -39,6 +39,7 @@ lib_libscreenshooter_la_CFLAGS = \ @LIBXFCE4UTIL_CFLAGS@ \ @LIBXFCE4UI_CFLAGS@ \ @SOUP_CFLAGS@ \ + @XFIXES_CFLAGS@ \ -DPACKAGE_LOCALE_DIR=\"$(localedir)\" lib_libscreenshooter_la_LIBADD = \ @@ -49,7 +50,8 @@ lib_libscreenshooter_la_LIBADD = \ @GLIB_LIBS@ \ @SOUP_LIBS@ \ @LIBXEXT_LIBS@ \ - @LIBX11_LIBS@ + @LIBX11_LIBS@ \ + @XFIXES_LIBS@ lib_libscreenshooter_built_sources = \ lib/screenshooter-marshal.c lib/screenshooter-marshal.h diff --git a/configure.ac.in b/configure.ac.in index 3367312..3f44a44 100644 --- a/configure.ac.in +++ b/configure.ac.in @@ -55,6 +55,7 @@ XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.16.0]) XDT_CHECK_PACKAGE([SOUP], [libsoup-2.4], [2.26.0]) XDT_CHECK_PACKAGE([EXO], [exo-1], [0.5.0]) XDT_CHECK_PACKAGE([LIBXEXT], [xext], [1.0.0]) +XDT_CHECK_OPTIONAL_PACKAGE([XFIXES], [xfixes], [4.0.0], [xfixes], [XFIXES extension support]) XDT_CHECK_LIBX11() dnl ************************** @@ -116,6 +117,7 @@ echo "" echo "Build Configuration:" echo "" +echo " * XFIXES support: $XFIXES_FOUND" echo " * Debugging support: $enable_debug" echo "" diff --git a/lib/screenshooter-capture.c b/lib/screenshooter-capture.c index 32b32e6..881a942 100644 --- a/lib/screenshooter-capture.c +++ b/lib/screenshooter-capture.c @@ -53,6 +53,14 @@ typedef struct static GdkWindow *get_active_window (GdkScreen *screen, gboolean *needs_unref, gboolean *border); +static void free_pixmap_data (guchar *pixels, + gpointer data); +static GdkPixbuf *get_cursor_pixbuf (GdkDisplay *display, + GdkWindow *root, + gint *cursorx, + gint *cursory, + gint *xhot, + gint *yhot); static GdkPixbuf *get_window_screenshot (GdkWindow *window, gboolean show_mouse, gboolean border); @@ -165,6 +173,98 @@ find_wm_window (Window xid) } +static void free_pixmap_data (guchar *pixels, gpointer data) +{ + g_free (pixels); +} + + +static GdkPixbuf *get_cursor_pixbuf (GdkDisplay *display, + GdkWindow *root, + gint *cursorx, + gint *cursory, + gint *xhot, + gint *yhot) +{ + GdkCursor *cursor = NULL; + GdkPixbuf *cursor_pixbuf = NULL; + +#ifdef HAVE_XFIXES + int event_basep; + int error_basep; + XFixesCursorImage *cursor_image = NULL; + guchar *cursor_pixmap_data = NULL; + gint i, j; + guint32 tmp; + + if (!XFixesQueryExtension (GDK_DISPLAY_XDISPLAY (display), + &event_basep, + &error_basep)) + goto fallback; + + TRACE ("Get the mouse cursor, its image, position and hotspot"); + + cursor_image = XFixesGetCursorImage (GDK_DISPLAY_XDISPLAY (display)); + if (cursor_image == NULL) + goto fallback; + + *cursorx = cursor_image->x; + *cursory = cursor_image->y; + *xhot = cursor_image->xhot; + *yhot = cursor_image->yhot; + + /* cursor_image->pixels contains premultiplied 32-bit ARGB data stored in + * long (!) + */ + cursor_pixmap_data = g_new (guchar, + cursor_image->width * cursor_image->height * 4); + for (i = 0, j = 0; i < cursor_image->width * cursor_image->height; + i++, j += 4) + { + tmp = ((guint32)cursor_image->pixels[i] << 8) | \ + ((guint32)cursor_image->pixels[i] >> 24); + cursor_pixmap_data[j] = tmp >> 24; + cursor_pixmap_data[j + 1] = (tmp >> 16) & 0xff; + cursor_pixmap_data[j + 2] = (tmp >> 8) & 0xff; + cursor_pixmap_data[j + 3] = tmp & 0xff; + } + cursor_pixbuf = gdk_pixbuf_new_from_data (cursor_pixmap_data, + GDK_COLORSPACE_RGB, + TRUE, + 8, + cursor_image->width, + cursor_image->height, + cursor_image->width * 4, + free_pixmap_data, + NULL); + + XFree(cursor_image); + if (cursor_pixbuf != NULL) + return cursor_pixbuf; + +fallback: +#endif + TRACE ("Get the mouse cursor and its image through fallback mode"); + + cursor = gdk_cursor_new_for_display (display, GDK_LEFT_PTR); + cursor_pixbuf = gdk_cursor_get_image (cursor); + if (cursor_pixbuf == NULL) + return NULL; + + TRACE ("Get the coordinates of the cursor"); + + gdk_window_get_pointer (root, cursorx, cursory, NULL); + + TRACE ("Get the cursor hotspot"); + + sscanf (gdk_pixbuf_get_option (cursor_pixbuf, "x_hot"), "%d", xhot); + sscanf (gdk_pixbuf_get_option (cursor_pixbuf, "y_hot"), "%d", yhot); + + gdk_cursor_unref (cursor); + + return cursor_pixbuf; +} + static GdkPixbuf *get_window_screenshot (GdkWindow *window, @@ -317,28 +417,16 @@ static GdkPixbuf if (show_mouse) { - GdkCursor *cursor; + gint cursorx, cursory, xhot, yhot; GdkPixbuf *cursor_pixbuf; + GdkDisplay *display = gdk_display_get_default (); - /* Add the mouse pointer to the grabbed screenshot */ - TRACE ("Get the mouse cursor and its image"); - - cursor = gdk_cursor_new_for_display (gdk_display_get_default (), GDK_LEFT_PTR); - cursor_pixbuf = gdk_cursor_get_image (cursor); + cursor_pixbuf = get_cursor_pixbuf (display, root, &cursorx, &cursory, + &xhot, &yhot); if (G_LIKELY (cursor_pixbuf != NULL)) { GdkRectangle rectangle_window, rectangle_cursor; - gint cursorx, cursory, xhot, yhot; - - TRACE ("Get the coordinates of the cursor"); - - gdk_window_get_pointer (root, &cursorx, &cursory, NULL); - - TRACE ("Get the cursor hotspot"); - - sscanf (gdk_pixbuf_get_option (cursor_pixbuf, "x_hot"), "%d", &xhot); - sscanf (gdk_pixbuf_get_option (cursor_pixbuf, "y_hot"), "%d", &yhot); /* rectangle_window stores the window coordinates */ rectangle_window.x = x_orig; @@ -370,15 +458,12 @@ static GdkPixbuf g_object_unref (cursor_pixbuf); } - - gdk_cursor_unref (cursor); } return screenshot; } - /* Callbacks for the rubber banding function */ static gboolean cb_key_pressed (GtkWidget *widget, GdkEventKey *event, diff --git a/lib/screenshooter-capture.h b/lib/screenshooter-capture.h index 804ad03..7f871f3 100644 --- a/lib/screenshooter-capture.h +++ b/lib/screenshooter-capture.h @@ -26,6 +26,9 @@ #include "screenshooter-global.h" +#ifdef HAVE_XFIXES +#include +#endif #include #include #include