[Xfce4-commits] [apps/xfce4-screenshooter] 01/01: Allow user to move selection rectangle (Bug #14365)
noreply at xfce.org
noreply at xfce.org
Tue May 1 18:14:53 CEST 2018
This is an automated email from the git hooks/post-receive script.
a n d r e p u s h e d a c o m m i t t o b r a n c h m a s t e r
in repository apps/xfce4-screenshooter.
commit 5983ffb03f7e30b945eac1ea6a58ae8e14fda36e
Author: Andre Miranda <andreldm at xfce.org>
Date: Tue May 1 13:14:41 2018 -0300
Allow user to move selection rectangle (Bug #14365)
---
lib/screenshooter-capture.c | 230 +++++++++++++++++++++++++++++++++++++-------
1 file changed, 195 insertions(+), 35 deletions(-)
diff --git a/lib/screenshooter-capture.c b/lib/screenshooter-capture.c
index d5449b2..8333c70 100644
--- a/lib/screenshooter-capture.c
+++ b/lib/screenshooter-capture.c
@@ -21,11 +21,21 @@
#define BACKGROUND_TRANSPARENCY 0.4
+enum {
+ ANCHOR_UNSET = 0,
+ ANCHOR_NONE = 1,
+ ANCHOR_TOP = 2,
+ ANCHOR_LEFT = 4
+};
+
/* Rubberband data for composited environment */
typedef struct
{
gboolean left_pressed;
gboolean rubber_banding;
+ gboolean cancelled;
+ gboolean move_rectangle;
+ gint anchor;
gint x;
gint y;
gint x_root;
@@ -39,6 +49,8 @@ typedef struct
{
gboolean pressed;
gboolean cancelled;
+ gboolean move_rectangle;
+ gint anchor;
cairo_rectangle_int_t rectangle;
gint x1, y1; /* holds the position where the mouse was pressed */
GC *context;
@@ -69,7 +81,10 @@ static GdkFilterReturn region_filter_func (GdkXEvent *xev
static GdkPixbuf *get_rectangle_screenshot (gint delay);
static gboolean cb_key_pressed (GtkWidget *widget,
GdkEventKey *event,
- gboolean *cancelled);
+ RubberBandData *rbdata);
+static gboolean cb_key_released (GtkWidget *widget,
+ GdkEventKey *event,
+ RubberBandData *rbdata);
static gboolean cb_draw (GtkWidget *widget,
cairo_t *cr,
RubberBandData *rbdata);
@@ -489,14 +504,40 @@ static GdkPixbuf
/* Callbacks for the rubber banding function */
-static gboolean cb_key_pressed (GtkWidget *widget,
- GdkEventKey *event,
- gboolean *cancelled)
+static gboolean cb_key_pressed (GtkWidget *widget,
+ GdkEventKey *event,
+ RubberBandData *rbdata)
{
- if (event->keyval == GDK_KEY_Escape)
+ guint key = event->keyval;
+
+ if (key == GDK_KEY_Escape)
{
gtk_widget_hide (widget);
- *cancelled = TRUE;
+ rbdata->cancelled = TRUE;
+ return TRUE;
+ }
+
+ if (rbdata->left_pressed && (key == GDK_KEY_Control_L || key == GDK_KEY_Control_R))
+ {
+ rbdata->move_rectangle = TRUE;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+static gboolean cb_key_released (GtkWidget *widget,
+ GdkEventKey *event,
+ RubberBandData *rbdata)
+{
+ guint key = event->keyval;
+
+ if (rbdata->left_pressed && (key == GDK_KEY_Control_L || key == GDK_KEY_Control_R))
+ {
+ rbdata->move_rectangle = FALSE;
+ rbdata->anchor = ANCHOR_UNSET;
return TRUE;
}
@@ -644,16 +685,52 @@ static gboolean cb_motion_notify (GtkWidget *widget,
old_rect.height = new_rect->height;
}
- /* Get the new rubber banding rectangle */
- new_rect->x = MIN (rbdata->x , event->x);
- new_rect->y = MIN (rbdata->y, event->y);
- new_rect->width = ABS (rbdata->x - event->x) + 1;
- new_rect->height = ABS (rbdata->y - event->y) +1;
+ if (rbdata->move_rectangle)
+ {
+ /* Define the anchor right after the control key is pressed */
+ if (rbdata->anchor == ANCHOR_UNSET)
+ {
+ rbdata->anchor = ANCHOR_NONE;
+ rbdata->anchor |= (event->x < rbdata->x) ? ANCHOR_LEFT : 0;
+ rbdata->anchor |= (event->y < rbdata->y) ? ANCHOR_TOP : 0;
+ }
+
+ /* Do not resize, instead move the rubber banding rectangle around */
+ if (rbdata->anchor & ANCHOR_LEFT)
+ {
+ rbdata->x = (new_rect->x = event->x) + new_rect->width;
+ rbdata->x_root = (new_rect_root->x = event->x_root) + new_rect->width;
+ }
+ else
+ {
+ rbdata->x = new_rect->x = event->x - new_rect->width;
+ rbdata->x_root = new_rect_root->x = event->x_root - new_rect->width;
+ }
- new_rect_root->x = MIN (rbdata->x_root , event->x_root);
- new_rect_root->y = MIN (rbdata->y_root, event->y_root);
- new_rect_root->width = ABS (rbdata->x_root - event->x_root) + 1;
- new_rect_root->height = ABS (rbdata->y_root - event->y_root) +1;
+ if (rbdata->anchor & ANCHOR_TOP)
+ {
+ rbdata->y = (new_rect->y = event->y) + new_rect->height;
+ rbdata->y_root = (new_rect_root->y = event->y_root) + new_rect->height;
+ }
+ else
+ {
+ rbdata->y = new_rect->y = event->y - new_rect->height;
+ rbdata->x_root = new_rect_root->y = event->y_root - new_rect->height;
+ }
+ }
+ else
+ {
+ /* Get the new rubber banding rectangle */
+ new_rect->x = MIN (rbdata->x, event->x);
+ new_rect->y = MIN (rbdata->y, event->y);
+ new_rect->width = ABS (rbdata->x - event->x) + 1;
+ new_rect->height = ABS (rbdata->y - event->y) + 1;
+
+ new_rect_root->x = MIN (rbdata->x_root, event->x_root);
+ new_rect_root->y = MIN (rbdata->y_root, event->y_root);
+ new_rect_root->width = ABS (rbdata->x_root - event->x_root) + 1;
+ new_rect_root->height = ABS (rbdata->y_root - event->y_root) + 1;
+ }
region = cairo_region_create_rectangle (&old_rect);
cairo_region_union_rectangle (region, new_rect);
@@ -685,12 +762,41 @@ static gboolean cb_motion_notify (GtkWidget *widget,
}
+
+static GdkPixbuf
+*capture_rectangle_screenshot (gint x, gint y, gint w, gint h)
+{
+ GdkWindow *root;
+ int root_width, root_height;
+
+ root = gdk_get_default_root_window ();
+ root_width = gdk_window_get_width (root);
+ root_height = gdk_window_get_height (root);
+
+ /* Avoid rectangle parts outside the screen */
+ if (x < 0)
+ w += x;
+ if (y < 0)
+ h += y;
+
+ x = MAX(0, x);
+ y = MAX(0, y);
+
+ if (x + w > root_width)
+ w = root_width - x;
+ if (y + h > root_height)
+ h = root_height - y;
+
+ return gdk_pixbuf_get_from_window (root, x, y, w, h);
+}
+
+
+
static GdkPixbuf
*get_rectangle_screenshot_composited (gint delay)
{
GtkWidget *window;
RubberBandData rbdata;
- gboolean cancelled = FALSE;
GdkPixbuf *screenshot = NULL;
GdkWindow *root;
GdkDevice *pointer, *keyboard;
@@ -702,6 +808,9 @@ static GdkPixbuf
rbdata.left_pressed = FALSE;
rbdata.rubber_banding = FALSE;
rbdata.x = rbdata.y = 0;
+ rbdata.cancelled = FALSE;
+ rbdata.move_rectangle = FALSE;
+ rbdata.anchor = ANCHOR_UNSET;
/* Create the fullscreen window on which the rubber banding
* will be drawn. */
@@ -720,7 +829,9 @@ static GdkPixbuf
/* Connect to the interesting signals */
g_signal_connect (window, "key-press-event",
- G_CALLBACK (cb_key_pressed), &cancelled);
+ G_CALLBACK (cb_key_pressed), &rbdata);
+ g_signal_connect (window, "key-release-event",
+ G_CALLBACK (cb_key_released), &rbdata);
g_signal_connect (window, "draw",
G_CALLBACK (cb_draw), &rbdata);
g_signal_connect (window, "button-press-event",
@@ -789,19 +900,18 @@ static GdkPixbuf
g_object_unref (xhair_cursor);
gdk_flush();
- if (cancelled)
+ if (rbdata.cancelled)
goto cleanup;
/* Grab the screenshot on the main window */
root = gdk_get_default_root_window ();
- sleep(delay);
+ sleep (delay);
- screenshot = gdk_pixbuf_get_from_window (root,
- rbdata.rectangle_root.x,
- rbdata.rectangle_root.y,
- rbdata.rectangle.width,
- rbdata.rectangle.height);
+ screenshot = capture_rectangle_screenshot (rbdata.rectangle_root.x,
+ rbdata.rectangle_root.y,
+ rbdata.rectangle.width,
+ rbdata.rectangle.height);
cleanup:
/* Ungrab the mouse and the keyboard */
@@ -822,6 +932,7 @@ region_filter_func (GdkXEvent *xevent, GdkEvent *event, RbData *rbdata)
XIDeviceEvent *device_event;
Display *display;
Window root_window;
+ int key;
display = gdk_x11_get_default_xdisplay ();
root_window = gdk_x11_get_default_root_xwindow ();
@@ -842,6 +953,8 @@ region_filter_func (GdkXEvent *xevent, GdkEvent *event, RbData *rbdata)
rbdata->rectangle.width = 0;
rbdata->rectangle.height = 0;
rbdata->pressed = TRUE;
+ rbdata->move_rectangle = FALSE;
+ rbdata->anchor = ANCHOR_UNSET;
return GDK_FILTER_REMOVE;
break;
@@ -900,10 +1013,34 @@ region_filter_func (GdkXEvent *xevent, GdkEvent *event, RbData *rbdata)
x2 = device_event->root_x;
y2 = device_event->root_y;
- rbdata->rectangle.x = MIN (rbdata->x1, x2);
- rbdata->rectangle.y = MIN (rbdata->y1, y2);
- rbdata->rectangle.width = ABS (x2 - rbdata->x1);
- rbdata->rectangle.height = ABS (y2 - rbdata->y1);
+ if (rbdata->move_rectangle)
+ {
+ /* Define the anchor right after the control key is pressed */
+ if (rbdata->anchor == ANCHOR_UNSET)
+ {
+ rbdata->anchor = ANCHOR_NONE;
+ rbdata->anchor |= (x2 < rbdata->x1) ? ANCHOR_LEFT : 0;
+ rbdata->anchor |= (y2 < rbdata->y1) ? ANCHOR_TOP : 0;
+ }
+
+ /* Do not resize, instead move the rubber banding rectangle around */
+ if (rbdata->anchor & ANCHOR_LEFT)
+ rbdata->x1 = (rbdata->rectangle.x = x2) + rbdata->rectangle.width;
+ else
+ rbdata->x1 = rbdata->rectangle.x = x2 - rbdata->rectangle.width;
+
+ if (rbdata->anchor & ANCHOR_TOP)
+ rbdata->y1 = (rbdata->rectangle.y = y2) + rbdata->rectangle.height;
+ else
+ rbdata->y1 = rbdata->rectangle.y = y2 - rbdata->rectangle.height;
+ }
+ else
+ {
+ rbdata->rectangle.x = MIN (rbdata->x1, x2);
+ rbdata->rectangle.y = MIN (rbdata->y1, y2);
+ rbdata->rectangle.width = ABS (x2 - rbdata->x1);
+ rbdata->rectangle.height = ABS (y2 - rbdata->y1);
+ }
/* Draw the rectangle as the user drags the mouse */
TRACE ("Draw the new rectangle");
@@ -923,8 +1060,18 @@ region_filter_func (GdkXEvent *xevent, GdkEvent *event, RbData *rbdata)
case XI_KeyPress:
device_event = (XIDeviceEvent*) x_event->xcookie.data;
+ key = device_event->detail;
+
+ if (rbdata->pressed && (
+ key == XKeysymToKeycode (gdk_x11_get_default_xdisplay (), XK_Control_L) ||
+ key == XKeysymToKeycode (gdk_x11_get_default_xdisplay (), XK_Control_R)))
+ {
+ TRACE ("Control key was pressed, move the selection area.");
+ rbdata->move_rectangle = TRUE;
+ return GDK_FILTER_REMOVE;
+ }
- if (device_event->detail == XKeysymToKeycode (gdk_x11_get_default_xdisplay(), XK_Escape))
+ if (key == XKeysymToKeycode (gdk_x11_get_default_xdisplay (), XK_Escape))
{
TRACE ("Escape key was pressed, cancel the screenshot.");
@@ -951,6 +1098,21 @@ region_filter_func (GdkXEvent *xevent, GdkEvent *event, RbData *rbdata)
}
break;
+ case XI_KeyRelease:
+ device_event = (XIDeviceEvent*) x_event->xcookie.data;
+ key = device_event->detail;
+
+ if (rbdata->pressed && (
+ key == XKeysymToKeycode (gdk_x11_get_default_xdisplay (), XK_Control_L) ||
+ key == XKeysymToKeycode (gdk_x11_get_default_xdisplay (), XK_Control_R)))
+ {
+ TRACE ("Control key was released, resize the selection area.");
+ rbdata->move_rectangle = FALSE;
+ rbdata->anchor = ANCHOR_UNSET;
+ return GDK_FILTER_REMOVE;
+ }
+ break;
+
default:
break;
}
@@ -1078,12 +1240,10 @@ static GdkPixbuf
sleep(delay);
- screenshot =
- gdk_pixbuf_get_from_window (root_window,
- rbdata.rectangle.x,
- rbdata.rectangle.y,
- rbdata.rectangle.width,
- rbdata.rectangle.height);
+ screenshot = capture_rectangle_screenshot (rbdata.rectangle.x,
+ rbdata.rectangle.y,
+ rbdata.rectangle.width,
+ rbdata.rectangle.height);
}
if (G_LIKELY (gc != NULL))
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the Xfce4-commits
mailing list