[Xfce4-commits] <xfce4-screenshooter:master> Respect the transparence of shaped decoration.
Jérôme Guelfucci
noreply at xfce.org
Wed Oct 28 22:38:03 CET 2009
Updating branch refs/heads/master
to 3c690f700fc40d2376612c0b5caf59a6e29be42d (commit)
from a07c81a590ea4927a4d494b33abddf0d6f3fef8e (commit)
commit 3c690f700fc40d2376612c0b5caf59a6e29be42d
Author: Jérôme Guelfucci <jeromeg at xfce.org>
Date: Wed Oct 28 22:34:31 2009 +0100
Respect the transparence of shaped decoration.
Do not use the frame extensions to get the screenshot of a window,
but use its shape instead. This allows us to have a transparent
background under rounded corners instead of the window that is
under the screenshoted window.
TODO | 1 -
lib/screenshooter-capture.c | 165 ++++++++++++++++++++++++++++++++++++++-----
lib/screenshooter-capture.h | 1 +
3 files changed, 147 insertions(+), 20 deletions(-)
diff --git a/TODO b/TODO
index 23d1f5e..0179b60 100644
--- a/TODO
+++ b/TODO
@@ -1,6 +1,5 @@
Before next release:
-* Use Xshape to have a transparent background in the generated screenshots.
* Improve the cairo rubber banding: allow the user to compute the size of
the rectangle (as with a Gimp selection for example). The Enter key
would be used to validate the selection.
diff --git a/lib/screenshooter-capture.c b/lib/screenshooter-capture.c
index 9af6409..3447465 100644
--- a/lib/screenshooter-capture.c
+++ b/lib/screenshooter-capture.c
@@ -41,9 +41,11 @@ typedef struct
static GdkWindow *get_active_window (GdkScreen *screen,
- gboolean *needs_unref);
+ gboolean *needs_unref,
+ gboolean *border);
static GdkPixbuf *get_window_screenshot (GdkWindow *window,
- gboolean show_mouse);
+ gboolean show_mouse,
+ gboolean border);
static GdkPixbuf *get_rectangle_screenshot (void);
static gboolean cb_key_pressed (GtkWidget *widget,
GdkEventKey *event,
@@ -69,7 +71,9 @@ static GdkPixbuf *get_rectangle_screenshot_composited (void);
static GdkWindow
-*get_active_window (GdkScreen *screen, gboolean *needs_unref)
+*get_active_window (GdkScreen *screen,
+ gboolean *needs_unref,
+ gboolean *border)
{
GdkWindow *window, *window2;
@@ -84,6 +88,7 @@ static GdkWindow
window = gdk_get_default_root_window ();
*needs_unref = FALSE;
+ *border = FALSE;
}
else if (gdk_window_get_type_hint (window) == GDK_WINDOW_TYPE_HINT_DESKTOP)
{
@@ -94,6 +99,7 @@ static GdkWindow
window = gdk_get_default_root_window ();
*needs_unref = FALSE;
+ *border = FALSE;
}
else
{
@@ -105,6 +111,7 @@ static GdkWindow
g_object_unref (window);
window = window2;
+ *border = TRUE;
}
return window;
@@ -112,8 +119,35 @@ static GdkWindow
+static Window
+find_wm_window (Window xid)
+{
+ Window root, parent, *children;
+ unsigned int nchildren;
+
+ do
+ {
+ if (XQueryTree (GDK_DISPLAY (), xid, &root,
+ &parent, &children, &nchildren) == 0)
+ {
+ g_warning ("Couldn't find window manager window");
+ return None;
+ }
+
+ if (root == parent)
+ return xid;
+
+ xid = parent;
+ }
+ while (TRUE);
+}
+
+
+
static GdkPixbuf
-*get_window_screenshot (GdkWindow *window, gboolean show_mouse)
+*get_window_screenshot (GdkWindow *window,
+ gboolean show_mouse,
+ gboolean border)
{
gint x_orig, y_orig;
gint width, height;
@@ -121,25 +155,31 @@ static GdkPixbuf
GdkPixbuf *screenshot;
GdkWindow *root;
- GdkRectangle *rectangle = g_new0 (GdkRectangle, 1);
+ GdkRectangle rectangle;
/* Get the root window */
TRACE ("Get the root window");
root = gdk_get_default_root_window ();
- TRACE ("Get the frame extents");
+ if (border)
+ {
+ Window xwindow = GDK_WINDOW_XWINDOW (window);
+ window = gdk_window_foreign_new (find_wm_window (xwindow));
+ }
+
+ gdk_drawable_get_size (window, &rectangle.width, &rectangle.height);
+ gdk_window_get_origin (window, &rectangle.x, &rectangle.y);
- gdk_window_get_frame_extents (window, rectangle);
/* Don't grab thing offscreen. */
TRACE ("Make sure we don't grab things offscreen");
- x_orig = rectangle->x;
- y_orig = rectangle->y;
- width = rectangle->width;
- height = rectangle->height;
+ x_orig = rectangle.x;
+ y_orig = rectangle.y;
+ width = rectangle.width;
+ height = rectangle.height;
if (x_orig < 0)
{
@@ -159,8 +199,6 @@ static GdkPixbuf
if (y_orig + height > gdk_screen_height ())
height = gdk_screen_height () - y_orig;
- g_free (rectangle);
-
/* Take the screenshot from the root GdkWindow, to grab things such as
* menus. */
@@ -170,15 +208,100 @@ static GdkPixbuf
x_orig, y_orig, 0, 0,
width, height);
- /* Add the mouse pointer to the grabbed screenshot */
+ /* Code adapted from gnome-screenshot:
+ * Copyright (C) 2001-2006 Jonathan Blandford <jrb at alum.mit.edu>
+ * Copyright (C) 2008 Cosimo Cecchi <cosimoc at gnome.org>
+ */
+ if (border)
+ {
+ /* Use XShape to make the background transparent */
+ XRectangle *rectangles;
+ GdkPixbuf *tmp;
+ int rectangle_count, rectangle_order, i;
+
+ rectangles = XShapeGetRectangles (GDK_DISPLAY (),
+ GDK_WINDOW_XWINDOW (window),
+ ShapeBounding,
+ &rectangle_count,
+ &rectangle_order);
+
+ if (rectangles && rectangle_count > 0 && window != root)
+ {
+ gboolean has_alpha = gdk_pixbuf_get_has_alpha (screenshot);
- TRACE ("Get the mouse cursor and its image");
+ tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
+ gdk_pixbuf_fill (tmp, 0);
+
+ for (i = 0; i < rectangle_count; i++)
+ {
+ gint rec_x, rec_y;
+ gint rec_width, rec_height;
+ gint y;
+
+ rec_x = rectangles[i].x;
+ rec_y = rectangles[i].y;
+ rec_width = rectangles[i].width;
+ rec_height = rectangles[i].height;
+
+ if (rectangle.x < 0)
+ {
+ rec_x += rectangle.x;
+ rec_x = MAX(rec_x, 0);
+ rec_width += rectangle.x;
+ }
+
+ if (rectangle.y < 0)
+ {
+ rec_y += rectangle.y;
+ rec_y = MAX(rec_y, 0);
+ rec_height += rectangle.y;
+ }
+
+ if (x_orig + rec_x + rec_width > gdk_screen_width ())
+ rec_width = gdk_screen_width () - x_orig - rec_x;
+
+ if (y_orig + rec_y + rec_height > gdk_screen_height ())
+ rec_height = gdk_screen_height () - y_orig - rec_y;
+
+ for (y = rec_y; y < rec_y + rec_height; y++)
+ {
+ guchar *src_pixels, *dest_pixels;
+ gint x;
+
+ src_pixels = gdk_pixbuf_get_pixels (screenshot)
+ + y * gdk_pixbuf_get_rowstride(screenshot)
+ + rec_x * (has_alpha ? 4 : 3);
+ dest_pixels = gdk_pixbuf_get_pixels (tmp)
+ + y * gdk_pixbuf_get_rowstride (tmp)
+ + rec_x * 4;
+
+ for (x = 0; x < rec_width; x++)
+ {
+ *dest_pixels++ = *src_pixels++;
+ *dest_pixels++ = *src_pixels++;
+ *dest_pixels++ = *src_pixels++;
+
+ if (has_alpha)
+ *dest_pixels++ = *src_pixels++;
+ else
+ *dest_pixels++ = 255;
+ }
+ }
+ }
+
+ g_object_unref (screenshot);
+ screenshot = tmp;
+ }
+ }
if (show_mouse)
{
GdkCursor *cursor;
GdkPixbuf *cursor_pixbuf;
+ /* 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);
@@ -764,12 +887,16 @@ static GdkPixbuf
* Return value: a #GdkPixbuf containing the screenshot or %NULL (if @region is SELECT,
* the user can cancel the operation).
**/
-GdkPixbuf *screenshooter_take_screenshot (gint region, gint delay, gboolean show_mouse, gboolean plugin)
+GdkPixbuf *screenshooter_take_screenshot (gint region,
+ gint delay,
+ gboolean show_mouse,
+ gboolean plugin)
{
GdkPixbuf *screenshot = NULL;
GdkWindow *window = NULL;
GdkScreen *screen;
GdkDisplay *display;
+ gboolean border;
/* gdk_get_default_root_window () does not need to be unrefed,
* needs_unref enables us to unref *window only if a non default
@@ -804,19 +931,20 @@ GdkPixbuf *screenshooter_take_screenshot (gint region, gint delay, gboolean show
window = gdk_get_default_root_window ();
needs_unref = FALSE;
+ border = FALSE;
}
else if (region == ACTIVE_WINDOW)
{
TRACE ("We grab the active window");
- window = get_active_window (screen, &needs_unref);
+ window = get_active_window (screen, &needs_unref, &border);
}
if (region == FULLSCREEN || region == ACTIVE_WINDOW)
{
TRACE ("Get the screenshot of the given window");
- screenshot = get_window_screenshot (window, show_mouse);
+ screenshot = get_window_screenshot (window, show_mouse, border);
if (needs_unref)
g_object_unref (window);
@@ -830,6 +958,5 @@ GdkPixbuf *screenshooter_take_screenshot (gint region, gint delay, gboolean show
screenshot = get_rectangle_screenshot_composited ();
}
-
return screenshot;
}
diff --git a/lib/screenshooter-capture.h b/lib/screenshooter-capture.h
index c229d62..804ad03 100644
--- a/lib/screenshooter-capture.h
+++ b/lib/screenshooter-capture.h
@@ -26,6 +26,7 @@
#include "screenshooter-global.h"
+#include <X11/extensions/shape.h>
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
#include <glib.h>
More information about the Xfce4-commits
mailing list