[gnome-shell] screenshot: move to a separate interface
- From: Cosimo Cecchi <cosimoc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] screenshot: move to a separate interface
- Date: Thu, 3 Jan 2013 11:58:05 +0000 (UTC)
commit 57bd43baf3734b7b0993781103e68893d5400387
Author: Cosimo Cecchi <cosimoc gnome org>
Date: Mon Dec 10 10:26:31 2012 -0500
screenshot: move to a separate interface
Since we're breaking API already, take this as an occasion to use a
separate interface for all the screenshot-related methods. The interface
name is org.gnome.Shell.Screenshot.
Internally, move all the related code to screenshot.js.
https://bugzilla.gnome.org/show_bug.cgi?id=688004
js/Makefile.am | 3 +-
js/ui/flashspot.js | 45 --------
js/ui/screenshot.js | 281 +++++++++++++++++++++++++++++++++++++++++++++++++++
js/ui/selectArea.js | 134 ------------------------
js/ui/shellDBus.js | 143 +--------------------------
5 files changed, 284 insertions(+), 322 deletions(-)
---
diff --git a/js/Makefile.am b/js/Makefile.am
index 7606f32..29187da 100644
--- a/js/Makefile.am
+++ b/js/Makefile.am
@@ -49,7 +49,6 @@ nobase_dist_js_DATA = \
ui/extensionSystem.js \
ui/extensionDownloader.js \
ui/environment.js \
- ui/flashspot.js \
ui/ibusCandidatePopup.js\
ui/grabHelper.js \
ui/iconGrid.js \
@@ -74,11 +73,11 @@ nobase_dist_js_DATA = \
ui/popupMenu.js \
ui/remoteSearch.js \
ui/runDialog.js \
+ ui/screenshot.js \
ui/screenShield.js \
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/screenshot.js b/js/ui/screenshot.js
new file mode 100644
index 0000000..12cf186
--- /dev/null
+++ b/js/ui/screenshot.js
@@ -0,0 +1,281 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const Clutter = imports.gi.Clutter;
+const Gdk = imports.gi.Gdk;
+const Gio = imports.gi.Gio;
+const GLib = imports.gi.GLib;
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+const Shell = imports.gi.Shell;
+const Signals = imports.signals;
+const St = imports.gi.St;
+
+const Lightbox = imports.ui.lightbox;
+const Main = imports.ui.main;
+const Tweener = imports.ui.tweener;
+
+const ScreenshotIface = <interface name="org.gnome.Shell.Screenshot">
+<method name="ScreenshotArea">
+ <arg type="i" direction="in" name="x"/>
+ <arg type="i" direction="in" name="y"/>
+ <arg type="i" direction="in" name="width"/>
+ <arg type="i" direction="in" name="height"/>
+ <arg type="b" direction="in" name="flash"/>
+ <arg type="s" direction="in" name="filename"/>
+ <arg type="b" direction="out" name="success"/>
+ <arg type="s" direction="out" name="filename_used"/>
+</method>
+<method name="ScreenshotWindow">
+ <arg type="b" direction="in" name="include_frame"/>
+ <arg type="b" direction="in" name="include_cursor"/>
+ <arg type="b" direction="in" name="flash"/>
+ <arg type="s" direction="in" name="filename"/>
+ <arg type="b" direction="out" name="success"/>
+ <arg type="s" direction="out" name="filename_used"/>
+</method>
+<method name="Screenshot">
+ <arg type="b" direction="in" name="include_cursor"/>
+ <arg type="b" direction="in" name="flash"/>
+ <arg type="s" direction="in" name="filename"/>
+ <arg type="b" direction="out" name="success"/>
+ <arg type="s" direction="out" name="filename_used"/>
+</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"/>
+ <arg type="i" direction="in" name="width"/>
+ <arg type="i" direction="in" name="height"/>
+</method>
+</interface>;
+
+const ScreenshotService = new Lang.Class({
+ Name: 'ScreenshotService',
+
+ _init: function() {
+ this._dbusImpl = Gio.DBusExportedObject.wrapJSObject(ScreenshotIface, this);
+ this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell/Screenshot');
+
+ Gio.DBus.session.own_name('org.gnome.Shell.Screenshot', Gio.BusNameOwnerFlags.REPLACE, null, null);
+ },
+
+ _onScreenshotComplete: function(obj, result, area, filenameUsed, flash, invocation) {
+ if (flash && result) {
+ let flashspot = new Flashspot(area);
+ flashspot.fire();
+ }
+
+ let retval = GLib.Variant.new('(bs)', [result, filenameUsed]);
+ invocation.return_value(retval);
+ },
+
+ ScreenshotAreaAsync : function (params, invocation) {
+ let [x, y, width, height, flash, filename, callback] = params;
+ let screenshot = new Shell.Screenshot();
+ screenshot.screenshot_area (x, y, width, height, filename,
+ Lang.bind(this, this._onScreenshotComplete,
+ flash, invocation));
+ },
+
+ ScreenshotWindowAsync : function (params, invocation) {
+ let [include_frame, include_cursor, flash, filename] = params;
+ let screenshot = new Shell.Screenshot();
+ screenshot.screenshot_window (include_frame, include_cursor, filename,
+ Lang.bind(this, this._onScreenshotComplete,
+ flash, invocation));
+ },
+
+ ScreenshotAsync : function (params, invocation) {
+ let [include_cursor, flash, filename] = params;
+ let screenshot = new Shell.Screenshot();
+ screenshot.screenshot(include_cursor, filename,
+ Lang.bind(this, this._onScreenshotComplete,
+ flash, invocation));
+ },
+
+ SelectAreaAsync: function (params, invocation) {
+ let selectArea = new 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({ x : x, y : y, width: width, height: height});
+ flashspot.fire();
+ }
+});
+
+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);
+
+const FLASHSPOT_ANIMATION_TIME = 0.25; // seconds
+
+const Flashspot = new Lang.Class({
+ Name: 'Flashspot',
+ Extends: Lightbox.Lightbox,
+
+ _init: function(area) {
+ this.parent(Main.uiGroup, { inhibitEvents: true,
+ width: area.width,
+ height: area.height });
+
+ this.actor.style_class = 'flashspot';
+ this.actor.set_position(area.x, area.y);
+ },
+
+ fire: function() {
+ this.actor.opacity = 0;
+ Tweener.addTween(this.actor,
+ { opacity: 255,
+ time: FLASHSPOT_ANIMATION_TIME,
+ transition: 'linear',
+ onComplete: Lang.bind(this, this._onFireShowComplete)
+ });
+ this.actor.show();
+ },
+
+ _onFireShowComplete: function() {
+ Tweener.addTween(this.actor,
+ { opacity: 0,
+ time: FLASHSPOT_ANIMATION_TIME,
+ transition: 'linear',
+ onComplete: Lang.bind(this, function() {
+ this.destroy();
+ })
+ });
+ }
+});
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
index f2d91a9..97ffe41 100644
--- a/js/ui/shellDBus.js
+++ b/js/ui/shellDBus.js
@@ -9,9 +9,8 @@ const Config = imports.misc.config;
const ExtensionSystem = imports.ui.extensionSystem;
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 Screenshot = imports.ui.screenshot;
const GnomeShellIface = <interface name="org.gnome.Shell">
<method name="Eval">
@@ -19,43 +18,6 @@ const GnomeShellIface = <interface name="org.gnome.Shell">
<arg type="b" direction="out" name="success" />
<arg type="s" direction="out" name="result" />
</method>
-<method name="ScreenshotArea">
- <arg type="i" direction="in" name="x"/>
- <arg type="i" direction="in" name="y"/>
- <arg type="i" direction="in" name="width"/>
- <arg type="i" direction="in" name="height"/>
- <arg type="b" direction="in" name="flash"/>
- <arg type="s" direction="in" name="filename"/>
- <arg type="b" direction="out" name="success"/>
- <arg type="s" direction="out" name="filename_used"/>
-</method>
-<method name="ScreenshotWindow">
- <arg type="b" direction="in" name="include_frame"/>
- <arg type="b" direction="in" name="include_cursor"/>
- <arg type="b" direction="in" name="flash"/>
- <arg type="s" direction="in" name="filename"/>
- <arg type="b" direction="out" name="success"/>
- <arg type="s" direction="out" name="filename_used"/>
-</method>
-<method name="Screenshot">
- <arg type="b" direction="in" name="include_cursor"/>
- <arg type="b" direction="in" name="flash"/>
- <arg type="s" direction="in" name="filename"/>
- <arg type="b" direction="out" name="success"/>
- <arg type="s" direction="out" name="filename_used"/>
-</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"/>
- <arg type="i" direction="in" name="width"/>
- <arg type="i" direction="in" name="height"/>
-</method>
<property name="Mode" type="s" access="read" />
<property name="OverviewActive" type="b" access="readwrite" />
<property name="ShellVersion" type="s" access="read" />
@@ -86,6 +48,7 @@ const GnomeShell = new Lang.Class({
this._dbusImpl.export(Gio.DBus.session, '/org/gnome/Shell');
this._extensionsSerivce = new GnomeShellExtensions();
+ this._screenshotService = new Screenshot.ScreenshotService();
},
/**
@@ -121,108 +84,6 @@ const GnomeShell = new Lang.Class({
return [success, returnValue];
},
- _onScreenshotComplete: function(obj, result, area, filenameUsed, flash, invocation) {
- if (flash && result) {
- let flashspot = new Flashspot.Flashspot(area);
- flashspot.fire();
- }
-
- let retval = GLib.Variant.new('(bs)', [result, filenameUsed]);
- invocation.return_value(retval);
- },
-
- /**
- * ScreenshotArea:
- * @x: The X coordinate of the area
- * @y: The Y coordinate of the area
- * @width: The width of the area
- * @height: The height of the area
- * @flash: Whether to flash the area or not
- * @filename: The filename for the screenshot
- *
- * Takes a screenshot of the passed in area and saves it
- * in @filename as png image, it returns a boolean
- * indicating whether the operation was successful or not.
- * @filename can either be an absolute path or a basename, in
- * which case the screenshot will be saved in the $XDG_PICTURES_DIR
- * or the home directory if it doesn't exist.
- *
- */
- ScreenshotAreaAsync : function (params, invocation) {
- let [x, y, width, height, flash, filename, callback] = params;
- let screenshot = new Shell.Screenshot();
- screenshot.screenshot_area (x, y, width, height, filename,
- Lang.bind(this, this._onScreenshotComplete,
- flash, invocation));
- },
-
- /**
- * ScreenshotWindow:
- * @include_frame: Whether to include the frame or not
- * @include_cursor: Whether to include the cursor image or not
- * @flash: Whether to flash the window area or not
- * @filename: The filename for the screenshot
- *
- * Takes a screenshot of the focused window (optionally omitting the frame)
- * and saves it in @filename as png image, it returns a boolean
- * indicating whether the operation was successful or not.
- * @filename can either be an absolute path or a basename, in
- * which case the screenshot will be saved in the $XDG_PICTURES_DIR
- * or the home directory if it doesn't exist.
- *
- */
- ScreenshotWindowAsync : function (params, invocation) {
- let [include_frame, include_cursor, flash, filename] = params;
- let screenshot = new Shell.Screenshot();
- screenshot.screenshot_window (include_frame, include_cursor, filename,
- Lang.bind(this, this._onScreenshotComplete,
- flash, invocation));
- },
-
- /**
- * Screenshot:
- * @filename: The filename for the screenshot
- * @include_cursor: Whether to include the cursor image or not
- * @flash: Whether to flash the screen or not
- *
- * Takes a screenshot of the whole screen and saves it
- * in @filename as png image, it returns a boolean
- * indicating whether the operation was successful or not.
- * @filename can either be an absolute path or a basename, in
- * which case the screenshot will be saved in the $XDG_PICTURES_DIR
- * or the home directory if it doesn't exist.
- *
- */
- ScreenshotAsync : function (params, invocation) {
- let [include_cursor, flash, filename] = params;
- let screenshot = new Shell.Screenshot();
- screenshot.screenshot(include_cursor, filename,
- Lang.bind(this, this._onScreenshotComplete,
- 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();
- },
-
Mode: global.session_mode,
get OverviewActive() {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]