diff options
Diffstat (limited to 'mate-screenshot')
-rw-r--r-- | mate-screenshot/mate-screenshot.c | 58 | ||||
-rw-r--r-- | mate-screenshot/screenshot-utils.c | 317 | ||||
-rw-r--r-- | mate-screenshot/screenshot-utils.h | 7 |
3 files changed, 212 insertions, 170 deletions
diff --git a/mate-screenshot/mate-screenshot.c b/mate-screenshot/mate-screenshot.c index dcd325e4..45682b88 100644 --- a/mate-screenshot/mate-screenshot.c +++ b/mate-screenshot/mate-screenshot.c @@ -860,7 +860,10 @@ async_existence_job_free (AsyncExistenceJob *job) g_free (job->base_uris[1]); g_free (job->base_uris[2]); - g_free (job->rectangle); + + if (job->rectangle != NULL) + g_slice_free (GdkRectangle, job->rectangle); + g_slice_free (AsyncExistenceJob, job); } @@ -1050,35 +1053,11 @@ find_current_window (char **window_title) return window; } -static GdkRectangle * -find_rectangle (void) -{ - GdkRectangle *rectangle; - - if (!take_area_shot) - return NULL; - - rectangle = g_new0 (GdkRectangle, 1); - if (screenshot_select_area (&rectangle->x, &rectangle->y, - &rectangle->width, &rectangle->height)) - { - g_assert (rectangle->width >= 0); - g_assert (rectangle->height >= 0); - - return rectangle; - } - else - { - g_free (rectangle); - return NULL; - } -} - static void -prepare_screenshot (void) +push_check_file_job (GdkRectangle *rectangle) { AsyncExistenceJob *job; - + job = g_slice_new0 (AsyncExistenceJob); job->base_uris[0] = last_save_dir; /* we'll have to free these two */ @@ -1087,7 +1066,15 @@ prepare_screenshot (void) job->iteration = 0; job->type = TEST_LAST_DIR; job->window = find_current_window (&window_title); - job->rectangle = find_rectangle (); + + if (rectangle != NULL) + { + job->rectangle = g_slice_new0 (GdkRectangle); + job->rectangle->x = rectangle->x; + job->rectangle->y = rectangle->y; + job->rectangle->width = rectangle->width; + job->rectangle->height = rectangle->height; + } /* Check if the area selection was cancelled */ if (job->rectangle && @@ -1105,6 +1092,21 @@ prepare_screenshot (void) } +static void +rectangle_found_cb (GdkRectangle *rectangle) +{ + push_check_file_job (rectangle); +} + +static void +prepare_screenshot (void) +{ + if (take_area_shot) + screenshot_select_area_async (rectangle_found_cb); + else + push_check_file_job (NULL); +} + static gboolean prepare_screenshot_timeout (gpointer data) { 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 (®ion_rect); +#else region = gdk_region_rectangle (®ion_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 (®ion_rect); + cairo_region_subtract (region, region2); +#else region2 = gdk_region_rectangle (®ion_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); diff --git a/mate-screenshot/screenshot-utils.h b/mate-screenshot/screenshot-utils.h index 5404bde4..b9d13f7b 100644 --- a/mate-screenshot/screenshot-utils.h +++ b/mate-screenshot/screenshot-utils.h @@ -25,14 +25,13 @@ G_BEGIN_DECLS +typedef void (* SelectAreaCallback) (GdkRectangle *rectangle); + gboolean screenshot_grab_lock (void); void screenshot_release_lock (void); gchar *screenshot_get_window_title (GdkWindow *win); GdkWindow *screenshot_find_current_window (void); -gboolean screenshot_select_area (int *px, - int *py, - int *pwidth, - int *pheight); +void screenshot_select_area_async (SelectAreaCallback callback); GdkPixbuf *screenshot_get_pixbuf (GdkWindow *win, GdkRectangle *rectangle, gboolean include_pointer, |