diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index 5a4b1eac4..33b063047 100644 --- a/data/theme/gnome-shell.css +++ b/data/theme/gnome-shell.css @@ -1716,6 +1716,10 @@ StTooltip StLabel { background-color: rgba(0, 0, 0, 0.4); } +.flashspot { + background-color: white; +} + /* End Session Dialog */ .end-session-dialog { spacing: 42px; diff --git a/js/Makefile.am b/js/Makefile.am index 63c11a0dc..28d935274 100644 --- a/js/Makefile.am +++ b/js/Makefile.am @@ -35,6 +35,7 @@ nobase_dist_js_DATA = \ ui/endSessionDialog.js \ ui/environment.js \ ui/extensionSystem.js \ + ui/flashspot.js \ ui/iconGrid.js \ ui/keyboard.js \ ui/layout.js \ diff --git a/js/ui/flashspot.js b/js/ui/flashspot.js new file mode 100644 index 000000000..eabbac657 --- /dev/null +++ b/js/ui/flashspot.js @@ -0,0 +1,45 @@ +// -*- 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/shellDBus.js b/js/ui/shellDBus.js index ee8859492..63d91012d 100644 --- a/js/ui/shellDBus.js +++ b/js/ui/shellDBus.js @@ -6,6 +6,7 @@ const GLib = imports.gi.GLib; const Config = imports.misc.config; const ExtensionSystem = imports.ui.extensionSystem; +const Flashspot = imports.ui.flashspot; const Main = imports.ui.main; const GnomeShellIface = @@ -30,15 +31,18 @@ const GnomeShellIface = + + + @@ -109,6 +113,13 @@ const GnomeShell = new Lang.Class({ return [success, returnValue]; }, + _handleScreenshotFlash: function(flash, area) { + if (flash) { + let flashspot = new Flashspot.Flashspot(area); + flashspot.fire(); + } + }, + /** * ScreenshotArea: * @x: The X coordinate of the area @@ -123,12 +134,14 @@ const GnomeShell = new Lang.Class({ * */ ScreenshotAreaAsync : function (params, invocation) { - let [x, y, width, height, filename, callback] = params; - global.screenshot_area (x, y, width, height, filename, - function (obj, result) { + let [x, y, width, height, flash, filename, callback] = params; + global.screenshot_area (x, y, width, height, filename, Lang.bind(this, + function (obj, result, area) { + this._handleScreenshotFlash(flash, area); + let retval = GLib.Variant.new('(b)', [result]); invocation.return_value(retval); - }); + })); }, /** @@ -142,12 +155,14 @@ const GnomeShell = new Lang.Class({ * */ ScreenshotWindowAsync : function (params, invocation) { - let [include_frame, filename] = params; - global.screenshot_window (include_frame, filename, - function (obj, result) { + let [include_frame, flash, filename] = params; + global.screenshot_window (include_frame, filename, Lang.bind(this, + function (obj, result, area) { + this._handleScreenshotFlash(flash, area); + let retval = GLib.Variant.new('(b)', [result]); invocation.return_value(retval); - }); + })); }, /** @@ -160,12 +175,14 @@ const GnomeShell = new Lang.Class({ * */ ScreenshotAsync : function (params, invocation) { - let [filename] = params; - global.screenshot(filename, - function (obj, result) { + let [flash, filename] = params; + global.screenshot(filename, Lang.bind(this, + function (obj, result, area) { + this._handleScreenshotFlash(flash, area); + let retval = GLib.Variant.new('(b)', [result]); invocation.return_value(retval); - }); + })); }, ListExtensions: function() { diff --git a/src/shell-global-private.h b/src/shell-global-private.h index 5cb9d6aef..5f2faf845 100644 --- a/src/shell-global-private.h +++ b/src/shell-global-private.h @@ -25,12 +25,8 @@ typedef struct _screenshot_data { char *filename; - int x; - int y; - int width; - int height; - cairo_surface_t *image; + cairo_rectangle_int_t screenshot_area; ShellGlobalScreenshotCallback callback; } _screenshot_data; diff --git a/src/shell-global.c b/src/shell-global.c index c8f80147e..185564426 100644 --- a/src/shell-global.c +++ b/src/shell-global.c @@ -1967,7 +1967,9 @@ on_screenshot_written (GObject *source, { _screenshot_data *screenshot_data = (_screenshot_data*) user_data; if (screenshot_data->callback) - screenshot_data->callback (screenshot_data->global, g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result))); + screenshot_data->callback (screenshot_data->global, + g_simple_async_result_get_op_res_gboolean (G_SIMPLE_ASYNC_RESULT (result)), + &screenshot_data->screenshot_area); cairo_surface_destroy (screenshot_data->image); g_free (screenshot_data->filename); @@ -2045,6 +2047,11 @@ grab_screenshot (ClutterActor *stage, cairo_region_destroy (stage_region); } + screenshot_data->screenshot_area.x = 0; + screenshot_data->screenshot_area.y = 0; + screenshot_data->screenshot_area.width = width; + screenshot_data->screenshot_area.height = height; + g_signal_handlers_disconnect_by_func (stage, (void *)grab_screenshot, (gpointer)screenshot_data); result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, grab_screenshot); @@ -2059,12 +2066,15 @@ grab_area_screenshot (ClutterActor *stage, GSimpleAsyncResult *result; guchar *data; - screenshot_data->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, screenshot_data->width, screenshot_data->height); + screenshot_data->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + screenshot_data->screenshot_area.width, + screenshot_data->screenshot_area.height); data = cairo_image_surface_get_data (screenshot_data->image); cogl_flush(); - cogl_read_pixels (screenshot_data->x, screenshot_data->y, screenshot_data->width, screenshot_data->height, + cogl_read_pixels (screenshot_data->screenshot_area.x, screenshot_data->screenshot_area.y, + screenshot_data->screenshot_area.width, screenshot_data->screenshot_area.height, COGL_READ_PIXELS_COLOR_BUFFER, CLUTTER_CAIRO_FORMAT_ARGB32, data); cairo_surface_mark_dirty (screenshot_data->image); @@ -2088,8 +2098,8 @@ grab_area_screenshot (ClutterActor *stage, */ void shell_global_screenshot (ShellGlobal *global, - const char *filename, - ShellGlobalScreenshotCallback callback) + const char *filename, + ShellGlobalScreenshotCallback callback) { ClutterActor *stage; _screenshot_data *data = g_new0 (_screenshot_data, 1); @@ -2134,10 +2144,10 @@ shell_global_screenshot_area (ShellGlobal *global, data->global = global; data->filename = g_strdup (filename); - data->x = x; - data->y = y; - data->width = width; - data->height = height; + data->screenshot_area.x = x; + data->screenshot_area.y = y; + data->screenshot_area.width = width; + data->screenshot_area.height = height; data->callback = callback; stage = CLUTTER_ACTOR (meta_plugin_get_stage (global->plugin)); @@ -2176,6 +2186,7 @@ shell_global_screenshot_window (ShellGlobal *global, MetaDisplay *display = meta_screen_get_display (screen); MetaWindow *window = meta_display_get_focus_window (display); ClutterActor *window_actor; + gint width, height; screenshot_data->global = global; screenshot_data->filename = g_strdup (filename); @@ -2184,6 +2195,9 @@ shell_global_screenshot_window (ShellGlobal *global, window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window)); texture = clutter_texture_get_cogl_texture (CLUTTER_TEXTURE (meta_window_actor_get_texture (META_WINDOW_ACTOR (window_actor)))); + screenshot_data->screenshot_area.x = (gint) clutter_actor_get_x (window_actor); + screenshot_data->screenshot_area.y = (gint) clutter_actor_get_y (window_actor); + if (!include_frame) { MetaRectangle *window_rect = meta_window_get_rect (window); @@ -2196,11 +2210,23 @@ shell_global_screenshot_window (ShellGlobal *global, screenshot_data->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, window_rect->width, window_rect->height); + + screenshot_data->screenshot_area.x += window_rect->x; + screenshot_data->screenshot_area.y += window_rect->y; + screenshot_data->screenshot_area.width = window_rect->width; + screenshot_data->screenshot_area.height = window_rect->height; } else - screenshot_data->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, - clutter_actor_get_width (window_actor), - clutter_actor_get_height (window_actor)); + { + width = (gint) clutter_actor_get_width (window_actor); + height = (gint) clutter_actor_get_height (window_actor); + + screenshot_data->image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, + width, height); + + screenshot_data->screenshot_area.width = width; + screenshot_data->screenshot_area.height = height; + } data = cairo_image_surface_get_data (screenshot_data->image); diff --git a/src/shell-global.h b/src/shell-global.h index 4433025db..ba87f46ad 100644 --- a/src/shell-global.h +++ b/src/shell-global.h @@ -146,7 +146,9 @@ void shell_global_reexec_self (ShellGlobal *global); void shell_global_launch_calendar_server (ShellGlobal *global); -typedef void (*ShellGlobalScreenshotCallback) (ShellGlobal *global, gboolean success); +typedef void (*ShellGlobalScreenshotCallback) (ShellGlobal *global, + gboolean success, + cairo_rectangle_int_t *screenshot_area); void shell_global_screenshot_area (ShellGlobal *global, int x,