gnome-utils r8437 - trunk/gnome-screenshot
- From: cosimoc svn gnome org
- To: svn-commits-list gnome org
- Subject: gnome-utils r8437 - trunk/gnome-screenshot
- Date: Fri, 27 Feb 2009 13:40:05 +0000 (UTC)
Author: cosimoc
Date: Fri Feb 27 13:40:05 2009
New Revision: 8437
URL: http://svn.gnome.org/viewvc/gnome-utils?rev=8437&view=rev
Log:
2009-02-27 Cosimo Cecchi <cosimoc gnome org>
* gnome-screenshot.c (target_toggled_cb),
(create_screenshot_frame), (finish_prepare_screenshot),
(async_existence_job_free), (check_file_done), (find_rectangle),
(prepare_screenshot), (main):
* screenshot-utils.c (select_area_button_press),
(select_area_button_release), (select_area_motion_notify),
(select_area_filter), (screenshot_select_area),
(screenshot_get_pixbuf):
* screenshot-utils.h: add support for taking a screenshot of an
user-defined selection.
Patch by Vincent Untz, bug #155061.
Modified:
trunk/gnome-screenshot/ChangeLog
trunk/gnome-screenshot/gnome-screenshot.c
trunk/gnome-screenshot/screenshot-utils.c
trunk/gnome-screenshot/screenshot-utils.h
Modified: trunk/gnome-screenshot/gnome-screenshot.c
==============================================================================
--- trunk/gnome-screenshot/gnome-screenshot.c (original)
+++ trunk/gnome-screenshot/gnome-screenshot.c Fri Feb 27 13:40:05 2009
@@ -86,6 +86,7 @@
int iteration;
TestType type;
GdkWindow *window;
+ GdkRectangle *rectangle;
} AsyncExistenceJob;
static GdkPixbuf *screenshot = NULL;
@@ -98,6 +99,7 @@
/* Options */
static gboolean take_window_shot = FALSE;
+static gboolean take_area_shot = FALSE;
static gboolean include_border = FALSE;
static gboolean include_pointer = TRUE;
static char *border_effect = NULL;
@@ -148,15 +150,20 @@
}
}
+#define TARGET_TOGGLE_DESKTOP 0
+#define TARGET_TOGGLE_WINDOW 1
+#define TARGET_TOGGLE_AREA 2
+
static void
target_toggled_cb (GtkToggleButton *button,
gpointer data)
{
- gboolean window_selected = (GPOINTER_TO_INT (data) == TRUE ? TRUE : FALSE);
+ int target_toggle = GPOINTER_TO_INT (data);
if (gtk_toggle_button_get_active (button))
{
- take_window_shot = window_selected;
+ take_window_shot = (target_toggle == TARGET_TOGGLE_WINDOW);
+ take_area_shot = (target_toggle == TARGET_TOGGLE_AREA);
gtk_widget_set_sensitive (border_check, take_window_shot);
gtk_widget_set_sensitive (effect_combo, take_window_shot);
@@ -421,11 +428,11 @@
group = NULL;
radio = gtk_radio_button_new_with_mnemonic (group,
_("Grab the whole _desktop"));
- if (take_window_shot)
+ if (take_window_shot || take_area_shot)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), FALSE);
g_signal_connect (radio, "toggled",
G_CALLBACK (target_toggled_cb),
- GINT_TO_POINTER (FALSE));
+ GINT_TO_POINTER (TARGET_TOGGLE_DESKTOP));
gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, FALSE, 0);
group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio));
gtk_widget_show (radio);
@@ -437,7 +444,19 @@
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE);
g_signal_connect (radio, "toggled",
G_CALLBACK (target_toggled_cb),
- GINT_TO_POINTER (TRUE));
+ GINT_TO_POINTER (TARGET_TOGGLE_WINDOW));
+ gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, FALSE, 0);
+ group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio));
+ gtk_widget_show (radio);
+
+ /** Grab area of the desktop **/
+ radio = gtk_radio_button_new_with_mnemonic (group,
+ _("Grab a selected _area"));
+ if (take_area_shot)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio), TRUE);
+ g_signal_connect (radio, "toggled",
+ G_CALLBACK (target_toggled_cb),
+ GINT_TO_POINTER (TARGET_TOGGLE_AREA));
gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, FALSE, 0);
gtk_widget_show (radio);
@@ -748,16 +767,16 @@
}
static void
-finish_prepare_screenshot (char *initial_uri, GdkWindow *window)
+finish_prepare_screenshot (char *initial_uri, GdkWindow *window, GdkRectangle *rectangle)
{
ScreenshotDialog *dialog;
- /* always disable window border for full-desktop screenshots */
+ /* always disable window border for full-desktop or selected-area screenshots */
if (!take_window_shot)
- screenshot = screenshot_get_pixbuf (window, include_pointer, FALSE);
+ screenshot = screenshot_get_pixbuf (window, rectangle, include_pointer, FALSE);
else
{
- screenshot = screenshot_get_pixbuf (window, include_pointer, include_border);
+ screenshot = screenshot_get_pixbuf (window, rectangle, include_pointer, include_border);
switch (border_effect[0])
{
@@ -792,20 +811,26 @@
run_dialog (dialog);
}
-static gboolean
-check_file_done (gpointer user_data)
+static void
+async_existence_job_free (AsyncExistenceJob *job)
{
- char *retval;
- GdkWindow *window;
- AsyncExistenceJob *job = user_data;
+ if (!job)
+ return;
- window = job->window;
- retval = job->retval;
g_free (job->base_uris[1]);
g_free (job->base_uris[2]);
+ g_free (job->rectangle);
g_slice_free (AsyncExistenceJob, job);
-
- finish_prepare_screenshot (retval, window);
+}
+
+static gboolean
+check_file_done (gpointer user_data)
+{
+ AsyncExistenceJob *job = user_data;
+
+ finish_prepare_screenshot (job->retval, job->window, job->rectangle);
+
+ async_existence_job_free (job);
return FALSE;
}
@@ -984,6 +1009,30 @@
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)
{
@@ -997,6 +1046,16 @@
job->iteration = 0;
job->type = TEST_LAST_DIR;
job->window = find_current_window (&window_title);
+ job->rectangle = find_rectangle ();
+
+ /* Check if the area selection was cancelled */
+ if (job->rectangle &&
+ (job->rectangle->width == 0 || job->rectangle->height == 0))
+ {
+ async_existence_job_free (job);
+ gtk_main_quit ();
+ return;
+ }
g_io_scheduler_push_job (try_check_file,
job,
@@ -1168,6 +1227,7 @@
GOptionContext *context;
GOptionGroup *group;
gboolean window_arg = FALSE;
+ gboolean area_arg = FALSE;
gboolean include_border_arg = FALSE;
gboolean disable_border_arg = FALSE;
gboolean interactive_arg = FALSE;
@@ -1177,6 +1237,7 @@
const GOptionEntry entries[] = {
{ "window", 'w', 0, G_OPTION_ARG_NONE, &window_arg, N_("Grab a window instead of the entire screen"), NULL },
+ { "area", 'a', 0, G_OPTION_ARG_NONE, &area_arg, N_("Grab an area of the screen instead of the entire screen"), NULL },
{ "include-border", 'b', 0, G_OPTION_ARG_NONE, &include_border_arg, N_("Include the window border with the screenshot"), NULL },
{ "remove-border", 'B', 0, G_OPTION_ARG_NONE, &disable_border_arg, N_("Remove the window border from the screenshot"), NULL },
{ "delay", 'd', 0, G_OPTION_ARG_INT, &delay_arg, N_("Take screenshot after specified delay [in seconds]"), N_("seconds") },
@@ -1209,6 +1270,12 @@
g_option_context_free (context);
+ if (window_arg && area_arg) {
+ g_printerr (_("Conflicting options: --window and --area should not be "
+ "used at the same time.\n"));
+ exit (1);
+ }
+
gtk_window_set_default_icon_name (SCREENSHOOTER_ICON);
screenshooter_init_stock_icons ();
@@ -1217,6 +1284,9 @@
if (window_arg)
take_window_shot = TRUE;
+ if (area_arg)
+ take_area_shot = TRUE;
+
if (include_border_arg)
include_border = TRUE;
Modified: trunk/gnome-screenshot/screenshot-utils.c
==============================================================================
--- trunk/gnome-screenshot/screenshot-utils.c (original)
+++ trunk/gnome-screenshot/screenshot-utils.c Fri Feb 27 13:40:05 2009
@@ -253,6 +253,212 @@
return current_window;
}
+static void
+select_area_button_press (XKeyEvent *event,
+ GdkRectangle *rect,
+ GdkRectangle *draw_rect)
+{
+ rect->x = event->x_root;
+ rect->y = event->y_root;
+
+ draw_rect->x = rect->x;
+ draw_rect->y = rect->y;
+ draw_rect->width = 0;
+ draw_rect->height = 0;
+}
+
+static void
+select_area_button_release (XKeyEvent *event,
+ GdkRectangle *rect,
+ GdkRectangle *draw_rect,
+ GdkWindow *root,
+ GdkGC *gc)
+{
+ /* remove the old rectangle */
+ if (draw_rect->width > 0 && draw_rect->height > 0)
+ gdk_draw_rectangle (root, gc, FALSE,
+ draw_rect->x, draw_rect->y,
+ draw_rect->width, draw_rect->height);
+
+ rect->width = ABS (rect->x - event->x_root);
+ rect->height = ABS (rect->y - event->y_root);
+
+ rect->x = MIN (rect->x, event->x_root);
+ rect->y = MIN (rect->y, event->y_root);
+}
+
+static void
+select_area_motion_notify (XKeyEvent *event,
+ GdkRectangle *rect,
+ GdkRectangle *draw_rect,
+ GdkWindow *root,
+ GdkGC *gc)
+{
+ /* FIXME: draw some nice rubberband with cairo if composited */
+
+ /* remove the old rectangle */
+ if (draw_rect->width > 0 && draw_rect->height > 0)
+ gdk_draw_rectangle (root, gc, FALSE,
+ draw_rect->x, draw_rect->y,
+ draw_rect->width, draw_rect->height);
+
+ 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);
+
+ /* draw the new rectangle */
+ if (draw_rect->width > 0 && draw_rect->height > 0)
+ gdk_draw_rectangle (root, gc, FALSE,
+ draw_rect->x, draw_rect->y,
+ draw_rect->width, draw_rect->height);
+}
+
+typedef struct {
+ GdkRectangle rect;
+ GdkRectangle draw_rect;
+ gboolean button_pressed;
+ /* only needed because we're not using cairo to draw the rectangle */
+ GdkWindow *root;
+ GdkGC *gc;
+} select_area_filter_data;
+
+static GdkFilterReturn
+select_area_filter (GdkXEvent *gdk_xevent,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ select_area_filter_data *data = user_data;
+ XEvent *xevent = (XEvent *) gdk_xevent;
+
+ 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->root, data->gc);
+ 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->root, data->gc);
+ return GDK_FILTER_REMOVE;
+ case KeyPress:
+ if (xevent->xkey.keycode == XKeysymToKeycode (gdk_display, 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;
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+gboolean
+screenshot_select_area (int *px,
+ int *py,
+ int *pwidth,
+ int *pheight)
+{
+ GdkWindow *root;
+ GdkCursor *cursor;
+ select_area_filter_data data;
+ GdkGCValues values;
+ GdkColor color;
+
+ root = gdk_get_default_root_window ();
+ cursor = gdk_cursor_new (GDK_CROSSHAIR);
+
+ 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)
+ {
+ gdk_cursor_unref (cursor);
+ return FALSE;
+ }
+
+ if (gdk_keyboard_grab (root, FALSE, GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
+ {
+ gdk_pointer_ungrab (GDK_CURRENT_TIME);
+ gdk_cursor_unref (cursor);
+ return FALSE;
+ }
+
+ 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.root = root;
+
+ values.function = GDK_XOR;
+ values.fill = GDK_SOLID;
+ values.clip_mask = NULL;
+ values.subwindow_mode = GDK_INCLUDE_INFERIORS;
+ values.clip_x_origin = 0;
+ values.clip_y_origin = 0;
+ values.graphics_exposures = 0;
+ values.line_width = 0;
+ values.line_style = GDK_LINE_SOLID;
+ values.cap_style = GDK_CAP_BUTT;
+ values.join_style = GDK_JOIN_MITER;
+
+ 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);
+ gdk_color_parse ("white", &color);
+ gdk_gc_set_rgb_fg_color (data.gc, &color);
+ gdk_color_parse ("black", &color);
+ gdk_gc_set_rgb_bg_color (data.gc, &color);
+
+ gtk_main ();
+
+ g_object_unref (data.gc);
+
+ gdk_window_remove_filter (root, (GdkFilterFunc) select_area_filter, &data);
+
+ gdk_keyboard_ungrab (GDK_CURRENT_TIME);
+ gdk_pointer_ungrab (GDK_CURRENT_TIME);
+ gdk_cursor_unref (cursor);
+
+ *px = data.rect.x;
+ *py = data.rect.y;
+ *pwidth = data.rect.width;
+ *pheight = data.rect.height;
+
+ return TRUE;
+}
+
static Window
find_wm_window (Window xid)
{
@@ -401,9 +607,10 @@
}
GdkPixbuf *
-screenshot_get_pixbuf (GdkWindow *window,
- gboolean include_pointer,
- gboolean include_border)
+screenshot_get_pixbuf (GdkWindow *window,
+ GdkRectangle *rectangle,
+ gboolean include_pointer,
+ gboolean include_border)
{
GdkWindow *root;
GdkPixbuf *screenshot;
@@ -452,6 +659,14 @@
if (y_orig + height > gdk_screen_height ())
height = gdk_screen_height () - y_orig;
+
+ if (rectangle)
+ {
+ x_orig = rectangle->x - x_orig;
+ y_orig = rectangle->y - y_orig;
+ width = rectangle->width;
+ height = rectangle->height;
+ }
screenshot = gdk_pixbuf_get_from_drawable (NULL, root, NULL,
x_orig, y_orig, 0, 0,
@@ -545,7 +760,9 @@
}
#endif /* HAVE_X11_EXTENSIONS_SHAPE_H */
- if (include_pointer)
+ /* if we have a selected area, there were by definition no cursor in the
+ * screenshot */
+ if (include_pointer && !rectangle)
{
GdkCursor *cursor;
GdkPixbuf *cursor_pixbuf;
Modified: trunk/gnome-screenshot/screenshot-utils.h
==============================================================================
--- trunk/gnome-screenshot/screenshot-utils.h (original)
+++ trunk/gnome-screenshot/screenshot-utils.h Fri Feb 27 13:40:05 2009
@@ -29,7 +29,12 @@
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);
GdkPixbuf *screenshot_get_pixbuf (GdkWindow *win,
+ GdkRectangle *rectangle,
gboolean include_pointer,
gboolean include_border);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]