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 (®ion_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, ®ion_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