[gnome-utils] screenshot: Don't draw directly to the root window
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-utils] screenshot: Don't draw directly to the root window
- Date: Wed, 1 Sep 2010 12:58:00 +0000 (UTC)
commit deca32637589e02df751a08292a308c27d8b3ab4
Author: Benjamin Otte <otte redhat com>
Date: Wed Sep 1 13:57:57 2010 +0200
screenshot: Don't draw directly to the root window
Instead, create a GtkWindow to draw the selected area with. As a side
effect, the selected area looks much nicer and not like 1995 anymore.
Also, the code doesn't use deprecated APIs anymore.
https://bugzilla.gnome.org/show_bug.cgi?id=628499
gnome-screenshot/screenshot-utils.c | 174 +++++++++++++++++++++++------------
1 files changed, 117 insertions(+), 57 deletions(-)
---
diff --git a/gnome-screenshot/screenshot-utils.c b/gnome-screenshot/screenshot-utils.c
index 6e0475e..f794283 100644
--- a/gnome-screenshot/screenshot-utils.c
+++ b/gnome-screenshot/screenshot-utils.c
@@ -91,7 +91,6 @@ gboolean
screenshot_grab_lock (void)
{
GdkAtom selection_atom;
- GdkCursor *cursor;
gboolean result = FALSE;
selection_atom = gdk_atom_intern (SELECTION_NAME, FALSE);
@@ -268,17 +267,56 @@ select_area_button_press (XKeyEvent *event,
}
static void
+select_area_update_rect (GtkWidget *window,
+ GdkRectangle *rect)
+{
+ if (rect->width <= 0 || rect->height <= 0)
+ {
+ gtk_widget_hide (window);
+ return;
+ }
+
+ gtk_window_move (GTK_WINDOW (window), rect->x, rect->y);
+ gtk_window_resize (GTK_WINDOW (window), rect->width, rect->height);
+ gtk_widget_show (window);
+
+ /* We (ab)use app-paintable to indicate if we have an RGBA window */
+ if (!gtk_widget_get_app_paintable (window))
+ {
+ GdkWindow *gdkwindow = gtk_widget_get_window (window);
+
+ /* Shape the window to make only the outline visible */
+ if (rect->width > 2 && rect->height > 2)
+ {
+ GdkRegion *region, *region2;
+ GdkRectangle region_rect = { 0, 0,
+ rect->width - 2, rect->height - 2 };
+
+ region = gdk_region_rectangle (®ion_rect);
+ region_rect.x++;
+ region_rect.y++;
+ region_rect.width -= 2;
+ region_rect.height -= 2;
+ region2 = gdk_region_rectangle (®ion_rect);
+ gdk_region_subtract (region, region2);
+
+ gdk_window_shape_combine_region (gdkwindow, region, 0, 0);
+
+ gdk_region_destroy (region);
+ gdk_region_destroy (region2);
+ }
+ else
+ gdk_window_shape_combine_region (gdkwindow, NULL, 0, 0);
+ }
+}
+
+static void
select_area_button_release (XKeyEvent *event,
GdkRectangle *rect,
GdkRectangle *draw_rect,
- GdkWindow *root,
- GdkGC *gc)
+ GtkWidget *window)
{
- /* 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);
+ gtk_widget_hide (window);
rect->width = ABS (rect->x - event->x_root);
rect->height = ABS (rect->y - event->y_root);
@@ -291,39 +329,87 @@ static void
select_area_motion_notify (XKeyEvent *event,
GdkRectangle *rect,
GdkRectangle *draw_rect,
- GdkWindow *root,
- GdkGC *gc)
+ GtkWidget *window)
{
- /* 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);
+ select_area_update_rect (window, draw_rect);
}
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;
+ GtkWidget *window;
} select_area_filter_data;
+static gboolean
+expose (GtkWidget *window, GdkEventExpose *event, gpointer unused)
+{
+ GtkAllocation allocation;
+ GtkStyle *style;
+ cairo_t *cr;
+
+ cr = gdk_cairo_create (event->window);
+ gdk_cairo_region (cr, event->region);
+ cairo_clip (cr);
+
+ style = gtk_widget_get_style (window);
+
+ if (gtk_widget_get_app_paintable (window))
+ {
+ cairo_set_line_width (cr, 1.0);
+
+ gtk_widget_get_allocation (window, &allocation);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_set_source_rgba (cr, 0, 0, 0, 0);
+ cairo_paint (cr);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_SELECTED]);
+ cairo_paint_with_alpha (cr, 0.25);
+
+ cairo_rectangle (cr,
+ allocation.x + 0.5, allocation.y + 0.5,
+ allocation.width - 1, allocation.height - 1);
+ cairo_stroke (cr);
+ }
+ else
+ {
+ gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_SELECTED]);
+ cairo_paint (cr);
+ }
+
+ cairo_destroy (cr);
+
+ return TRUE;
+}
+
+static GtkWidget *
+create_select_window (void)
+{
+ GtkWidget *window;
+ GdkScreen *screen;
+
+ screen = gdk_screen_get_default ();
+
+ window = gtk_window_new (GTK_WINDOW_POPUP);
+ if (gdk_screen_is_composited (screen) &&
+ gdk_screen_get_rgba_colormap (screen))
+ {
+ gtk_widget_set_colormap (window, gdk_screen_get_rgba_colormap (screen));
+ gtk_widget_set_app_paintable (window, TRUE);
+ }
+ g_signal_connect (window, "expose-event", G_CALLBACK (expose), NULL);
+
+ return window;
+}
+
static GdkFilterReturn
select_area_filter (GdkXEvent *gdk_xevent,
GdkEvent *event,
@@ -347,7 +433,7 @@ select_area_filter (GdkXEvent *gdk_xevent,
{
select_area_button_release (&xevent->xkey,
&data->rect, &data->draw_rect,
- data->root, data->gc);
+ data->window);
gtk_main_quit ();
}
return GDK_FILTER_REMOVE;
@@ -355,7 +441,7 @@ select_area_filter (GdkXEvent *gdk_xevent,
if (data->button_pressed)
select_area_motion_notify (&xevent->xkey,
&data->rect, &data->draw_rect,
- data->root, data->gc);
+ data->window);
return GDK_FILTER_REMOVE;
case KeyPress:
if (xevent->xkey.keycode == XKeysymToKeycode (gdk_display, XK_Escape))
@@ -384,8 +470,6 @@ screenshot_select_area (int *px,
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);
@@ -415,38 +499,14 @@ screenshot_select_area (int *px,
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);
+ data.window = create_select_window();
gtk_main ();
- g_object_unref (data.gc);
-
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);
gdk_cursor_unref (cursor);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]