[gnome-flashback] screenshot: implement SelectArea method



commit b3891973ee235392af585e02e42e565f411349d1
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Sun Aug 23 10:52:52 2015 +0300

    screenshot: implement SelectArea method
    
    https://bugzilla.gnome.org/show_bug.cgi?id=753529

 gnome-flashback/libscreenshot/Makefile.am          |    2 +
 .../libscreenshot/flashback-screenshot.c           |   27 ++-
 .../libscreenshot/flashback-select-area.c          |  341 ++++++++++++++++++++
 .../libscreenshot/flashback-select-area.h          |   39 +++
 4 files changed, 406 insertions(+), 3 deletions(-)
---
diff --git a/gnome-flashback/libscreenshot/Makefile.am b/gnome-flashback/libscreenshot/Makefile.am
index 1fa9bec..1d97423 100644
--- a/gnome-flashback/libscreenshot/Makefile.am
+++ b/gnome-flashback/libscreenshot/Makefile.am
@@ -16,6 +16,8 @@ libscreenshot_la_SOURCES = \
        flashback-dbus-screenshot.h \
        flashback-screenshot.c \
        flashback-screenshot.h \
+       flashback-select-area.c \
+       flashback-select-area.h \
        $(NULL)
 
 libscreenshot_la_LDFLAGS = \
diff --git a/gnome-flashback/libscreenshot/flashback-screenshot.c 
b/gnome-flashback/libscreenshot/flashback-screenshot.c
index 03e3471..20a2b15 100644
--- a/gnome-flashback/libscreenshot/flashback-screenshot.c
+++ b/gnome-flashback/libscreenshot/flashback-screenshot.c
@@ -21,6 +21,7 @@
 
 #include "flashback-dbus-screenshot.h"
 #include "flashback-screenshot.h"
+#include "flashback-select-area.h"
 
 #define SCREENSHOT_DBUS_NAME "org.gnome.Shell.Screenshot"
 #define SCREENSHOT_DBUS_PATH "/org/gnome/Shell/Screenshot"
@@ -104,9 +105,29 @@ handle_select_area (FlashbackDBusScreenshot *dbus_screenshot,
                     GDBusMethodInvocation   *invocation,
                     gpointer                 user_data)
 {
-  g_warning ("screenshot: select-area");
-  flashback_dbus_screenshot_complete_select_area (dbus_screenshot, invocation,
-                                                  0, 0, 0, 0);
+  FlashbackSelectArea *select_area;
+  gint x;
+  gint y;
+  gint width;
+  gint height;
+
+  select_area = flashback_select_area_new ();
+  x = y = width = height = 0;
+
+  if (flashback_select_area_select (select_area, &x, &y, &width, &height))
+    {
+      flashback_dbus_screenshot_complete_select_area (dbus_screenshot,
+                                                      invocation,
+                                                      x, y, width, height);
+    }
+  else
+    {
+      g_dbus_method_invocation_return_error (invocation, G_IO_ERROR,
+                                             G_IO_ERROR_CANCELLED,
+                                             "Operation was cancelled");
+    }
+
+  g_object_unref (select_area);
 
   return TRUE;
 }
diff --git a/gnome-flashback/libscreenshot/flashback-select-area.c 
b/gnome-flashback/libscreenshot/flashback-select-area.c
new file mode 100644
index 0000000..dc7bb1e
--- /dev/null
+++ b/gnome-flashback/libscreenshot/flashback-select-area.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Based on code in gnome-screenshot:
+ * https://git.gnome.org/browse/gnome-screenshot/tree/src/screenshot-area-selection.c
+ * Copyright (C) 2001 - 2006 Jonathan Blandford, 2008 Cosimo Cecchi
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+
+#include "flashback-select-area.h"
+
+struct _FlashbackSelectArea
+{
+  GObject    parent;
+
+  GtkWidget *window;
+  gboolean   composited;
+
+  gboolean   selecting;
+  gboolean   selected;
+
+  gint       x;
+  gint       y;
+  gint       width;
+  gint       height;
+};
+
+G_DEFINE_TYPE (FlashbackSelectArea, flashback_select_area, G_TYPE_OBJECT)
+
+static gboolean
+draw_cb (GtkWidget *widget,
+         cairo_t   *cr,
+         gpointer   user_data)
+{
+  FlashbackSelectArea *select_area;
+  GtkStyleContext *context;
+  gint width;
+  gint height;
+
+  select_area = FLASHBACK_SELECT_AREA (user_data);
+
+  if (select_area->composited == FALSE)
+    return TRUE;
+
+  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+  cairo_set_source_rgba (cr, 0, 0, 0, 0);
+  cairo_paint (cr);
+
+  context = gtk_widget_get_style_context (widget);
+  width = gtk_widget_get_allocated_width (widget);
+  height = gtk_widget_get_allocated_height (widget);
+
+  gtk_style_context_save (context);
+  gtk_style_context_add_class (context, GTK_STYLE_CLASS_RUBBERBAND);
+
+  gtk_render_background (context, cr, 0, 0, width, height);
+  gtk_render_frame (context, cr, 0, 0, width, height);
+
+  gtk_style_context_restore (context);
+
+  return TRUE;
+}
+
+static gboolean
+key_press_event_cb (GtkWidget   *widget,
+                    GdkEventKey *event,
+                    gpointer     user_data)
+{
+  if (event->keyval == GDK_KEY_Escape)
+    gtk_main_quit ();
+
+  return TRUE;
+}
+
+static gboolean
+button_press_event_cb (GtkWidget      *widget,
+                       GdkEventButton *event,
+                       gpointer        user_data)
+{
+  FlashbackSelectArea *select_area;
+
+  select_area = FLASHBACK_SELECT_AREA (user_data);
+
+  if (select_area->selecting)
+    return TRUE;
+
+  select_area->selecting = TRUE;
+  select_area->x = event->x_root;
+  select_area->y = event->y_root;
+
+  return TRUE;
+}
+
+static gboolean
+button_release_event_cb (GtkWidget      *widget,
+                         GdkEventButton *event,
+                         gpointer        user_data)
+{
+  FlashbackSelectArea *select_area;
+
+  select_area = FLASHBACK_SELECT_AREA (user_data);
+
+  select_area->width = ABS (select_area->x - event->x_root);
+  select_area->height = ABS (select_area->y - event->y_root);
+  select_area->x = MIN (select_area->x, event->x_root);
+  select_area->y = MIN (select_area->y, event->y_root);
+
+  if (select_area->width != 0 && select_area->height != 0)
+    select_area->selected = TRUE;
+
+  gtk_main_quit ();
+
+  return TRUE;
+}
+
+static gboolean
+motion_notify_event_cb (GtkWidget      *widget,
+                        GdkEventMotion *event,
+                        gpointer        user_data)
+{
+  FlashbackSelectArea *select_area;
+  gint x;
+  gint y;
+  gint width;
+  gint height;
+  GtkWindow *window;
+
+  select_area = FLASHBACK_SELECT_AREA (user_data);
+
+  if (select_area->selecting == FALSE)
+    return TRUE;
+
+  x = MIN (select_area->x, event->x_root);
+  y = MIN (select_area->y, event->y_root);
+  width = ABS (select_area->x - event->x_root);
+  height = ABS (select_area->y - event->y_root);
+
+  window = GTK_WINDOW (select_area->window);
+
+  if (width <= 0 || height <= 0)
+    {
+      gtk_window_move (window, -100, -100);
+      gtk_window_resize (window, 10, 10);
+
+      return TRUE;
+    }
+
+  gtk_window_move (window, x, y);
+  gtk_window_resize (window, width, height);
+
+  if (select_area->composited == FALSE)
+    {
+      GdkWindow *gdk_window;
+
+      gdk_window = gtk_widget_get_window (select_area->window);
+
+      if (width > 2 && height > 2)
+        {
+          cairo_region_t *region;
+          cairo_rectangle_int_t rectangle;
+
+          rectangle.x = x;
+          rectangle.y = y;
+          rectangle.width = width;
+          rectangle.height = height;
+
+          region = cairo_region_create_rectangle (&rectangle);
+
+          rectangle.x++;
+          rectangle.y++;
+          rectangle.width -= 2;
+          rectangle.height -= 2;
+
+          cairo_region_subtract_rectangle (region, &rectangle);
+
+          gdk_window_shape_combine_region (gdk_window, region, 0, 0);
+          cairo_region_destroy (region);
+        }
+      else
+        {
+          gdk_window_shape_combine_region (gdk_window, NULL, 0, 0);
+        }
+    }
+
+  return TRUE;
+}
+
+static void
+setup_window (FlashbackSelectArea *select_area)
+{
+  GdkScreen *screen;
+  GdkVisual *visual;
+  GtkWindow *window;
+
+  screen = gdk_screen_get_default ();
+  visual = gdk_screen_get_rgba_visual (screen);
+
+  if (gdk_screen_is_composited (screen) && visual != NULL)
+    {
+      gtk_widget_set_visual (select_area->window, visual);
+      select_area->composited = TRUE;
+    }
+
+  g_signal_connect (select_area->window, "draw",
+                    G_CALLBACK (draw_cb), select_area);
+  g_signal_connect (select_area->window, "key-press-event",
+                    G_CALLBACK (key_press_event_cb), select_area);
+  g_signal_connect (select_area->window, "button-press-event",
+                    G_CALLBACK (button_press_event_cb), select_area);
+  g_signal_connect (select_area->window, "button-release-event",
+                    G_CALLBACK (button_release_event_cb), select_area);
+  g_signal_connect (select_area->window, "motion-notify-event",
+                    G_CALLBACK (motion_notify_event_cb), select_area);
+
+  window = GTK_WINDOW (select_area->window);
+
+  gtk_window_move (window, -100, -100);
+  gtk_window_resize (window, 10, 10);
+  gtk_widget_show (select_area->window);
+}
+
+static void
+flashback_select_area_dispose (GObject *object)
+{
+  FlashbackSelectArea *select_area;
+
+  select_area = FLASHBACK_SELECT_AREA (object);
+
+  if (select_area->window != NULL)
+    {
+      gtk_widget_destroy (select_area->window);
+      select_area->window = NULL;
+    }
+
+  G_OBJECT_CLASS (flashback_select_area_parent_class)->dispose (object);
+}
+
+static void
+flashback_select_area_class_init (FlashbackSelectAreaClass *select_area_class)
+{
+  GObjectClass *object_class;
+
+  object_class = G_OBJECT_CLASS (select_area_class);
+
+  object_class->dispose = flashback_select_area_dispose;
+}
+
+static void
+flashback_select_area_init (FlashbackSelectArea *select_area)
+{
+  select_area->window = gtk_window_new (GTK_WINDOW_POPUP);
+}
+
+FlashbackSelectArea *
+flashback_select_area_new (void)
+{
+  return g_object_new (FLASHBACK_TYPE_SELECT_AREA, NULL);
+}
+
+gboolean
+flashback_select_area_select (FlashbackSelectArea *select_area,
+                              gint                *x,
+                              gint                *y,
+                              gint                *width,
+                              gint                *height)
+{
+  GdkDisplay *display;
+  GdkCursor *cursor;
+  GdkDeviceManager *manager;
+  GdkDevice *pointer;
+  GdkDevice *keyboard;
+  GdkWindow *window;
+  GdkGrabStatus status;
+
+  *x = *y = *width = *height = 0;
+
+  setup_window (select_area);
+
+  display = gdk_display_get_default ();
+  cursor = gdk_cursor_new_for_display (display, GDK_CROSSHAIR);
+  manager = gdk_display_get_device_manager (display);
+  pointer = gdk_device_manager_get_client_pointer (manager);
+  keyboard = gdk_device_get_associated_device (pointer);
+  window = gtk_widget_get_window (select_area->window);
+
+  status = gdk_device_grab (pointer, window, GDK_OWNERSHIP_NONE, FALSE,
+                            GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK |
+                            GDK_BUTTON_RELEASE_MASK,
+                            cursor, GDK_CURRENT_TIME);
+
+  if (status != GDK_GRAB_SUCCESS)
+    {
+      g_object_unref (cursor);
+      return FALSE;
+    }
+
+  if (gdk_display_device_is_grabbed (display, keyboard))
+    gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
+
+  status = gdk_device_grab (keyboard, window, GDK_OWNERSHIP_NONE, FALSE,
+                            GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK,
+                            NULL, GDK_CURRENT_TIME);
+
+  if (status != GDK_GRAB_SUCCESS)
+    {
+      gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
+      g_object_unref (cursor);
+      return FALSE;
+    }
+
+  gtk_main ();
+
+  gdk_device_ungrab (pointer, GDK_CURRENT_TIME);
+  gdk_device_ungrab (keyboard, GDK_CURRENT_TIME);
+
+  if (select_area->selected == FALSE)
+    return FALSE;
+
+  *x = select_area->x;
+  *y = select_area->y;
+  *width = select_area->width;
+  *height = select_area->height;
+
+  return TRUE;
+}
diff --git a/gnome-flashback/libscreenshot/flashback-select-area.h 
b/gnome-flashback/libscreenshot/flashback-select-area.h
new file mode 100644
index 0000000..40669a2
--- /dev/null
+++ b/gnome-flashback/libscreenshot/flashback-select-area.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 Alberts Muktupāvels
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FLASHBACK_SELECT_AREA_H
+#define FLASHBACK_SELECT_AREA_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define FLASHBACK_TYPE_SELECT_AREA flashback_select_area_get_type ()
+G_DECLARE_FINAL_TYPE (FlashbackSelectArea, flashback_select_area,
+                      FLASHBACK, SELECT_AREA, GObject)
+
+FlashbackSelectArea *flashback_select_area_new    (void);
+
+gboolean             flashback_select_area_select (FlashbackSelectArea *select_area,
+                                                   gint                *x,
+                                                   gint                *y,
+                                                   gint                *width,
+                                                   gint                *height);
+
+G_END_DECLS
+
+#endif


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]