[gnome-shell] screenshot: Split into separate file / class
- From: Adel Gadllah <agadllah src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] screenshot: Split into separate file / class
- Date: Tue, 14 Feb 2012 20:08:53 +0000 (UTC)
commit 4516e4cc3bd9a7ea1b79a9d3d4e3ba6fa2a1127b
Author: Adel Gadllah <adel gadllah gmail com>
Date: Tue Feb 14 20:33:56 2012 +0100
screenshot: Split into separate file / class
Split the screenshot functionality from ShellGlobal into its own class.
https://bugzilla.gnome.org/show_bug.cgi?id=670086
js/ui/shellDBus.js | 15 +-
src/Makefile.am | 2 +
src/shell-global-private.h | 14 --
src/shell-global.c | 351 ++-------------------------------------
src/shell-global.h | 23 +---
src/shell-screenshot.c | 401 ++++++++++++++++++++++++++++++++++++++++++++
src/shell-screenshot.h | 51 ++++++
7 files changed, 475 insertions(+), 382 deletions(-)
---
diff --git a/js/ui/shellDBus.js b/js/ui/shellDBus.js
index 96c75f1..5233383 100644
--- a/js/ui/shellDBus.js
+++ b/js/ui/shellDBus.js
@@ -146,8 +146,9 @@ const GnomeShell = new Lang.Class({
*/
ScreenshotAreaAsync : function (params, invocation) {
let [x, y, width, height, flash, filename, callback] = params;
- global.screenshot_area (x, y, width, height, filename,
- Lang.bind(this, this._onScreenshotComplete,
+ let screenshot = new Shell.Screenshot();
+ screenshot.screenshot_area (x, y, width, height, filename,
+ Lang.bind(this, this._onScreenshotComplete,
flash, invocation));
},
@@ -165,8 +166,9 @@ const GnomeShell = new Lang.Class({
*/
ScreenshotWindowAsync : function (params, invocation) {
let [include_frame, include_cursor, flash, filename] = params;
- global.screenshot_window (include_frame, include_cursor, filename,
- Lang.bind(this, this._onScreenshotComplete,
+ let screenshot = new Shell.Screenshot();
+ screenshot.screenshot_window (include_frame, include_cursor, filename,
+ Lang.bind(this, this._onScreenshotComplete,
flash, invocation));
},
@@ -183,8 +185,9 @@ const GnomeShell = new Lang.Class({
*/
ScreenshotAsync : function (params, invocation) {
let [include_cursor, flash, filename] = params;
- global.screenshot(include_cursor, filename,
- Lang.bind(this, this._onScreenshotComplete,
+ let screenshot = new Shell.Screenshot();
+ screenshot.screenshot(include_cursor, filename,
+ Lang.bind(this, this._onScreenshotComplete,
flash, invocation));
},
diff --git a/src/Makefile.am b/src/Makefile.am
index 835ce5f..b512b41 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -114,6 +114,7 @@ shell_public_headers_h = \
shell-mount-operation.h \
shell-network-agent.h \
shell-perf-log.h \
+ shell-screenshot.h \
shell-screen-grabber.h \
shell-slicer.h \
shell-stack.h \
@@ -162,6 +163,7 @@ libgnome_shell_la_SOURCES = \
shell-perf-log.c \
shell-polkit-authentication-agent.h \
shell-polkit-authentication-agent.c \
+ shell-screenshot.c \
shell-screen-grabber.c \
shell-slicer.c \
shell-stack.c \
diff --git a/src/shell-global-private.h b/src/shell-global-private.h
index 27e7829..62f7c26 100644
--- a/src/shell-global-private.h
+++ b/src/shell-global-private.h
@@ -19,18 +19,4 @@ gboolean _shell_global_check_xdnd_event (ShellGlobal *global,
void _shell_global_set_session_type (ShellGlobal *global,
ShellSessionType session_type);
-/* Used for async screenshot grabbing */
-typedef struct _screenshot_data {
- ShellGlobal *global;
-
- char *filename;
-
- cairo_surface_t *image;
- cairo_rectangle_int_t screenshot_area;
-
- gboolean include_cursor;
-
- ShellGlobalScreenshotCallback callback;
-} _screenshot_data;
-
#endif /* __SHELL_GLOBAL_PRIVATE_H__ */
diff --git a/src/shell-global.c b/src/shell-global.c
index 8588f37..ed73f29 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -36,7 +36,6 @@
#include "shell-global-private.h"
#include "shell-jsapi-compat-private.h"
#include "shell-perf-log.h"
-#include "shell-screen-grabber.h"
#include "shell-window-tracker.h"
#include "shell-wm.h"
#include "st.h"
@@ -706,6 +705,17 @@ shell_global_set_stage_input_region (ShellGlobal *global,
}
/**
+ * shell_global_get_stage:
+ *
+ * Return value: (transfer none): The default #ClutterStage
+ */
+ClutterStage *
+shell_global_get_stage (ShellGlobal *global)
+{
+ return global->stage;
+}
+
+/**
* shell_global_get_screen:
*
* Return value: (transfer none): The default #MetaScreen
@@ -1898,345 +1908,6 @@ shell_global_launch_calendar_server (ShellGlobal *global)
g_free (calendar_server_exe);
}
-static void
-on_screenshot_written (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
-{
- _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->screenshot_area);
-
- cairo_surface_destroy (screenshot_data->image);
- g_free (screenshot_data->filename);
- g_free (screenshot_data);
-}
-
-static void
-write_screenshot_thread (GSimpleAsyncResult *result,
- GObject *object,
- GCancellable *cancellable)
-{
- cairo_status_t status;
- _screenshot_data *screenshot_data = g_async_result_get_user_data (G_ASYNC_RESULT (result));
- g_assert (screenshot_data != NULL);
-
- status = cairo_surface_write_to_png (screenshot_data->image, screenshot_data->filename);
- g_simple_async_result_set_op_res_gboolean (result, status == CAIRO_STATUS_SUCCESS);
-}
-
-static void
-do_grab_screenshot (_screenshot_data *screenshot_data,
- int x,
- int y,
- int width,
- int height)
-{
- ShellScreenGrabber *grabber;
- static const cairo_user_data_key_t key;
- guchar *data;
-
- grabber = shell_screen_grabber_new ();
- data = shell_screen_grabber_grab (grabber, x, y, width, height);
- g_object_unref (grabber);
-
- screenshot_data->image = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_RGB24,
- width, height, width * 4);
- cairo_surface_set_user_data (screenshot_data->image, &key,
- data, (cairo_destroy_func_t)g_free);
-}
-
-static void
-_draw_cursor_image (cairo_surface_t *surface,
- cairo_rectangle_int_t area)
-{
- XFixesCursorImage *cursor_image;
-
- cairo_surface_t *cursor_surface;
- cairo_region_t *screenshot_region;
- cairo_t *cr;
-
- guchar *data;
- int stride;
- int i, j;
-
- cursor_image = XFixesGetCursorImage (clutter_x11_get_default_display ());
-
- if (!cursor_image)
- return;
-
- screenshot_region = cairo_region_create_rectangle (&area);
-
- if (!cairo_region_contains_point (screenshot_region, cursor_image->x, cursor_image->y))
- {
- XFree (cursor_image);
- cairo_region_destroy (screenshot_region);
- return;
- }
-
- cursor_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, cursor_image->width, cursor_image->height);
-
- /* The pixel data (in typical Xlib breakage) is longs even on
- * 64-bit platforms, so we have to data-convert there. For simplicity,
- * just do it always
- */
- data = cairo_image_surface_get_data (cursor_surface);
- stride = cairo_image_surface_get_stride (cursor_surface);
- for (i = 0; i < cursor_image->height; i++)
- for (j = 0; j < cursor_image->width; j++)
- *(guint32 *)(data + i * stride + 4 * j) = cursor_image->pixels[i * cursor_image->width + j];
-
- cairo_surface_mark_dirty (cursor_surface);
-
- cr = cairo_create (surface);
- cairo_set_source_surface (cr,
- cursor_surface,
- cursor_image->x - cursor_image->xhot - area.x,
- cursor_image->y - cursor_image->yhot - area.y);
- cairo_paint (cr);
-
- cairo_destroy (cr);
- cairo_surface_destroy (cursor_surface);
- cairo_region_destroy (screenshot_region);
- XFree (cursor_image);
-}
-
-static void
-grab_screenshot (ClutterActor *stage,
- _screenshot_data *screenshot_data)
-{
- MetaScreen *screen = shell_global_get_screen (screenshot_data->global);
- int width, height;
- GSimpleAsyncResult *result;
-
- meta_plugin_query_screen_size (screenshot_data->global->plugin, &width, &height);
-
- do_grab_screenshot (screenshot_data, 0, 0, width, height);
-
- 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 (screenshot_data->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);
- }
-
- screenshot_data->screenshot_area.x = 0;
- screenshot_data->screenshot_area.y = 0;
- screenshot_data->screenshot_area.width = width;
- screenshot_data->screenshot_area.height = height;
-
- if (screenshot_data->include_cursor)
- _draw_cursor_image (screenshot_data->image, screenshot_data->screenshot_area);
-
- 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);
- g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
- g_object_unref (result);
-}
-
-static void
-grab_area_screenshot (ClutterActor *stage,
- _screenshot_data *screenshot_data)
-{
- GSimpleAsyncResult *result;
-
- do_grab_screenshot (screenshot_data,
- screenshot_data->screenshot_area.x,
- screenshot_data->screenshot_area.y,
- screenshot_data->screenshot_area.width,
- screenshot_data->screenshot_area.height);
-
- g_signal_handlers_disconnect_by_func (stage, (void *)grab_area_screenshot, (gpointer)screenshot_data);
- result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, grab_area_screenshot);
- g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
- g_object_unref (result);
-}
-
-/**
- * shell_global_screenshot:
- * @global: the #ShellGlobal
- * @include_cursor: Whether to include the cursor or not
- * @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,
- gboolean include_cursor,
- 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;
- data->include_cursor = include_cursor;
-
- 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->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));
-
- 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
- * @include_cursor: Whether to include the cursor or not
- *
- * @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 focused window (optionally omitting the frame)
- * in @filename as png image.
- *
- */
-void
-shell_global_screenshot_window (ShellGlobal *global,
- gboolean include_frame,
- gboolean include_cursor,
- const char *filename,
- ShellGlobalScreenshotCallback callback)
-{
- GSimpleAsyncResult *result;
-
- _screenshot_data *screenshot_data = g_new0 (_screenshot_data, 1);
-
- 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;
- gfloat actor_x, actor_y;
- MetaShapedTexture *stex;
- MetaRectangle rect;
- cairo_rectangle_int_t clip;
-
- screenshot_data->global = global;
- screenshot_data->filename = g_strdup (filename);
- screenshot_data->callback = callback;
-
- window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
- clutter_actor_get_position (window_actor, &actor_x, &actor_y);
-
- if (include_frame || !meta_window_get_frame (window))
- {
- meta_window_get_outer_rect (window, &rect);
-
- screenshot_data->screenshot_area.x = rect.x;
- screenshot_data->screenshot_area.y = rect.y;
-
- clip.x = rect.x - (gint) actor_x;
- clip.y = rect.y - (gint) actor_y;
- }
- else
- {
- rect = *meta_window_get_rect (window);
-
- screenshot_data->screenshot_area.x = (gint) actor_x + rect.x;
- screenshot_data->screenshot_area.y = (gint) actor_y + rect.y;
-
- clip.x = rect.x;
- clip.y = rect.y;
- }
-
- clip.width = screenshot_data->screenshot_area.width = rect.width;
- clip.height = screenshot_data->screenshot_area.height = rect.height;
-
- stex = META_SHAPED_TEXTURE (meta_window_actor_get_texture (META_WINDOW_ACTOR (window_actor)));
- screenshot_data->image = meta_shaped_texture_get_image (stex, &clip);
-
- if (include_cursor)
- _draw_cursor_image (screenshot_data->image, screenshot_data->screenshot_area);
-
- result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, shell_global_screenshot_window);
- g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
- g_object_unref (result);
-}
-
/**
* shell_global_get_session_type:
* @global: The #ShellGlobal.
diff --git a/src/shell-global.h b/src/shell-global.h
index 7e83451..5a39e79 100644
--- a/src/shell-global.h
+++ b/src/shell-global.h
@@ -29,6 +29,7 @@ GType shell_global_get_type (void) G_GNUC_CONST;
ShellGlobal *shell_global_get (void);
+ClutterStage *shell_global_get_stage (ShellGlobal *global);
MetaScreen *shell_global_get_screen (ShellGlobal *global);
GdkScreen *shell_global_get_gdk_screen (ShellGlobal *global);
MetaDisplay *shell_global_get_display (ShellGlobal *global);
@@ -140,28 +141,6 @@ void shell_global_reexec_self (ShellGlobal *global);
void shell_global_launch_calendar_server (ShellGlobal *global);
-typedef void (*ShellGlobalScreenshotCallback) (ShellGlobal *global,
- gboolean success,
- cairo_rectangle_int_t *screenshot_area);
-
-void shell_global_screenshot_area (ShellGlobal *global,
- int x,
- int y,
- int width,
- int height,
- const char *filename,
- ShellGlobalScreenshotCallback callback);
-
-void shell_global_screenshot_window (ShellGlobal *global,
- gboolean include_frame,
- gboolean include_cursor,
- const char *filename,
- ShellGlobalScreenshotCallback callback);
-
-void shell_global_screenshot (ShellGlobal *global,
- gboolean include_cursor,
- const char *filename,
- ShellGlobalScreenshotCallback callback);
typedef enum {
SHELL_SESSION_USER,
SHELL_SESSION_GDM
diff --git a/src/shell-screenshot.c b/src/shell-screenshot.c
new file mode 100644
index 0000000..792e737
--- /dev/null
+++ b/src/shell-screenshot.c
@@ -0,0 +1,401 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+
+#include <X11/extensions/Xfixes.h>
+#include <clutter/x11/clutter-x11.h>
+#include <clutter/clutter.h>
+#include <cogl/cogl.h>
+#include <meta/display.h>
+#include <meta/util.h>
+#include <meta/meta-plugin.h>
+#include <meta/meta-shaped-texture.h>
+
+#include "shell-global.h"
+#include "shell-screen-grabber.h"
+#include "shell-screenshot.h"
+
+struct _ShellScreenshotClass
+{
+ GObjectClass parent_class;
+};
+
+struct _ShellScreenshot
+{
+ GObject parent_instance;
+
+ ShellGlobal *global;
+};
+
+/* Used for async screenshot grabbing */
+typedef struct _screenshot_data {
+ ShellScreenshot *screenshot;
+
+ char *filename;
+
+ cairo_surface_t *image;
+ cairo_rectangle_int_t screenshot_area;
+
+ gboolean include_cursor;
+
+ ShellScreenshotCallback callback;
+} _screenshot_data;
+
+G_DEFINE_TYPE(ShellScreenshot, shell_screenshot, G_TYPE_OBJECT);
+
+static void
+shell_screenshot_finalize (GObject *gobject)
+{
+
+}
+
+static void
+shell_screenshot_class_init (ShellScreenshotClass *screenshot_class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (screenshot_class);
+
+ gobject_class->finalize = shell_screenshot_finalize;
+}
+
+static void
+shell_screenshot_init (ShellScreenshot *screenshot)
+{
+ screenshot->global = shell_global_get ();
+}
+
+static void
+on_screenshot_written (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ _screenshot_data *screenshot_data = (_screenshot_data*) user_data;
+ if (screenshot_data->callback)
+ screenshot_data->callback (screenshot_data->screenshot,
+ 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);
+ g_free (screenshot_data);
+}
+
+static void
+write_screenshot_thread (GSimpleAsyncResult *result,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ cairo_status_t status;
+ _screenshot_data *screenshot_data = g_async_result_get_user_data (G_ASYNC_RESULT (result));
+ g_assert (screenshot_data != NULL);
+
+ status = cairo_surface_write_to_png (screenshot_data->image, screenshot_data->filename);
+ g_simple_async_result_set_op_res_gboolean (result, status == CAIRO_STATUS_SUCCESS);
+}
+
+static void
+do_grab_screenshot (_screenshot_data *screenshot_data,
+ int x,
+ int y,
+ int width,
+ int height)
+{
+ ShellScreenGrabber *grabber;
+ static const cairo_user_data_key_t key;
+ guchar *data;
+
+ grabber = shell_screen_grabber_new ();
+ data = shell_screen_grabber_grab (grabber, x, y, width, height);
+ g_object_unref (grabber);
+
+ screenshot_data->image = cairo_image_surface_create_for_data (data, CAIRO_FORMAT_RGB24,
+ width, height, width * 4);
+ cairo_surface_set_user_data (screenshot_data->image, &key,
+ data, (cairo_destroy_func_t)g_free);
+}
+
+static void
+_draw_cursor_image (cairo_surface_t *surface,
+ cairo_rectangle_int_t area)
+{
+ XFixesCursorImage *cursor_image;
+
+ cairo_surface_t *cursor_surface;
+ cairo_region_t *screenshot_region;
+ cairo_t *cr;
+
+ guchar *data;
+ int stride;
+ int i, j;
+
+ cursor_image = XFixesGetCursorImage (clutter_x11_get_default_display ());
+
+ if (!cursor_image)
+ return;
+
+ screenshot_region = cairo_region_create_rectangle (&area);
+
+ if (!cairo_region_contains_point (screenshot_region, cursor_image->x, cursor_image->y))
+ {
+ XFree (cursor_image);
+ cairo_region_destroy (screenshot_region);
+ return;
+ }
+
+ cursor_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, cursor_image->width, cursor_image->height);
+
+ /* The pixel data (in typical Xlib breakage) is longs even on
+ * 64-bit platforms, so we have to data-convert there. For simplicity,
+ * just do it always
+ */
+ data = cairo_image_surface_get_data (cursor_surface);
+ stride = cairo_image_surface_get_stride (cursor_surface);
+ for (i = 0; i < cursor_image->height; i++)
+ for (j = 0; j < cursor_image->width; j++)
+ *(guint32 *)(data + i * stride + 4 * j) = cursor_image->pixels[i * cursor_image->width + j];
+
+ cairo_surface_mark_dirty (cursor_surface);
+
+ cr = cairo_create (surface);
+ cairo_set_source_surface (cr,
+ cursor_surface,
+ cursor_image->x - cursor_image->xhot - area.x,
+ cursor_image->y - cursor_image->yhot - area.y);
+ cairo_paint (cr);
+
+ cairo_destroy (cr);
+ cairo_surface_destroy (cursor_surface);
+ cairo_region_destroy (screenshot_region);
+ XFree (cursor_image);
+}
+
+static void
+grab_screenshot (ClutterActor *stage,
+ _screenshot_data *screenshot_data)
+{
+ MetaScreen *screen = shell_global_get_screen (screenshot_data->screenshot->global);
+ int width, height;
+ GSimpleAsyncResult *result;
+
+ meta_screen_get_size (screen, &width, &height);
+
+ do_grab_screenshot (screenshot_data, 0, 0, width, height);
+
+ 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 (screenshot_data->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);
+ }
+
+ screenshot_data->screenshot_area.x = 0;
+ screenshot_data->screenshot_area.y = 0;
+ screenshot_data->screenshot_area.width = width;
+ screenshot_data->screenshot_area.height = height;
+
+ if (screenshot_data->include_cursor)
+ _draw_cursor_image (screenshot_data->image, screenshot_data->screenshot_area);
+
+ 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);
+ g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
+ g_object_unref (result);
+}
+
+static void
+grab_area_screenshot (ClutterActor *stage,
+ _screenshot_data *screenshot_data)
+{
+ GSimpleAsyncResult *result;
+
+ do_grab_screenshot (screenshot_data,
+ screenshot_data->screenshot_area.x,
+ screenshot_data->screenshot_area.y,
+ screenshot_data->screenshot_area.width,
+ screenshot_data->screenshot_area.height);
+
+ g_signal_handlers_disconnect_by_func (stage, (void *)grab_area_screenshot, (gpointer)screenshot_data);
+ result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, grab_area_screenshot);
+ g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
+ g_object_unref (result);
+}
+
+/**
+ * shell_screenshot_screenshot:
+ * @screenshot: the #ShellScreenshot
+ * @include_cursor: Whether to include the cursor or not
+ * @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_screenshot_screenshot (ShellScreenshot *screenshot,
+ gboolean include_cursor,
+ const char *filename,
+ ShellScreenshotCallback callback)
+{
+ ClutterActor *stage;
+ _screenshot_data *data = g_new0 (_screenshot_data, 1);
+
+ data->screenshot = screenshot;
+ data->filename = g_strdup (filename);
+ data->callback = callback;
+ data->include_cursor = include_cursor;
+
+ stage = CLUTTER_ACTOR (shell_global_get_stage (screenshot->global));
+
+ g_signal_connect_after (stage, "paint", G_CALLBACK (grab_screenshot), (gpointer)data);
+
+ clutter_actor_queue_redraw (stage);
+}
+
+/**
+ * shell_screenshot_screenshot_area:
+ * @screenshot: the #ShellScreenshot
+ * @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_screenshot_screenshot_area (ShellScreenshot *screenshot,
+ int x,
+ int y,
+ int width,
+ int height,
+ const char *filename,
+ ShellScreenshotCallback callback)
+{
+ ClutterActor *stage;
+ _screenshot_data *data = g_new0 (_screenshot_data, 1);
+
+ data->screenshot = screenshot;
+ data->filename = g_strdup (filename);
+ 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 (shell_global_get_stage (screenshot->global));
+
+ g_signal_connect_after (stage, "paint", G_CALLBACK (grab_area_screenshot), (gpointer)data);
+
+ clutter_actor_queue_redraw (stage);
+}
+
+/**
+ * shell_screenshot_screenshot_window:
+ * @screenshot: the #ShellScreenshot
+ * @include_frame: Whether to include the frame or not
+ * @include_cursor: Whether to include the cursor or not
+ *
+ * @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 focused window (optionally omitting the frame)
+ * in @filename as png image.
+ *
+ */
+void
+shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
+ gboolean include_frame,
+ gboolean include_cursor,
+ const char *filename,
+ ShellScreenshotCallback callback)
+{
+ GSimpleAsyncResult *result;
+
+ _screenshot_data *screenshot_data = g_new0 (_screenshot_data, 1);
+
+ MetaScreen *screen = shell_global_get_screen (screenshot->global);
+ MetaDisplay *display = meta_screen_get_display (screen);
+ MetaWindow *window = meta_display_get_focus_window (display);
+ ClutterActor *window_actor;
+ gfloat actor_x, actor_y;
+ MetaShapedTexture *stex;
+ MetaRectangle rect;
+ cairo_rectangle_int_t clip;
+
+ screenshot_data->screenshot = screenshot;
+ screenshot_data->filename = g_strdup (filename);
+ screenshot_data->callback = callback;
+
+ window_actor = CLUTTER_ACTOR (meta_window_get_compositor_private (window));
+ clutter_actor_get_position (window_actor, &actor_x, &actor_y);
+
+ if (include_frame || !meta_window_get_frame (window))
+ {
+ meta_window_get_outer_rect (window, &rect);
+
+ screenshot_data->screenshot_area.x = rect.x;
+ screenshot_data->screenshot_area.y = rect.y;
+
+ clip.x = rect.x - (gint) actor_x;
+ clip.y = rect.y - (gint) actor_y;
+ }
+ else
+ {
+ rect = *meta_window_get_rect (window);
+
+ screenshot_data->screenshot_area.x = (gint) actor_x + rect.x;
+ screenshot_data->screenshot_area.y = (gint) actor_y + rect.y;
+
+ clip.x = rect.x;
+ clip.y = rect.y;
+ }
+
+ clip.width = screenshot_data->screenshot_area.width = rect.width;
+ clip.height = screenshot_data->screenshot_area.height = rect.height;
+
+ stex = META_SHAPED_TEXTURE (meta_window_actor_get_texture (META_WINDOW_ACTOR (window_actor)));
+ screenshot_data->image = meta_shaped_texture_get_image (stex, &clip);
+
+ if (include_cursor)
+ _draw_cursor_image (screenshot_data->image, screenshot_data->screenshot_area);
+
+ result = g_simple_async_result_new (NULL, on_screenshot_written, (gpointer)screenshot_data, shell_screenshot_screenshot_window);
+ g_simple_async_result_run_in_thread (result, write_screenshot_thread, G_PRIORITY_DEFAULT, NULL);
+ g_object_unref (result);
+}
diff --git a/src/shell-screenshot.h b/src/shell-screenshot.h
new file mode 100644
index 0000000..9be1574
--- /dev/null
+++ b/src/shell-screenshot.h
@@ -0,0 +1,51 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+#ifndef __SHELL_SCREENSHOT_H__
+#define __SHELL_SCREENSHOT_H__
+
+/**
+ * SECTION:shell-screenshot
+ * @short_description: Grabs screenshots of areas and/or windows
+ *
+ * The #ShellScreenshot object is used to take screenshots of screen
+ * areas or windows and write them out as png files.
+ *
+ */
+
+typedef struct _ShellScreenshot ShellScreenshot;
+typedef struct _ShellScreenshotClass ShellScreenshotClass;
+
+#define SHELL_TYPE_SCREENSHOT (shell_screenshot_get_type ())
+#define SHELL_SCREENSHOT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_SCREENSHOT, ShellScreenshot))
+#define SHELL_SCREENSHOT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_SCREENSHOT, ShellScreenshotClass))
+#define SHELL_IS_SCREENSHOT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_SCREENSHOT))
+#define SHELL_IS_SCREENSHOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_SCREENSHOT))
+#define SHELL_SCREENSHOT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_SCREENSHOT, ShellScreenshotClass))
+
+GType shell_screenshot_get_type (void) G_GNUC_CONST;
+
+ShellScreenGrabber *shell_screenshot_new (void);
+
+typedef void (*ShellScreenshotCallback) (ShellScreenshot *screenshot,
+ gboolean success,
+ cairo_rectangle_int_t *screenshot_area);
+
+void shell_screenshot_screenshot_area (ShellScreenshot *screenshot,
+ int x,
+ int y,
+ int width,
+ int height,
+ const char *filename,
+ ShellScreenshotCallback callback);
+
+void shell_screenshot_screenshot_window (ShellScreenshot *screenshot,
+ gboolean include_frame,
+ gboolean include_cursor,
+ const char *filename,
+ ShellScreenshotCallback callback);
+
+void shell_screenshot_screenshot (ShellScreenshot *screenshot,
+ gboolean include_cursor,
+ const char *filename,
+ ShellScreenshotCallback callback);
+
+#endif /* ___SHELL_SCREENSHOT_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]