diff --git a/js/Makefile.am b/js/Makefile.am index 7606f32b1..29187da2e 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/flashspot.js b/js/ui/flashspot.js deleted file mode 100644 index eabbac657..000000000 --- a/js/ui/flashspot.js +++ /dev/null @@ -1,45 +0,0 @@ -// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- - -const Lang = imports.lang; - -const Lightbox = imports.ui.lightbox; -const Main = imports.ui.main; -const Tweener = imports.ui.tweener; - -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/screenshot.js b/js/ui/screenshot.js new file mode 100644 index 000000000..12cf18642 --- /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 = + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +; + +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/selectArea.js b/js/ui/selectArea.js deleted file mode 100644 index b5bbdc74d..000000000 --- a/js/ui/selectArea.js +++ /dev/null @@ -1,134 +0,0 @@ -// -*- 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 f2d91a9ab..97ffe4104 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 = @@ -19,43 +18,6 @@ const GnomeShellIface = - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -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() {