[gnome-shell] Add screenshot interface
- From: Adel Gadllah <agadllah src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] Add screenshot interface
- Date: Wed, 24 Aug 2011 14:07:10 +0000 (UTC)
commit b7fd78b254d4e238d60df70fb790820f5dc68987
Author: Adel Gadllah <adel gadllah gmail com>
Date: Wed Aug 24 16:06:13 2011 +0200
Add screenshot interface
Adds methods to shell_global to allow taking screenshots
save the result into a specified png image.
It exposes three methods via shellDBus applications like
gnome-screenshot:
*) Screenshot (screenshots the whole screen)
*) ScreenshotWindow (screenshots the focused window)
*) ScreenshotArea (screenshots a specific area)
https://bugzilla.gnome.org/show_bug.cgi?id=652952
js/ui/shellDBus.js | 56 +++++++++++
src/shell-global-private.h | 15 +++
src/shell-global.c | 229 ++++++++++++++++++++++++++++++++++++++++++++
src/shell-global.h | 19 ++++
4 files changed, 319 insertions(+), 0 deletions(-)
---
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
index 78cd8a0..03adae9 100644
--- a/js/ui/shellDBus.js
+++ b/js/ui/shellDBus.js
@@ -23,6 +23,18 @@ const GnomeShellIface = {
{ name: 'GetExtensionErrors',
inSignature: 's',
outSignature: 'as'
+ },
+ { name: 'ScreenshotArea',
+ inSignature: 'iiiis',
+ outSignature: 'b'
+ },
+ { name: 'ScreenshotWindow',
+ inSignature: 'bs',
+ outSignature: 'b'
+ },
+ { name: 'Screenshot',
+ inSignature: 's',
+ outSignature: 'b'
}
],
signals: [],
@@ -76,6 +88,50 @@ GnomeShell.prototype = {
return [success, returnValue];
},
+ /**
+ * 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
+ * @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.
+ *
+ */
+ ScreenshotAreaAsync : function (x, y, width, height, filename, callback) {
+ global.screenshot_area (x, y, width, height, filename, function (obj, result) { callback(result); });
+ },
+
+ /**
+ * ScreenshotWindow:
+ * @include_frame: Whether to include the frame 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.
+ *
+ */
+ ScreenshotWindow : function (include_frame, filename) {
+ return global.screenshot_window (include_frame, filename);
+ },
+
+ /**
+ * Screenshot:
+ * @filename: The filename for the screenshot
+ *
+ * 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.
+ *
+ */
+ ScreenshotAsync : function (filename, callback) {
+ global.screenshot(filename, function (obj, result) { callback(result); });
+ },
+
ListExtensions: function() {
return ExtensionSystem.extensionMeta;
},
diff --git a/src/shell-global-private.h b/src/shell-global-private.h
index 5512645..2dd698f 100644
--- a/src/shell-global-private.h
+++ b/src/shell-global-private.h
@@ -13,4 +13,19 @@ GjsContext *_shell_global_get_gjs_context (ShellGlobal *global);
gboolean _shell_global_check_xdnd_event (ShellGlobal *global,
XEvent *xev);
+
+/* Used for async screenshot grabbing */
+typedef struct _screenshot_data {
+ ShellGlobal *global;
+
+ char *filename;
+
+ int x;
+ int y;
+ int width;
+ int height;
+
+ ShellGlobalScreenshotCallback callback;
+} _screenshot_data;
+
#endif /* __SHELL_GLOBAL_PRIVATE_H__ */
diff --git a/src/shell-global.c b/src/shell-global.c
index c18d474..07a51a2 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -1628,3 +1628,232 @@ shell_global_launch_calendar_server (ShellGlobal *global)
g_free (calendar_server_exe);
}
+
+static void
+grab_screenshot (ClutterActor *stage,
+ _screenshot_data *screenshot_data)
+{
+ MetaScreen *screen = shell_global_get_screen (screenshot_data->global);
+ cairo_status_t status;
+ cairo_surface_t *image;
+ guchar *data;
+ int width, height;
+
+ meta_plugin_query_screen_size (screenshot_data->global->plugin, &width, &height);
+ image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+ data = cairo_image_surface_get_data (image);
+
+ cogl_flush();
+
+ cogl_read_pixels (0, 0, width, height, COGL_READ_PIXELS_COLOR_BUFFER, CLUTTER_CAIRO_FORMAT_ARGB32, data);
+
+ cairo_surface_mark_dirty (image);
+
+ if (meta_screen_get_n_monitors (screen) > 1)
+ {
+ cairo_region_t *screen_region = cairo_region_create ();
+ cairo_region_t *stage_region;
+ MetaRectangle monitor_rect;
+ cairo_rectangle_int_t stage_rect;
+ int i;
+ cairo_t *cr;
+
+ for (i = meta_screen_get_n_monitors (screen) - 1; i >= 0; i--)
+ {
+ meta_screen_get_monitor_geometry (screen, i, &monitor_rect);
+ cairo_region_union_rectangle (screen_region, (const cairo_rectangle_int_t *) &monitor_rect);
+ }
+
+ stage_rect.x = 0;
+ stage_rect.y = 0;
+ stage_rect.width = width;
+ stage_rect.height = height;
+
+ stage_region = cairo_region_create_rectangle ((const cairo_rectangle_int_t *) &stage_rect);
+ cairo_region_xor (stage_region, screen_region);
+ cairo_region_destroy (screen_region);
+
+ cr = cairo_create (image);
+
+ for (i = 0; i < cairo_region_num_rectangles (stage_region); i++)
+ {
+ cairo_rectangle_int_t rect;
+ cairo_region_get_rectangle (stage_region, i, &rect);
+ cairo_rectangle (cr, (double) rect.x, (double) rect.y, (double) rect.width, (double) rect.height);
+ cairo_fill (cr);
+ }
+
+ cairo_destroy (cr);
+ cairo_region_destroy (stage_region);
+ }
+
+
+ status = cairo_surface_write_to_png (image, screenshot_data->filename);
+ cairo_surface_destroy (image);
+
+ if (screenshot_data->callback)
+ screenshot_data->callback (screenshot_data->global, status == CAIRO_STATUS_SUCCESS);
+
+ g_signal_handlers_disconnect_by_func (stage, (void *)grab_screenshot, (gpointer)screenshot_data);
+ g_free (screenshot_data->filename);
+ g_free (screenshot_data);
+}
+
+static void
+grab_area_screenshot (ClutterActor *stage,
+ _screenshot_data *screenshot_data)
+{
+ cairo_status_t status;
+ cairo_surface_t *image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, screenshot_data->width, screenshot_data->height);
+ guchar *data = cairo_image_surface_get_data (image);
+
+ cogl_flush();
+
+ cogl_read_pixels (screenshot_data->x, screenshot_data->y, screenshot_data->width, screenshot_data->height,
+ COGL_READ_PIXELS_COLOR_BUFFER, CLUTTER_CAIRO_FORMAT_ARGB32, data);
+
+ cairo_surface_mark_dirty (image);
+ status = cairo_surface_write_to_png (image, screenshot_data->filename);
+ cairo_surface_destroy (image);
+
+ if (screenshot_data->callback)
+ screenshot_data->callback (screenshot_data->global, status == CAIRO_STATUS_SUCCESS);
+
+ g_signal_handlers_disconnect_by_func (stage, (void *)grab_area_screenshot, (gpointer)screenshot_data);
+ g_free (screenshot_data->filename);
+ g_free (screenshot_data);
+}
+
+/**
+ * shell_global_screenshot:
+ * @global: the #ShellGlobal
+ * @filename: The filename for the screenshot
+ * @callback: (scope async): function to call returning success or failure
+ * of the async grabbing
+ *
+ * Takes a screenshot of the whole screen
+ * in @filename as png image.
+ *
+ */
+void
+shell_global_screenshot (ShellGlobal *global,
+ const char *filename,
+ ShellGlobalScreenshotCallback callback)
+{
+ ClutterActor *stage;
+ _screenshot_data *data = g_new0 (_screenshot_data, 1);
+
+ data->global = global;
+ data->filename = g_strdup (filename);
+ data->callback = callback;
+
+ stage = CLUTTER_ACTOR (meta_plugin_get_stage (global->plugin));
+
+ g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), (gpointer)data);
+
+ clutter_actor_queue_redraw (stage);
+}
+
+/**
+ * shell_global_screenshot_area:
+ * @global: the #ShellGlobal
+ * @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
+ * @filename: The filename for the screenshot
+ * @callback: (scope async): function to call returning success or failure
+ * of the async grabbing
+ *
+ * Takes a screenshot of the passed in area and saves it
+ * in @filename as png image.
+ *
+ */
+void
+shell_global_screenshot_area (ShellGlobal *global,
+ int x,
+ int y,
+ int width,
+ int height,
+ const char *filename,
+ ShellGlobalScreenshotCallback callback)
+{
+ ClutterActor *stage;
+ _screenshot_data *data = g_new0 (_screenshot_data, 1);
+
+ data->global = global;
+ data->filename = g_strdup (filename);
+ data->x = x;
+ data->y = y;
+ data->width = width;
+ data->height = height;
+ data->callback = callback;
+
+ stage = CLUTTER_ACTOR (meta_plugin_get_stage (global->plugin));
+
+ g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), (gpointer)data);
+
+ clutter_actor_queue_redraw (stage);
+}
+
+/**
+ * shell_global_screenshot_window:
+ * @global: the #ShellGlobal
+ * @include_frame: Whether to include the frame or not
+ *
+ * @filename: The filename for the screenshot
+ *
+ * Takes a screenshot of the focused window (optionally omitting the frame)
+ * in @filename as png image.
+ *
+ * Return value: success or failure.
+ */
+gboolean
+shell_global_screenshot_window (ShellGlobal *global,
+ gboolean include_frame,
+ const char *filename)
+{
+ CoglHandle texture;
+ cairo_surface_t *image;
+ guchar *data;
+
+ MetaScreen *screen = meta_plugin_get_screen (global->plugin);
+ MetaDisplay *display = meta_screen_get_display (screen);
+ MetaWindow *window = meta_display_get_focus_window (display);
+ ClutterActor *window_actor;
+
+ cairo_status_t status;
+
+ 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))));
+
+ if (!include_frame)
+ {
+ MetaRectangle *window_rect = meta_window_get_rect (window);
+ texture = cogl_texture_new_from_sub_texture (texture,
+ window_rect->x,
+ window_rect->y,
+ window_rect->width,
+ window_rect->height);
+
+ image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ window_rect->width,
+ window_rect->height);
+ }
+ else
+ image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+ clutter_actor_get_width (window_actor),
+ clutter_actor_get_height (window_actor));
+
+ data = cairo_image_surface_get_data (image);
+
+ cogl_flush();
+
+ cogl_texture_get_data (texture, CLUTTER_CAIRO_FORMAT_ARGB32, 0, data);
+
+ cairo_surface_mark_dirty (image);
+ status = cairo_surface_write_to_png (image, filename);
+ cairo_surface_destroy (image);
+
+ return status == CAIRO_STATUS_SUCCESS;
+}
diff --git a/src/shell-global.h b/src/shell-global.h
index d5bca83..aa1941a 100644
--- a/src/shell-global.h
+++ b/src/shell-global.h
@@ -142,6 +142,25 @@ void shell_global_reexec_self (ShellGlobal *global);
void shell_global_launch_calendar_server (ShellGlobal *global);
+
+typedef void (*ShellGlobalScreenshotCallback) (ShellGlobal *global, gboolean success);
+
+void shell_global_screenshot_area (ShellGlobal *global,
+ int x,
+ int y,
+ int width,
+ int height,
+ const char *filename,
+ ShellGlobalScreenshotCallback callback);
+
+gboolean shell_global_screenshot_window (ShellGlobal *global,
+ gboolean include_frame,
+ const char *filename);
+
+void shell_global_screenshot (ShellGlobal *global,
+ const char *filename,
+ ShellGlobalScreenshotCallback callback);
+
G_END_DECLS
#endif /* __SHELL_GLOBAL_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]