[gnome-shell] Add a SelectArea() DBus method



commit dd19459e183d8bb99ac1f6ca230dd4834983031f
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Thu Nov 8 20:19:19 2012 -0500

    Add a SelectArea() DBus method
    
    This will be useful for e.g. selecting an area for a screenshot.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=687954

 js/Makefile.am      |    1 +
 js/ui/selectArea.js |  134 +++++++++++++++++++++++++++++++++++++++++++++++++++
 js/ui/shellDBus.js  |   24 +++++++++
 src/shell-global.c  |    6 ++
 src/shell-global.h  |    3 +-
 5 files changed, 167 insertions(+), 1 deletions(-)
---
diff --git a/js/Makefile.am b/js/Makefile.am
index d5d8047..7606f32 100644
--- a/js/Makefile.am
+++ b/js/Makefile.am
@@ -78,6 +78,7 @@ nobase_dist_js_DATA = 	\
 	ui/scripting.js		\
 	ui/search.js		\
 	ui/searchDisplay.js	\
+	ui/selectArea.js	\
 	ui/shellDBus.js		\
 	ui/status/accessibility.js	\
 	ui/status/keyboard.js	\
diff --git a/js/ui/selectArea.js b/js/ui/selectArea.js
new file mode 100644
index 0000000..b5bbdc7
--- /dev/null
+++ b/js/ui/selectArea.js
@@ -0,0 +1,134 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const Cairo = imports.cairo;
+const Clutter = imports.gi.Clutter;
+const Gdk = imports.gi.Gdk;
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+const Shell = imports.gi.Shell;
+const Signals = imports.signals;
+const St = imports.gi.St;
+
+const Main = imports.ui.main;
+const Tweener = imports.ui.tweener;
+
+const SelectArea = new Lang.Class({
+    Name: 'SelectArea',
+
+    _init: function() {
+        this._startX = -1;
+        this._startY = -1;
+        this._lastX = 0;
+        this._lastY = 0;
+
+        this._initRubberbandColors();
+
+        this._group = new St.Widget({ visible: false,
+                                      reactive: true,
+                                      x: 0,
+                                      y: 0 });
+        Main.uiGroup.add_actor(this._group);
+
+        this._group.connect('button-press-event',
+                            Lang.bind(this, this._onButtonPress));
+        this._group.connect('button-release-event',
+                            Lang.bind(this, this._onButtonRelease));
+        this._group.connect('key-press-event',
+                            Lang.bind(this, this._onKeyPress));
+        this._group.connect('motion-event',
+                            Lang.bind(this, this._onMotionEvent));
+
+        let constraint = new Clutter.BindConstraint({ source: global.stage,
+                                                      coordinate: Clutter.BindCoordinate.ALL });
+        this._group.add_constraint(constraint);
+
+        this._rubberband = new Clutter.Rectangle({ color: this._background,
+                                                   has_border: true,
+                                                   border_width: 1,
+                                                   border_color: this._border });
+        this._group.add_actor(this._rubberband);
+    },
+
+    show: function() {
+        if (!Main.pushModal(this._group) || this._group.visible)
+            return;
+
+        global.set_cursor(Shell.Cursor.CROSSHAIR);
+        this._group.visible = true;
+    },
+
+    _initRubberbandColors: function() {
+        function colorFromRGBA(rgba) {
+            return new Clutter.Color({ red: rgba.red * 255,
+                                       green: rgba.green * 255,
+                                       blue: rgba.blue * 255,
+                                       alpha: rgba.alpha * 255 });
+        }
+
+        let path = new Gtk.WidgetPath();
+        path.append_type(Gtk.IconView);
+
+        let context = new Gtk.StyleContext();
+        context.set_path(path);
+        context.add_class('rubberband');
+
+        this._background = colorFromRGBA(context.get_background_color(Gtk.StateFlags.NORMAL));
+        this._border = colorFromRGBA(context.get_border_color(Gtk.StateFlags.NORMAL));
+    },
+
+    _getGeometry: function() {
+        return { x: Math.min(this._startX, this._lastX),
+                 y: Math.min(this._startY, this._lastY),
+                 width: Math.abs(this._startX - this._lastX),
+                 height: Math.abs(this._startY - this._lastY) };
+    },
+
+    _onKeyPress: function(actor, event) {
+        if (event.get_key_symbol() == Clutter.Escape)
+            this._destroy(null, false);
+
+        return;
+    },
+
+    _onMotionEvent: function(actor, event) {
+        if (this._startX == -1 || this._startY == -1)
+            return false;
+
+        [this._lastX, this._lastY] = event.get_coords();
+        let geometry = this._getGeometry();
+
+        this._rubberband.set_position(geometry.x, geometry.y);
+        this._rubberband.set_size(geometry.width, geometry.height);
+
+        return false;
+    },
+
+    _onButtonPress: function(actor, event) {
+        [this._startX, this._startY] = event.get_coords();
+        this._rubberband.set_position(this._startX, this._startY);
+
+        return false;
+    },
+
+    _onButtonRelease: function(actor, event) {
+        this._destroy(this._getGeometry(), true);
+        return false;
+    },
+
+    _destroy: function(geometry, fade) {
+        Tweener.addTween(this._group,
+                         { opacity: 0,
+                           time: fade ? 0.2 : 0,
+                           transition: 'easeOutQuad',
+                           onComplete: Lang.bind(this,
+                               function() {
+                                   Main.popModal(this._group);
+                                   this._group.destroy();
+                                   global.unset_cursor();
+
+                                   this.emit('finished', geometry);
+                               })
+                         });
+    }
+});
+Signals.addSignalMethods(SelectArea.prototype);
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
index 6b88baf..1eba296 100644
--- a/js/ui/shellDBus.js
+++ b/js/ui/shellDBus.js
@@ -11,6 +11,7 @@ const ExtensionDownloader = imports.ui.extensionDownloader;
 const ExtensionUtils = imports.misc.extensionUtils;
 const Flashspot = imports.ui.flashspot;
 const Main = imports.ui.main;
+const SelectArea = imports.ui.selectArea;
 
 const GnomeShellIface = <interface name="org.gnome.Shell">
 <method name="Eval">
@@ -40,6 +41,12 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
     <arg type="s" direction="in" name="filename"/>
     <arg type="b" direction="out" name="success"/>
 </method>
+<method name="SelectArea">
+    <arg type="i" direction="out" name="x"/>
+    <arg type="i" direction="out" name="y"/>
+    <arg type="i" direction="out" name="width"/>
+    <arg type="i" direction="out" name="height"/>
+</method>
 <method name="FlashArea">
     <arg type="i" direction="in" name="x"/>
     <arg type="i" direction="in" name="y"/>
@@ -182,6 +189,23 @@ const GnomeShell = new Lang.Class({
                                     flash, invocation));
     },
 
+    SelectAreaAsync: function (params, invocation) {
+        let selectArea = new SelectArea.SelectArea();
+        selectArea.show();
+        selectArea.connect('finished', Lang.bind(this,
+            function(selectArea, areaRectangle) {
+                if (areaRectangle) {
+                    let retval = GLib.Variant.new('(iiii)',
+                        [areaRectangle.x, areaRectangle.y,
+                         areaRectangle.width, areaRectangle.height]);
+                    invocation.return_value(retval);
+                } else {
+                    invocation.return_error_literal(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED,
+                        "Operation was cancelled");
+                }
+            }));
+    },
+
     FlashArea: function(x, y, width, height) {
         let flashspot = new Flashspot.Flashspot({ x : x, y : y, width: width, height: height});
         flashspot.fire();
diff --git a/src/shell-global.c b/src/shell-global.c
index b7198a9..10b1fc1 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -616,6 +616,9 @@ shell_global_set_cursor (ShellGlobal *global,
     case SHELL_CURSOR_POINTING_HAND:
       name = "hand";
       break;
+    case SHELL_CURSOR_CROSSHAIR:
+      name = "crosshair";
+      break;
     default:
       g_return_if_reached ();
     }
@@ -638,6 +641,9 @@ shell_global_set_cursor (ShellGlobal *global,
         case SHELL_CURSOR_POINTING_HAND:
           cursor_type = GDK_HAND2;
           break;
+        case SHELL_CURSOR_CROSSHAIR:
+          cursor_type = GDK_CROSSHAIR;
+          break;
         case SHELL_CURSOR_DND_UNSUPPORTED_TARGET:
           cursor_type = GDK_X_CURSOR;
           break;
diff --git a/src/shell-global.h b/src/shell-global.h
index 95c18e0..7c14892 100644
--- a/src/shell-global.h
+++ b/src/shell-global.h
@@ -63,7 +63,8 @@ typedef enum {
   SHELL_CURSOR_DND_UNSUPPORTED_TARGET,
   SHELL_CURSOR_DND_MOVE,
   SHELL_CURSOR_DND_COPY,
-  SHELL_CURSOR_POINTING_HAND
+  SHELL_CURSOR_POINTING_HAND,
+  SHELL_CURSOR_CROSSHAIR
 } ShellCursor;
 
 void    shell_global_set_cursor              (ShellGlobal         *global,



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