summaryrefslogtreecommitdiff
path: root/mate-screenshot/screenshot-utils.c
diff options
context:
space:
mode:
authorinfirit <[email protected]>2014-11-10 17:46:47 +0100
committerinfirit <[email protected]>2014-11-10 17:46:47 +0100
commit435be8bdc4f0e9881b439825b16b29fecd02338e (patch)
treef310b6d7728ee49de111e067a74d000ed7f2b0a0 /mate-screenshot/screenshot-utils.c
parentc75635285af8b70a781c2314aa7b03b2af716835 (diff)
downloadmate-utils-435be8bdc4f0e9881b439825b16b29fecd02338e.tar.bz2
mate-utils-435be8bdc4f0e9881b439825b16b29fecd02338e.tar.xz
mate-screenshot: Several fixes taken from gnome-screenshot
Code taken from commits: screenshot: Rewrite event handling in area selection 772b9cc0774468ea21addb85ef843ee8dfef9e00 screenshot: add a workaround to avoid capturing the selection window 745eea03a3092fa055f76132971e3dd2bb4e8737 screenshot: Don't snap the selection 13741db3522aaac8be732567bca00d9c81929b72
Diffstat (limited to 'mate-screenshot/screenshot-utils.c')
-rw-r--r--mate-screenshot/screenshot-utils.c317
1 files changed, 179 insertions, 138 deletions
diff --git a/mate-screenshot/screenshot-utils.c b/mate-screenshot/screenshot-utils.c
index fce538bd..f226b0b5 100644
--- a/mate-screenshot/screenshot-utils.c
+++ b/mate-screenshot/screenshot-utils.c
@@ -21,7 +21,7 @@
#include "config.h"
#include "screenshot-utils.h"
-#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <glib.h>
#include <glib/gi18n.h>
@@ -263,33 +263,51 @@ screenshot_find_current_window ()
return current_window;
}
-static void
-select_area_button_press (XKeyEvent *event,
- GdkRectangle *rect,
- GdkRectangle *draw_rect)
+typedef struct {
+ GdkRectangle rect;
+ gboolean button_pressed;
+ GtkWidget *window;
+} select_area_filter_data;
+
+static gboolean
+select_area_button_press (GtkWidget *window,
+ GdkEventButton *event,
+ select_area_filter_data *data)
{
- rect->x = event->x_root;
- rect->y = event->y_root;
+ if (data->button_pressed)
+ return TRUE;
- draw_rect->x = rect->x;
- draw_rect->y = rect->y;
- draw_rect->width = 0;
- draw_rect->height = 0;
+ data->button_pressed = TRUE;
+ data->rect.x = event->x_root;
+ data->rect.y = event->y_root;
+
+ return TRUE;
}
-static void
-select_area_update_rect (GtkWidget *window,
- GdkRectangle *rect)
+static gboolean
+select_area_motion_notify (GtkWidget *window,
+ GdkEventMotion *event,
+ select_area_filter_data *data)
{
- if (rect->width <= 0 || rect->height <= 0)
+ GdkRectangle draw_rect;
+
+ if (!data->button_pressed)
+ return TRUE;
+
+ draw_rect.width = ABS (data->rect.x - event->x_root);
+ draw_rect.height = ABS (data->rect.y - event->y_root);
+ draw_rect.x = MIN (data->rect.x, event->x_root);
+ draw_rect.y = MIN (data->rect.y, event->y_root);
+
+ if (draw_rect.width <= 0 || draw_rect.height <= 0)
{
- gtk_widget_hide (window);
- return;
+ gtk_window_move (GTK_WINDOW (window), -100, -100);
+ gtk_window_resize (GTK_WINDOW (window), 10, 10);
+ return TRUE;
}
- gtk_window_move (GTK_WINDOW (window), rect->x, rect->y);
- gtk_window_resize (GTK_WINDOW (window), rect->width, rect->height);
- gtk_widget_show (window);
+ gtk_window_move (GTK_WINDOW (window), draw_rect.x, draw_rect.y);
+ gtk_window_resize (GTK_WINDOW (window), draw_rect.width, draw_rect.height);
/* We (ab)use app-paintable to indicate if we have an RGBA window */
if (!gtk_widget_get_app_paintable (window))
@@ -297,19 +315,35 @@ select_area_update_rect (GtkWidget *window,
GdkWindow *gdkwindow = gtk_widget_get_window (window);
/* Shape the window to make only the outline visible */
- if (rect->width > 2 && rect->height > 2)
+ if (draw_rect.width > 2 && draw_rect.height > 2)
{
+#if GTK_CHECK_VERSION (3, 0, 0)
+ cairo_region_t *region, *region2;
+ cairo_rectangle_int_t region_rect = {
+#else
GdkRegion *region, *region2;
- GdkRectangle region_rect = { 0, 0,
- rect->width - 2, rect->height - 2 };
+ GdkRectangle region_rect = {
+#endif
+ 0, 0,
+ draw_rect.width - 2, draw_rect.height - 2
+ };
+#if GTK_CHECK_VERSION (3, 0, 0)
+ region = cairo_region_create_rectangle (&region_rect);
+#else
region = gdk_region_rectangle (&region_rect);
+#endif
region_rect.x++;
region_rect.y++;
region_rect.width -= 2;
region_rect.height -= 2;
+#if GTK_CHECK_VERSION (3, 0, 0)
+ region2 = cairo_region_create_rectangle (&region_rect);
+ cairo_region_subtract (region, region2);
+#else
region2 = gdk_region_rectangle (&region_rect);
gdk_region_subtract (region, region2);
+#endif
gdk_window_shape_combine_region (gdkwindow, region, 0, 0);
@@ -319,44 +353,45 @@ select_area_update_rect (GtkWidget *window,
else
gdk_window_shape_combine_region (gdkwindow, NULL, 0, 0);
}
+
+ return TRUE;
}
-static void
-select_area_button_release (XKeyEvent *event,
- GdkRectangle *rect,
- GdkRectangle *draw_rect,
- GtkWidget *window)
+static gboolean
+select_area_button_release (GtkWidget *window,
+ GdkEventButton *event,
+ select_area_filter_data *data)
{
- gtk_widget_hide (window);
+ if (!data->button_pressed)
+ return TRUE;
- rect->width = ABS (rect->x - event->x_root);
- rect->height = ABS (rect->y - event->y_root);
+ data->rect.width = ABS (data->rect.x - event->x_root);
+ data->rect.height = ABS (data->rect.y - event->y_root);
+ data->rect.x = MIN (data->rect.x, event->x_root);
+ data->rect.y = MIN (data->rect.y, event->y_root);
- rect->x = MIN (rect->x, event->x_root);
- rect->y = MIN (rect->y, event->y_root);
+ gtk_main_quit ();
+
+ return TRUE;
}
-static void
-select_area_motion_notify (XKeyEvent *event,
- GdkRectangle *rect,
- GdkRectangle *draw_rect,
- GtkWidget *window)
+static gboolean
+select_area_key_press (GtkWidget *window,
+ GdkEventKey *event,
+ select_area_filter_data *data)
{
- draw_rect->width = ABS (rect->x - event->x_root);
- draw_rect->height = ABS (rect->y - event->y_root);
-
- draw_rect->x = MIN (rect->x, event->x_root);
- draw_rect->y = MIN (rect->y, event->y_root);
+ if (event->keyval == GDK_KEY_Escape)
+ {
+ data->rect.x = 0;
+ data->rect.y = 0;
+ data->rect.width = 0;
+ data->rect.height = 0;
+ gtk_main_quit ();
+ }
- select_area_update_rect (window, draw_rect);
+ return TRUE;
}
-typedef struct {
- GdkRectangle rect;
- GdkRectangle draw_rect;
- gboolean button_pressed;
- GtkWidget *window;
-} select_area_filter_data;
static gboolean
#if GTK_CHECK_VERSION (3, 0, 0)
@@ -444,116 +479,88 @@ create_select_window (void)
g_signal_connect (window, "expose-event", G_CALLBACK (expose), NULL);
#endif
+ gtk_window_move (GTK_WINDOW (window), -100, -100);
+ gtk_window_resize (GTK_WINDOW (window), 10, 10);
+ gtk_widget_show (window);
return window;
}
-static GdkFilterReturn
-select_area_filter (GdkXEvent *gdk_xevent,
- GdkEvent *event,
- gpointer user_data)
+typedef struct {
+ GdkRectangle rectangle;
+ SelectAreaCallback callback;
+} CallbackData;
+
+static gboolean
+emit_select_callback_in_idle (gpointer user_data)
{
- select_area_filter_data *data = user_data;
- XEvent *xevent = (XEvent *) gdk_xevent;
+ CallbackData *data = user_data;
- switch (xevent->type)
- {
- case ButtonPress:
- if (!data->button_pressed)
- {
- select_area_button_press (&xevent->xkey,
- &data->rect, &data->draw_rect);
- data->button_pressed = TRUE;
- }
- return GDK_FILTER_REMOVE;
- case ButtonRelease:
- if (data->button_pressed)
- {
- select_area_button_release (&xevent->xkey,
- &data->rect, &data->draw_rect,
- data->window);
- gtk_main_quit ();
- }
- return GDK_FILTER_REMOVE;
- case MotionNotify:
- if (data->button_pressed)
- select_area_motion_notify (&xevent->xkey,
- &data->rect, &data->draw_rect,
- data->window);
- return GDK_FILTER_REMOVE;
- case KeyPress:
- if (xevent->xkey.keycode == XKeysymToKeycode (gdk_x11_display_get_xdisplay(gdk_display_get_default()), XK_Escape))
- {
- data->rect.x = 0;
- data->rect.y = 0;
- data->rect.width = 0;
- data->rect.height = 0;
- gtk_main_quit ();
- return GDK_FILTER_REMOVE;
- }
- break;
- default:
- break;
- }
+ data->callback (&data->rectangle);
+
+ g_slice_free (CallbackData, data);
- return GDK_FILTER_CONTINUE;
+ return FALSE;
}
-gboolean
-screenshot_select_area (int *px,
- int *py,
- int *pwidth,
- int *pheight)
+void
+screenshot_select_area_async (SelectAreaCallback callback)
{
- GdkWindow *root;
GdkCursor *cursor;
select_area_filter_data data;
+ GdkRectangle *rectangle;
+ CallbackData *cb_data;
+
+ data.rect.x = 0;
+ data.rect.y = 0;
+ data.rect.width = 0;
+ data.rect.height = 0;
+ data.button_pressed = FALSE;
+ data.window = create_select_window();
+
+ cb_data = g_slice_new0 (CallbackData);
+ cb_data->callback = callback;
+
+ g_signal_connect (data.window, "key-press-event", G_CALLBACK (select_area_key_press), &data);
+ g_signal_connect (data.window, "button-press-event", G_CALLBACK (select_area_button_press), &data);
+ g_signal_connect (data.window, "button-release-event", G_CALLBACK (select_area_button_release), &data);
+ g_signal_connect (data.window, "motion-notify-event", G_CALLBACK (select_area_motion_notify), &data);
- root = gdk_get_default_root_window ();
cursor = gdk_cursor_new (GDK_CROSSHAIR);
- if (gdk_pointer_grab (root, FALSE,
+ if (gdk_pointer_grab (gtk_widget_get_window (data.window), FALSE,
GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK,
NULL, cursor,
GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
{
gdk_cursor_unref (cursor);
- return FALSE;
+ goto out;
}
- if (gdk_keyboard_grab (root, FALSE, GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
+ if (gdk_keyboard_grab (gtk_widget_get_window (data.window), FALSE, GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
{
gdk_pointer_ungrab (GDK_CURRENT_TIME);
gdk_cursor_unref (cursor);
- return FALSE;
+ goto out;
}
- gdk_window_add_filter (root, (GdkFilterFunc) select_area_filter, &data);
-
- gdk_flush ();
-
- data.rect.x = 0;
- data.rect.y = 0;
- data.rect.width = 0;
- data.rect.height = 0;
- data.button_pressed = FALSE;
- data.window = create_select_window();
-
gtk_main ();
- gdk_window_remove_filter (root, (GdkFilterFunc) select_area_filter, &data);
-
- gtk_widget_destroy (data.window);
-
gdk_keyboard_ungrab (GDK_CURRENT_TIME);
gdk_pointer_ungrab (GDK_CURRENT_TIME);
+
+ gtk_widget_destroy (data.window);
gdk_cursor_unref (cursor);
- *px = data.rect.x;
- *py = data.rect.y;
- *pwidth = data.rect.width;
- *pheight = data.rect.height;
+ gdk_flush ();
- return TRUE;
+ out:
+ cb_data->rectangle = data.rect;
+
+ /* FIXME: we should actually be emitting the callback When
+ * the compositor has finished re-drawing, but there seems to be no easy
+ * way to know that.
+ */
+ g_timeout_add (200, emit_select_callback_in_idle, cb_data);
}
static Window
@@ -579,23 +586,39 @@ find_wm_window (Window xid)
while (TRUE);
}
+#if GTK_CHECK_VERSION (3, 0, 0)
+static cairo_region_t *
+#else
static GdkRegion *
+#endif
make_region_with_monitors (GdkScreen *screen)
{
+#if GTK_CHECK_VERSION (3, 0, 0)
+ cairo_region_t *region;
+#else
GdkRegion *region;
+#endif
int num_monitors;
int i;
num_monitors = gdk_screen_get_n_monitors (screen);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ region = cairo_region_create ();
+#else
region = gdk_region_new ();
+#endif
for (i = 0; i < num_monitors; i++)
{
GdkRectangle rect;
gdk_screen_get_monitor_geometry (screen, i, &rect);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ cairo_region_union_rectangle (region, &rect);
+#else
gdk_region_union_with_rect (region, &rect);
+#endif
}
return region;
@@ -642,19 +665,24 @@ blank_rectangle_in_pixbuf (GdkPixbuf *pixbuf, GdkRectangle *rect)
}
static void
+#if GTK_CHECK_VERSION (3, 0, 0)
+blank_region_in_pixbuf (GdkPixbuf *pixbuf, cairo_region_t *region)
+{
+ int n_rects;
+ int i;
+ int width, height;
+ cairo_rectangle_int_t pixbuf_rect;
+
+ n_rects = cairo_region_num_rectangles (region);
+#else
blank_region_in_pixbuf (GdkPixbuf *pixbuf, GdkRegion *region)
{
-#if !GTK_CHECK_VERSION (3, 0, 0)
GdkRectangle *rects;
-#endif
int n_rects;
int i;
int width, height;
GdkRectangle pixbuf_rect;
-#if GTK_CHECK_VERSION (3, 0, 0)
- n_rects = cairo_region_num_rectangles (region);
-#else
gdk_region_get_rectangles (region, &rects, &n_rects);
#endif
@@ -668,16 +696,18 @@ blank_region_in_pixbuf (GdkPixbuf *pixbuf, GdkRegion *region)
for (i = 0; i < n_rects; i++)
{
- GdkRectangle dest;
#if GTK_CHECK_VERSION (3, 0, 0)
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
if (gdk_rectangle_intersect (&rect, &pixbuf_rect, &dest))
#else
+ GdkRectangle dest;
+
if (gdk_rectangle_intersect (rects + i, &pixbuf_rect, &dest))
#endif
blank_rectangle_in_pixbuf (pixbuf, &dest);
+
}
#if !GTK_CHECK_VERSION (3, 0, 0)
g_free (rects);
@@ -694,9 +724,15 @@ static void
mask_monitors (GdkPixbuf *pixbuf, GdkWindow *root_window)
{
GdkScreen *screen;
+#if GTK_CHECK_VERSION (3, 0, 0)
+ cairo_region_t *region_with_monitors;
+ cairo_region_t *invisible_region;
+ cairo_rectangle_int_t rect;
+#else
GdkRegion *region_with_monitors;
GdkRegion *invisible_region;
GdkRectangle rect;
+#endif
screen = gdk_window_get_screen (root_window);
@@ -707,6 +743,15 @@ mask_monitors (GdkPixbuf *pixbuf, GdkWindow *root_window)
rect.width = gdk_screen_get_width (screen);
rect.height = gdk_screen_get_height (screen);
+#if GTK_CHECK_VERSION (3, 0, 0)
+ invisible_region = cairo_region_create_rectangle (&rect);
+ cairo_region_subtract (invisible_region, region_with_monitors);
+
+ blank_region_in_pixbuf (pixbuf, invisible_region);
+
+ cairo_region_destroy (region_with_monitors);
+ cairo_region_destroy (invisible_region);
+#else
invisible_region = gdk_region_rectangle (&rect);
gdk_region_subtract (invisible_region, region_with_monitors);
@@ -714,6 +759,7 @@ mask_monitors (GdkPixbuf *pixbuf, GdkWindow *root_window)
gdk_region_destroy (region_with_monitors);
gdk_region_destroy (invisible_region);
+#endif
}
GdkPixbuf *
@@ -808,13 +854,8 @@ screenshot_get_pixbuf (GdkWindow *window,
* of the WM decoration.
*/
-#if GTK_CHECK_VERSION (3, 0, 0)
rectangles = XShapeGetRectangles (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
GDK_WINDOW_XID (window),
-#else
- rectangles = XShapeGetRectangles (GDK_DISPLAY (),
- GDK_WINDOW_XWINDOW (window),
-#endif
ShapeBounding,
&rectangle_count,
&rectangle_order);