1 #ifdef _HAVE_X11_
2 /* screenshot.c - Take a screenshot from user selected rectangle
3  * Copyright (C) 2011 Richard Shann
4  *
5  * Copyright (C) 2001 Jonathan Blandford <jrb@alum.mit.edu>
6  * Copyright (C) 2006 Emmanuele Bassi <ebassi@gnome.org>
7  * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
8  * Copyright (C) 2011 Philippe Corbes <philippe.corbes@gmail.com>
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2 of the
13  * License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23  * USA
24  */
25 #include <gtk/gtk.h>
26 #include <glib.h>
27 #include <gdk/gdk.h>
28 #if GTK_MAJOR_VERSION==3
29 #if 1                           //remove this and the corresponding endif to compile and test on gkt3
30 
31 #ifdef G_OS_WIN32
32 #include "windows.h"
33 #else
34 #include <gdk/gdkx.h>
35 #endif
36 
37 typedef void (*SelectAreaCallback) (GdkRectangle * rectangle);
38 
39 typedef struct
40 {
41   GdkRectangle rect;
42   GdkRectangle draw_rect;
43   gboolean button_pressed;
44 
45   GtkWidget *window;
46   gboolean aborted;
47 } select_area_filter_data;
48 
49 static select_area_filter_data the_data;
50 static gboolean
select_window_draw(GtkWidget * window,cairo_t * cr,G_GNUC_UNUSED gpointer unused)51 select_window_draw (GtkWidget * window, cairo_t * cr, G_GNUC_UNUSED gpointer unused)
52 {
53   GtkAllocation allocation;
54   GtkStyle *style;
55 
56   style = gtk_widget_get_style (window);
57 
58   if (gtk_widget_get_app_paintable (window))
59     {
60       cairo_set_line_width (cr, 1.0);
61 
62       gtk_widget_get_allocation (window, &allocation);
63 
64       cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
65       cairo_set_source_rgba (cr, 0, 0, 0, 0);
66       cairo_paint (cr);
67 
68       cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
69       gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_SELECTED]);
70       cairo_paint_with_alpha (cr, 0.25);
71 
72       cairo_rectangle (cr, allocation.x + 0.5, allocation.y + 0.5, allocation.width - 1, allocation.height - 1);
73       cairo_stroke (cr);
74     }
75   else
76     {
77       gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_SELECTED]);
78       cairo_paint (cr);
79     }
80 
81   return TRUE;
82 }
83 
84 static GtkWidget *
create_select_window(void)85 create_select_window (void)
86 {
87   GtkWidget *window;
88   GdkScreen *screen;
89   GdkVisual *visual;
90 
91   screen = gdk_screen_get_default ();
92   visual = gdk_screen_get_rgba_visual (screen);
93 
94   window = gtk_window_new (GTK_WINDOW_POPUP);
95   if (gdk_screen_is_composited (screen) && visual)
96     {
97       gtk_widget_set_visual (window, visual);
98       gtk_widget_set_app_paintable (window, TRUE);
99     }
100 
101   g_signal_connect (window, "draw", G_CALLBACK (select_window_draw), NULL);
102 
103   gtk_window_move (GTK_WINDOW (window), -100, -100);
104   gtk_window_resize (GTK_WINDOW (window), 10, 10);
105   gtk_widget_show (window);
106 
107   return window;
108 }
109 
110 
111 static void
rectangle_found_cb(GdkRectangle * rectangle)112 rectangle_found_cb (GdkRectangle * rectangle)
113 {
114   if (rectangle != NULL)
115     {
116 
117       the_data.rect = *rectangle;       //structure copy
118     }
119   else
120     the_data.rect.width = -1;
121   gtk_main_quit ();
122 }
123 
124 typedef struct
125 {
126   GdkRectangle rectangle;
127   SelectAreaCallback callback;
128   gboolean aborted;
129 } CallbackData;
130 
131 static gboolean
emit_select_callback_in_idle(gpointer user_data)132 emit_select_callback_in_idle (gpointer user_data)
133 {
134   CallbackData *data = user_data;
135 
136   if (!data->aborted)
137     data->callback (&data->rectangle);
138   else
139     data->callback (NULL);
140 
141   g_slice_free (CallbackData, data);
142 
143   return FALSE;
144 }
145 
146 
147 static void
empty_rectangle(gint x_root,gint y_root,GdkRectangle * rect,GdkRectangle * draw_rect)148 empty_rectangle (gint x_root, gint y_root, GdkRectangle * rect, GdkRectangle * draw_rect)
149 {
150   rect->x = x_root;
151   rect->y = y_root;
152 
153   draw_rect->x = rect->x;
154   draw_rect->y = rect->y;
155   draw_rect->width = 0;
156   draw_rect->height = 0;
157 }
158 
159 static void
fix_rectangle(gint x_root,gint y_root,GdkRectangle * rect)160 fix_rectangle (gint x_root, gint y_root, GdkRectangle * rect)
161 {
162   rect->width = ABS (rect->x - x_root);
163   rect->height = ABS (rect->y - y_root);
164 
165   rect->x = MIN (rect->x, x_root);
166   rect->y = MIN (rect->y, y_root);
167 }
168 
169 static void
select_area_motion_action(GtkWidget * window,GdkRectangle * rect,GdkRectangle * pdraw_rect,gint x_root,gint y_root)170 select_area_motion_action (GtkWidget * window, GdkRectangle * rect, GdkRectangle * pdraw_rect, gint x_root, gint y_root)
171 {
172   GdkRectangle draw_rect = (*pdraw_rect);
173 
174   gtk_window_move (GTK_WINDOW (window), draw_rect.x, draw_rect.y);
175   gtk_window_resize (GTK_WINDOW (window), draw_rect.width, draw_rect.height);
176 
177   /* We (ab)use app-paintable to indicate if we have an RGBA window */
178   if (!gtk_widget_get_app_paintable (window))
179     {
180       GdkWindow *gdkwindow = gtk_widget_get_window (window);
181 
182       /* Shape the window to make only the outline visible */
183       if (draw_rect.width > 2 && draw_rect.height > 2)
184         {
185           cairo_region_t *region;
186           GdkRectangle region_rect = {
187             0, 0,
188             draw_rect.width, draw_rect.height
189           };
190 
191           region = cairo_region_create_rectangle (&region_rect);
192           region_rect.x++;
193           region_rect.y++;
194           region_rect.width -= 2;
195           region_rect.height -= 2;
196           cairo_region_subtract_rectangle (region, &region_rect);
197 
198           gdk_window_shape_combine_region (gdkwindow, region, 0, 0);
199 
200           cairo_region_destroy (region);
201         }
202       else
203         gdk_window_shape_combine_region (gdkwindow, NULL, 0, 0);
204     }
205 
206 
207   draw_rect.width = ABS (rect->x - x_root);
208   draw_rect.height = ABS (rect->y - y_root);
209 
210   draw_rect.x = MIN (rect->x, x_root);
211   draw_rect.y = MIN (rect->y, y_root);
212 
213   g_debug ("... and Drew %d %d for %d, %d\n", draw_rect.x, draw_rect.y, draw_rect.width, draw_rect.height);
214 
215 }
216 
217 gboolean
select_area_button_press(GtkWidget * window,GdkEventButton * event,select_area_filter_data * data)218 select_area_button_press (GtkWidget * window, GdkEventButton * event, select_area_filter_data * data)
219 {
220   gdouble xroot, yroot;
221   gint x_root, y_root;
222   gdk_event_get_root_coords ((GdkEvent*) event, &xroot, &yroot);
223   x_root = (gint) xroot;
224   y_root = (gint) yroot;
225   gboolean left = (event->button != 3);
226   if (left)
227     {
228       if (!data->button_pressed)
229         {
230           empty_rectangle (x_root, y_root, &data->rect, &data->draw_rect);      //sets the origin, width, height 0
231           data->button_pressed = TRUE;
232         }
233       else
234         {
235           fix_rectangle (x_root, y_root, &data->rect);  //sets the far corner
236           gtk_main_quit ();
237         }
238     }
239   else
240     {
241       gint x = x_root;
242       gint y = y_root;
243       GdkDisplay *disp = gdk_display_get_default ();
244       g_debug ("moving pointer to x %d y %d\n", data->rect.x, data->rect.y);
245       gdk_display_warp_pointer (disp, gdk_display_get_default_screen (disp), data->rect.x, data->rect.y);
246       data->rect.x = x;
247       data->rect.y = y;
248     }
249   return TRUE;
250 }
251 
252 static gboolean
select_area_motion_notify(GtkWidget * window,GdkEventMotion * event,select_area_filter_data * data)253 select_area_motion_notify (GtkWidget * window, GdkEventMotion * event, select_area_filter_data * data)
254 {
255   gdouble xroot, yroot;
256   gint x_root, y_root;
257   gdk_event_get_root_coords ((GdkEvent*) event, &xroot, &yroot);
258   x_root = (gint) xroot;
259   y_root = (gint) yroot;
260   select_area_motion_action (window, &data->rect, &data->draw_rect, x_root, y_root);    //draws the rectangle
261   return TRUE;
262 
263 }
264 
265 static gboolean
select_area_key_press(GtkWidget * window,GdkEventKey * event,select_area_filter_data * data)266 select_area_key_press (GtkWidget * window, GdkEventKey * event, select_area_filter_data * data)
267 {
268 
269   data->button_pressed = FALSE;
270   data->rect.x = 0;
271   data->rect.y = 0;
272   data->rect.width = 0;
273   data->rect.height = 0;
274   gtk_main_quit ();
275   return TRUE;
276 
277 }
278 
279 void
screenshot_select_area_async(SelectAreaCallback callback)280 screenshot_select_area_async (SelectAreaCallback callback)
281 {
282   GdkCursor *cursor;
283   select_area_filter_data data;
284   CallbackData *cb_data;
285   GdkDeviceManager *manager;
286   GdkDevice *pointer, *keyboard;
287   GdkGrabStatus res;
288 
289   data.rect.x = 0;
290   data.rect.y = 0;
291   data.rect.width = 0;
292   data.rect.height = 0;
293   data.button_pressed = FALSE;
294   data.aborted = FALSE;
295   data.window = create_select_window ();
296 
297   cb_data = g_slice_new0 (CallbackData);
298   cb_data->callback = callback;
299 
300   g_signal_connect (data.window, "key-press-event", G_CALLBACK (select_area_key_press), &data);
301   g_signal_connect (data.window, "button-press-event", G_CALLBACK (select_area_button_press), &data);
302   g_signal_connect (data.window, "motion-notify-event", G_CALLBACK (select_area_motion_notify), &data);
303 
304   cursor = gdk_cursor_new (GDK_CROSSHAIR);
305   manager = gdk_display_get_device_manager (gdk_display_get_default ());
306   pointer = gdk_device_manager_get_client_pointer (manager);
307   keyboard = gdk_device_get_associated_device (pointer);
308 
309   res = gdk_device_grab (pointer, gtk_widget_get_window (data.window), GDK_OWNERSHIP_NONE, FALSE, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK, cursor, GDK_CURRENT_TIME);
310 
311   if (res != GDK_GRAB_SUCCESS)
312     {
313       g_object_unref (cursor);
314       goto out;
315     }
316 
317   res = gdk_device_grab (keyboard, gtk_widget_get_window (data.window), GDK_OWNERSHIP_NONE, FALSE, GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK, NULL, GDK_CURRENT_TIME);
318   if (res != GDK_GRAB_SUCCESS)
319     {
320       gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
321       g_object_unref (cursor);
322       goto out;
323     }
324 
325   gtk_main ();
326 
327   gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
328   gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
329 
330   gtk_widget_destroy (data.window);
331   g_object_unref (cursor);
332 
333   gdk_flush ();
334 
335 out:
336   cb_data->aborted = data.aborted;
337   cb_data->rectangle = data.rect;
338 
339   /* FIXME: we should actually be emitting the callback When
340    * the compositor has finished re-drawing, but there seems to be no easy
341    * way to know that.
342    */
343   g_timeout_add (200, emit_select_callback_in_idle, cb_data);
344 }
345 
346 
347 gboolean
screenshot_select_area(int * px,int * py,int * pwidth,int * pheight)348 screenshot_select_area (int *px, int *py, int *pwidth, int *pheight)
349 {
350   screenshot_select_area_async (rectangle_found_cb);
351   gtk_main ();
352   if (the_data.rect.width > 0)
353     {
354       *px = the_data.rect.x;
355       *py = the_data.rect.y;
356       *pwidth = the_data.rect.width;
357       *pheight = the_data.rect.height;
358       the_data.rect.x += the_data.rect.width;
359       the_data.rect.y += the_data.rect.height;
360       return TRUE;
361     }
362   else
363     return FALSE;
364 }
365 
366 GdkRectangle *
screenshot_find_rectangle(void)367 screenshot_find_rectangle (void)
368 {
369   GdkRectangle *rectangle;
370   rectangle = g_new0 (GdkRectangle, 1);
371   if (screenshot_select_area (&rectangle->x, &rectangle->y, &rectangle->width, &rectangle->height))
372     {
373       if ((rectangle->width > 0) && (rectangle->height > 0))
374         return rectangle;
375     }
376   g_free (rectangle);
377   return NULL;
378 }
379 
380 GdkPixbuf *
screenshot_get_pixbuf(GdkWindow * window,GdkRectangle * rectangle)381 screenshot_get_pixbuf (GdkWindow * window, GdkRectangle * rectangle)
382 {
383   GdkWindow *root;
384   GdkPixbuf *screenshot = NULL;
385   gint x_orig, y_orig;
386   gint width, height;
387   root = gdk_get_default_root_window ();
388 
389   if (rectangle)
390     {
391       x_orig = rectangle->x;
392       y_orig = rectangle->y;
393       width = rectangle->width;
394       height = rectangle->height;
395       if (width > 0 && height > 0)
396         screenshot = gdk_pixbuf_get_from_window (root, x_orig, y_orig, width, height);
397     }
398   return screenshot;
399 }
400 #else
401 GdkPixbuf *
screenshot_get_pixbuf(GdkWindow * window,GdkRectangle * rectangle)402 screenshot_get_pixbuf (GdkWindow * window, GdkRectangle * rectangle)
403 {
404   g_warning ("Not available on gtk3 yet");
405   return NULL;
406 }
407 #endif //remove to compile and test on gtk3
408 
409 
410 #else //gtk 2
411 /* screenshot.c - Take a screenshot from user selected rectangle
412  * Copyright (C) 2011 Richard Shann
413  *
414  * Copyright (C) 2001 Jonathan Blandford <jrb@alum.mit.edu>
415  * Copyright (C) 2006 Emmanuele Bassi <ebassi@gnome.org>
416  * Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
417  * Copyright (C) 2011 Philippe Corbes <philippe.corbes@gmail.com>
418  *
419  * This program is free software; you can redistribute it and/or
420  * modify it under the terms of the GNU General Public License as
421  * published by the Free Software Foundation; either version 2 of the
422  * License, or (at your option) any later version.
423  *
424  * This program is distributed in the hope that it will be useful,
425  * but WITHOUT ANY WARRANTY; without even the implied warranty of
426  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
427  * GNU General Public License for more details.
428  *
429  * You should have received a copy of the GNU General Public License
430  * along with this program; if not, write to the Free Software
431  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
432  * USA
433  */
434 #include <gtk/gtk.h>
435 #include <glib.h>
436 #ifdef G_OS_WIN32
437 #include "windows.h"
438 #else
439 #include <gdk/gdkx.h>
440 #endif
441 
442 
443 
444 
445 typedef struct
446 {
447   GdkRectangle rect;
448   GdkRectangle draw_rect;
449   gboolean button_pressed;
450   /* only needed because we're not using cairo to draw the rectangle */
451   GdkWindow *root;
452   GdkGC *gc;
453 } select_area_filter_data;
454 
455 
456 #ifdef G_OS_WIN32
457 #else
458 static void
empty_rectangle(XButtonEvent * event,GdkRectangle * rect,GdkRectangle * draw_rect)459 empty_rectangle (XButtonEvent * event, GdkRectangle * rect, GdkRectangle * draw_rect)
460 {
461   rect->x = event->x_root;
462   rect->y = event->y_root;
463 
464   draw_rect->x = rect->x;
465   draw_rect->y = rect->y;
466   draw_rect->width = 0;
467   draw_rect->height = 0;
468 }
469 
470 static void
fix_rectangle(XButtonEvent * event,GdkRectangle * rect,GdkRectangle * draw_rect,GdkWindow * root,GdkGC * gc)471 fix_rectangle (XButtonEvent * event, GdkRectangle * rect, GdkRectangle * draw_rect, GdkWindow * root, GdkGC * gc)
472 {
473   /* do not remove the old rectangle as it shows you what you have captured so far */
474   rect->width = ABS (rect->x - event->x_root);
475   rect->height = ABS (rect->y - event->y_root);
476 
477   rect->x = MIN (rect->x, event->x_root);
478   rect->y = MIN (rect->y, event->y_root);
479 }
480 
481 static void
select_area_motion_notify(XButtonEvent * event,GdkRectangle * rect,GdkRectangle * draw_rect,GdkWindow * root,GdkGC * gc)482 select_area_motion_notify (XButtonEvent * event, GdkRectangle * rect, GdkRectangle * draw_rect, GdkWindow * root, GdkGC * gc)
483 {
484   /* FIXME: draw some nice rubberband with cairo if composited */
485 
486   /* remove the old rectangle */
487   if (draw_rect->width > 0 && draw_rect->height > 0)
488     gdk_draw_rectangle (root, gc, FALSE, draw_rect->x, draw_rect->y, draw_rect->width, draw_rect->height);
489   draw_rect->width = ABS (rect->x - event->x_root);
490   draw_rect->height = ABS (rect->y - event->y_root);
491 
492   draw_rect->x = MIN (rect->x, event->x_root);
493   draw_rect->y = MIN (rect->y, event->y_root);
494 
495   /* draw the new rectangle */
496   if (draw_rect->width > 0 && draw_rect->height > 0)
497     gdk_draw_rectangle (root, gc, FALSE, draw_rect->x, draw_rect->y, draw_rect->width, draw_rect->height);
498 }
499 #endif
500 
501 
502 static GdkFilterReturn
select_area_filter(GdkXEvent * gdk_xevent,GdkEvent * event,gpointer user_data)503 select_area_filter (GdkXEvent * gdk_xevent, GdkEvent * event, gpointer user_data)
504 {
505   select_area_filter_data *data = user_data;
506 #ifdef G_OS_WIN32
507   MSG *wevent = (MSG *) gdk_xevent;
508   g_debug ("Received event %x %x %x at %ld %ld\n", wevent->message, wevent->wParam, wevent->lParam, wevent->pt.x, wevent->pt.y);
509   return GDK_FILTER_REMOVE;
510 #else
511   XEvent *xevent = (XEvent *) gdk_xevent;
512   switch (xevent->type)
513     {
514     case ButtonPress:
515       switch (xevent->xbutton.button)
516         {
517         case 1:
518           if (!data->button_pressed)
519             {
520               empty_rectangle (&xevent->xbutton, &data->rect, &data->draw_rect);        //sets the origin, width, height 0
521               data->button_pressed = TRUE;
522             }
523           else
524             {
525               fix_rectangle (&xevent->xbutton, &data->rect, &data->draw_rect, data->root, data->gc);    //sets the far corner
526               gtk_main_quit ();
527             }
528           break;
529         case 2:
530         case 3:
531         case 4:                //scroll up
532         case 5:                //scroll down
533           {
534             gint x = xevent->xbutton.x_root;
535             gint y = xevent->xbutton.y_root;
536             GdkDisplay *disp = gdk_display_get_default ();
537             g_debug ("moving pointer to x %d y %d\n", data->rect.x, data->rect.y);
538             gdk_display_warp_pointer (disp, gdk_display_get_default_screen (disp), data->rect.x, data->rect.y);
539             data->rect.x = x;
540             data->rect.y = y;
541             break;
542           }
543         default:
544           g_debug ("button %d\n", xevent->xbutton.button);
545           //return GDK_FILTER_CONTINUE; no other application responds to the button press even with this return value.
546           break;
547         }
548       return GDK_FILTER_REMOVE;
549     case ButtonRelease:
550       return GDK_FILTER_REMOVE;
551     case MotionNotify:
552       if (data->button_pressed)
553         select_area_motion_notify (&xevent->xbutton, &data->rect, &data->draw_rect, data->root, data->gc);      //draws the rectangle
554       return GDK_FILTER_REMOVE;
555     case KeyPress:
556       // if (xevent->xkey.keycode == XKeysymToKeycode (gdk_display, XK_Escape)) let any key end - may need to re-instate this for Ctrl-press to join pixbufs
557       {
558         // this undraws in the wrong place,
559         // gdk_draw_rectangle (data->root, data->gc, FALSE,
560         //               data->rect.x - data->rect.width, data->rect.y - data->rect.height,
561         //              data->rect.width, data->rect.height);
562         data->button_pressed = FALSE;
563         data->rect.x = 0;
564         data->rect.y = 0;
565         data->rect.width = 0;
566         data->rect.height = 0;
567         gtk_main_quit ();
568         return GDK_FILTER_REMOVE;
569       }
570       break;
571     default:
572       break;
573     }
574 #endif
575 
576 
577   return GDK_FILTER_CONTINUE;
578 }
579 
580 gboolean
screenshot_select_area(int * px,int * py,int * pwidth,int * pheight)581 screenshot_select_area (int *px, int *py, int *pwidth, int *pheight)
582 {
583   GdkWindow *root;
584   GdkCursor *cursor;
585   static select_area_filter_data data;
586   GdkGCValues values;
587   GdkColor color;
588 #ifdef G_OS_WIN32
589   g_warning ("Not available on windows, sorry");
590   return FALSE;
591 #endif
592   root = gdk_get_default_root_window ();
593   cursor = gdk_cursor_new (GDK_CROSSHAIR);
594 
595   if (gdk_pointer_grab (root, FALSE, GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK, NULL, cursor, GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
596     {
597       gdk_cursor_unref (cursor);
598       return FALSE;
599     }
600 
601   if (gdk_keyboard_grab (root, FALSE, GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
602     {
603       gdk_pointer_ungrab (GDK_CURRENT_TIME);
604       gdk_cursor_unref (cursor);
605       return FALSE;
606     }
607 
608   gdk_window_add_filter (root, (GdkFilterFunc) select_area_filter, &data);
609 
610   gdk_flush ();
611 
612   data.root = root;
613 
614   values.function = GDK_XOR;
615   values.fill = GDK_SOLID;
616   values.clip_mask = NULL;
617   values.subwindow_mode = GDK_INCLUDE_INFERIORS;
618   values.clip_x_origin = 0;
619   values.clip_y_origin = 0;
620   values.graphics_exposures = 0;
621   values.line_width = 0;
622   values.line_style = GDK_LINE_SOLID;
623   values.cap_style = GDK_CAP_BUTT;
624   values.join_style = GDK_JOIN_MITER;
625 
626   data.gc = gdk_gc_new_with_values (root, &values, GDK_GC_FUNCTION | GDK_GC_FILL | GDK_GC_CLIP_MASK | GDK_GC_SUBWINDOW | GDK_GC_CLIP_X_ORIGIN | GDK_GC_CLIP_Y_ORIGIN | GDK_GC_EXPOSURES | GDK_GC_LINE_WIDTH | GDK_GC_LINE_STYLE | GDK_GC_CAP_STYLE | GDK_GC_JOIN_STYLE);
627   gdk_color_parse ("white", &color);
628   gdk_gc_set_rgb_fg_color (data.gc, &color);
629   gdk_color_parse ("black", &color);
630   gdk_gc_set_rgb_bg_color (data.gc, &color);
631 
632   if (data.button_pressed)
633     {
634       GdkDisplay *disp = gdk_display_get_default ();
635       //g_debug("re-starting and moving pointer to x %d y %d\n", data.rect.x+data.rect.width, data.rect.y);
636       gdk_display_warp_pointer (disp, gdk_display_get_default_screen (disp), data.rect.x + data.rect.width, data.rect.y - data.rect.height);
637     }
638 
639   gtk_main ();
640 
641   g_object_unref (data.gc);
642 
643   gdk_window_remove_filter (root, (GdkFilterFunc) select_area_filter, &data);
644 
645   gdk_keyboard_ungrab (GDK_CURRENT_TIME);
646   gdk_pointer_ungrab (GDK_CURRENT_TIME);
647   gdk_cursor_unref (cursor);
648 
649   *px = data.rect.x;
650   *py = data.rect.y;
651   *pwidth = data.rect.width;
652   *pheight = data.rect.height;
653   data.rect.x += data.rect.width;
654   data.rect.y += data.rect.height;
655   return TRUE;
656 }
657 
658 GdkRectangle *
screenshot_find_rectangle(void)659 screenshot_find_rectangle (void)
660 {
661   GdkRectangle *rectangle;
662   rectangle = g_new0 (GdkRectangle, 1);
663   if (screenshot_select_area (&rectangle->x, &rectangle->y, &rectangle->width, &rectangle->height))
664     {
665       if ((rectangle->width > 0) && (rectangle->height > 0))
666         return rectangle;
667     }
668   g_free (rectangle);
669   return NULL;
670 }
671 
672 GdkPixbuf *
screenshot_get_pixbuf(GdkWindow * window,GdkRectangle * rectangle)673 screenshot_get_pixbuf (GdkWindow * window, GdkRectangle * rectangle)
674 {
675   GdkWindow *root;
676   GdkPixbuf *screenshot = NULL;
677   gint x_orig, y_orig;
678   gint width, real_width, height, real_height;
679   root = gdk_get_default_root_window ();
680 
681   if (rectangle)
682     {
683       x_orig = rectangle->x;
684       y_orig = rectangle->y;
685       width = rectangle->width;
686       height = rectangle->height;
687       if (width > 0 && height > 0)
688         screenshot = gdk_pixbuf_get_from_drawable (NULL, root, NULL, x_orig, y_orig, 0, 0, width, height);
689     }
690   return screenshot;
691 }
692 
693 #endif //gtk2 version
694 #endif //_HAVE_X11_
695