summaryrefslogtreecommitdiff
path: root/mate-screenshot/screenshot-utils.c
diff options
context:
space:
mode:
authormonsta <[email protected]>2015-09-09 12:35:05 +0300
committermonsta <[email protected]>2015-09-09 12:35:05 +0300
commitaa3a853c9d06d0321e8924cbfbc42c8411f571f5 (patch)
tree7bca363d0bb67fddadbe6fd53e92c3b3db71db8d /mate-screenshot/screenshot-utils.c
parent0d36d61761a1d68839d61f521889dba3db7f514f (diff)
downloadmate-utils-aa3a853c9d06d0321e8924cbfbc42c8411f571f5.tar.bz2
mate-utils-aa3a853c9d06d0321e8924cbfbc42c8411f571f5.tar.xz
mate-screenshot: move stuff to data/ and src/ subdirs
Diffstat (limited to 'mate-screenshot/screenshot-utils.c')
-rw-r--r--mate-screenshot/screenshot-utils.c1040
1 files changed, 0 insertions, 1040 deletions
diff --git a/mate-screenshot/screenshot-utils.c b/mate-screenshot/screenshot-utils.c
deleted file mode 100644
index eaeeca28..00000000
--- a/mate-screenshot/screenshot-utils.c
+++ /dev/null
@@ -1,1040 +0,0 @@
-/* screenshot-utils.c - common functions for MATE Screenshot
- *
- * Copyright (C) 2001-2006 Jonathan Blandford <[email protected]>
- * Copyright (C) 2008 Cosimo Cecchi <[email protected]>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- */
-
-#include "config.h"
-#include "screenshot-utils.h"
-
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-#include <glib.h>
-#include <glib/gi18n.h>
-
-#ifdef HAVE_X11_EXTENSIONS_SHAPE_H
-#include <X11/extensions/shape.h>
-#endif
-
-#if GTK_CHECK_VERSION (3, 0, 0)
-#define GdkRegion cairo_region_t
-#define gdk_region_new cairo_region_create
-#define gdk_region_destroy cairo_region_destroy
-#define gdk_region_rectangle cairo_region_create_rectangle
-#define gdk_region_offset cairo_region_translate
-#define gdk_region_intersect cairo_region_intersect
-#define gdk_region_subtract cairo_region_subtract
-#define gdk_region_union_with_rect cairo_region_union_rectangle
-#define gdk_cursor_unref g_object_unref
-#endif
-
-static GtkWidget *selection_window;
-
-#define SELECTION_NAME "_MATE_PANEL_SCREENSHOT"
-
-static char *
-get_utf8_property (GdkWindow *window,
- GdkAtom atom)
-{
- gboolean res;
- GdkAtom utf8_string;
- GdkAtom type;
- int actual_format, actual_length;
- guchar *data;
- char *retval;
-
- utf8_string = gdk_x11_xatom_to_atom (gdk_x11_get_xatom_by_name ("UTF8_STRING"));
- res = gdk_property_get (window, atom, utf8_string,
- 0, G_MAXLONG, FALSE,
- &type,
- &actual_format, &actual_length,
- &data);
- if (!res)
- return NULL;
-
- if (type != utf8_string || actual_format != 8 || actual_length == 0)
- {
- g_free (data);
- return NULL;
- }
-
- if (!g_utf8_validate ((gchar *) data, actual_length, NULL))
- {
- char *atom_name = gdk_atom_name (atom);
-
- g_warning ("Property `%s' (format: %d, length: %d) contained "
- "invalid UTF-8",
- atom_name,
- actual_format,
- actual_length);
-
- g_free (atom_name);
- g_free (data);
-
- return NULL;
- }
-
- retval = g_strndup ((gchar *) data, actual_length);
-
- g_free (data);
-
- return retval;
-}
-
-/* To make sure there is only one screenshot taken at a time,
- * (Imagine key repeat for the print screen key) we hold a selection
- * until we are done taking the screenshot
- */
-gboolean
-screenshot_grab_lock (void)
-{
- GdkAtom selection_atom;
- gboolean result = FALSE;
-
- selection_atom = gdk_atom_intern (SELECTION_NAME, FALSE);
- gdk_x11_grab_server ();
-
- if (gdk_selection_owner_get (selection_atom) != NULL)
- goto out;
-
- selection_window = gtk_invisible_new ();
- gtk_widget_show (selection_window);
-
- if (!gtk_selection_owner_set (selection_window,
- gdk_atom_intern (SELECTION_NAME, FALSE),
- GDK_CURRENT_TIME))
- {
- gtk_widget_destroy (selection_window);
- selection_window = NULL;
- goto out;
- }
-
- result = TRUE;
-
- out:
- gdk_x11_ungrab_server ();
- gdk_flush ();
-
- return result;
-}
-
-void
-screenshot_release_lock (void)
-{
- if (selection_window)
- {
- gtk_widget_destroy (selection_window);
- selection_window = NULL;
- }
-
- gdk_flush ();
-}
-
-static GdkWindow *
-screenshot_find_active_window (void)
-{
- GdkWindow *window;
- GdkScreen *default_screen;
-
- default_screen = gdk_screen_get_default ();
- window = gdk_screen_get_active_window (default_screen);
-
- return window;
-}
-
-static gboolean
-screenshot_window_is_desktop (GdkWindow *window)
-{
- GdkWindow *root_window = gdk_get_default_root_window ();
- GdkWindowTypeHint window_type_hint;
-
- if (window == root_window)
- return TRUE;
-
- window_type_hint = gdk_window_get_type_hint (window);
- if (window_type_hint == GDK_WINDOW_TYPE_HINT_DESKTOP)
- return TRUE;
-
- return FALSE;
-
-}
-
-#define MAXIMUM_WM_REPARENTING_DEPTH 4
-
-static GdkWindow *
-look_for_hint_helper (GdkWindow *window,
- GdkAtom property,
- int depth)
-{
- gboolean res;
- GdkAtom actual_type;
- int actual_format, actual_length;
- guchar *data;
-
- res = gdk_property_get (window, property, GDK_NONE,
- 0, 1, FALSE,
- &actual_type,
- &actual_format, &actual_length,
- &data);
-
- if (res == TRUE &&
- data != NULL &&
- actual_format == 32 &&
- data[0] == 1)
- {
- g_free (data);
-
- return window;
- }
-
- if (depth < MAXIMUM_WM_REPARENTING_DEPTH)
- {
- GList *children, *l;
-
- children = gdk_window_get_children (window);
- if (children != NULL)
- {
- for (l = children; l; l = l->next)
- {
- window = look_for_hint_helper (l->data, property, depth + 1);
- if (window)
- break;
- }
-
- g_list_free (children);
-
- if (window)
- return window;
- }
- }
-
- return NULL;
-}
-
-static GdkWindow *
-look_for_hint (GdkWindow *window,
- GdkAtom property)
-{
- GdkWindow *retval;
-
- retval = look_for_hint_helper (window, property, 0);
-
- return retval;
-}
-
-GdkWindow *
-screenshot_find_current_window ()
-{
- GdkWindow *current_window;
-
- current_window = screenshot_find_active_window ();
-
- /* If there's no active window, we fall back to returning the
- * window that the cursor is in.
- */
- if (!current_window)
- current_window = gdk_window_at_pointer (NULL, NULL);
-
- if (current_window)
- {
- if (screenshot_window_is_desktop (current_window))
- /* if the current window is the desktop (e.g. caja), we
- * return NULL, as getting the whole screen makes more sense.
- */
- return NULL;
-
- /* Once we have a window, we take the toplevel ancestor. */
- current_window = gdk_window_get_toplevel (current_window);
- }
-
- return current_window;
-}
-
-typedef struct {
- GdkRectangle rect;
- gboolean button_pressed;
- GtkWidget *window;
-} select_area_filter_data;
-
-static gboolean
-select_area_button_press (GtkWidget *window,
- GdkEventButton *event,
- select_area_filter_data *data)
-{
- if (data->button_pressed)
- return TRUE;
-
- data->button_pressed = TRUE;
- data->rect.x = event->x_root;
- data->rect.y = event->y_root;
-
- return TRUE;
-}
-
-static gboolean
-select_area_motion_notify (GtkWidget *window,
- GdkEventMotion *event,
- select_area_filter_data *data)
-{
- GdkRectangle draw_rect;
-
- if (!data->button_pressed)
- return TRUE;
-
- draw_rect.width = ABS (data->rect.x - event->x_root);
- draw_rect.height = ABS (data->rect.y - event->y_root);
- draw_rect.x = MIN (data->rect.x, event->x_root);
- draw_rect.y = MIN (data->rect.y, event->y_root);
-
- if (draw_rect.width <= 0 || draw_rect.height <= 0)
- {
- gtk_window_move (GTK_WINDOW (window), -100, -100);
- gtk_window_resize (GTK_WINDOW (window), 10, 10);
- return TRUE;
- }
-
- gtk_window_move (GTK_WINDOW (window), draw_rect.x, draw_rect.y);
- gtk_window_resize (GTK_WINDOW (window), draw_rect.width, draw_rect.height);
-
- /* We (ab)use app-paintable to indicate if we have an RGBA window */
- if (!gtk_widget_get_app_paintable (window))
- {
- GdkWindow *gdkwindow = gtk_widget_get_window (window);
-
- /* Shape the window to make only the outline visible */
- if (draw_rect.width > 2 && draw_rect.height > 2)
- {
-#if GTK_CHECK_VERSION (3, 0, 0)
- cairo_region_t *region, *region2;
- cairo_rectangle_int_t region_rect = {
-#else
- GdkRegion *region, *region2;
- GdkRectangle region_rect = {
-#endif
- 0, 0,
- draw_rect.width - 2, draw_rect.height - 2
- };
-
-#if GTK_CHECK_VERSION (3, 0, 0)
- region = cairo_region_create_rectangle (&region_rect);
-#else
- region = gdk_region_rectangle (&region_rect);
-#endif
- region_rect.x++;
- region_rect.y++;
- region_rect.width -= 2;
- region_rect.height -= 2;
-#if GTK_CHECK_VERSION (3, 0, 0)
- region2 = cairo_region_create_rectangle (&region_rect);
- cairo_region_subtract (region, region2);
-#else
- region2 = gdk_region_rectangle (&region_rect);
- gdk_region_subtract (region, region2);
-#endif
-
- gdk_window_shape_combine_region (gdkwindow, region, 0, 0);
-
- gdk_region_destroy (region);
- gdk_region_destroy (region2);
- }
- else
- gdk_window_shape_combine_region (gdkwindow, NULL, 0, 0);
- }
-
- return TRUE;
-}
-
-static gboolean
-select_area_button_release (GtkWidget *window,
- GdkEventButton *event,
- select_area_filter_data *data)
-{
- if (!data->button_pressed)
- return TRUE;
-
- data->rect.width = ABS (data->rect.x - event->x_root);
- data->rect.height = ABS (data->rect.y - event->y_root);
- data->rect.x = MIN (data->rect.x, event->x_root);
- data->rect.y = MIN (data->rect.y, event->y_root);
-
- gtk_main_quit ();
-
- return TRUE;
-}
-
-static gboolean
-select_area_key_press (GtkWidget *window,
- GdkEventKey *event,
- select_area_filter_data *data)
-{
- if (event->keyval == GDK_KEY_Escape)
- {
- data->rect.x = 0;
- data->rect.y = 0;
- data->rect.width = 0;
- data->rect.height = 0;
- gtk_main_quit ();
- }
-
- return TRUE;
-}
-
-
-static gboolean
-#if GTK_CHECK_VERSION (3, 0, 0)
-draw (GtkWidget *window, cairo_t *cr, gpointer unused)
-#else
-expose (GtkWidget *window, GdkEventExpose *event, gpointer unused)
-#endif
-{
- GtkAllocation allocation;
- GtkStyle *style;
-#if !GTK_CHECK_VERSION (3, 0, 0)
- cairo_t *cr;
-
- cr = gdk_cairo_create (event->window);
- gdk_cairo_region (cr, event->region);
- cairo_clip (cr);
-#endif
-
- style = gtk_widget_get_style (window);
-
- if (gtk_widget_get_app_paintable (window))
- {
- cairo_set_line_width (cr, 1.0);
-
- gtk_widget_get_allocation (window, &allocation);
-
- cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
- cairo_set_source_rgba (cr, 0, 0, 0, 0);
- cairo_paint (cr);
-
- cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
- gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_SELECTED]);
- cairo_paint_with_alpha (cr, 0.25);
-
- cairo_rectangle (cr,
- allocation.x + 0.5, allocation.y + 0.5,
- allocation.width - 1, allocation.height - 1);
- cairo_stroke (cr);
- }
- else
- {
- gdk_cairo_set_source_color (cr, &style->base[GTK_STATE_SELECTED]);
- cairo_paint (cr);
- }
-
-#if !GTK_CHECK_VERSION (3, 0, 0)
- cairo_destroy (cr);
-#endif
-
- return TRUE;
-}
-
-static GtkWidget *
-create_select_window (void)
-{
- GtkWidget *window;
- GdkScreen *screen;
-#if GTK_CHECK_VERSION (3, 0, 0)
- GdkVisual *visual;
-#endif
-
- screen = gdk_screen_get_default ();
-#if GTK_CHECK_VERSION (3, 0, 0)
- visual = gdk_screen_get_rgba_visual (screen);
-#endif
-
- window = gtk_window_new (GTK_WINDOW_POPUP);
- if (gdk_screen_is_composited (screen) &&
-#if GTK_CHECK_VERSION (3, 0, 0)
- visual)
-#else
- gdk_screen_get_rgba_colormap (screen))
-#endif
- {
-#if GTK_CHECK_VERSION (3, 0, 0)
- gtk_widget_set_visual (window, visual);
-#else
- gtk_widget_set_colormap (window, gdk_screen_get_rgba_colormap (screen));
-#endif
- gtk_widget_set_app_paintable (window, TRUE);
- }
-#if GTK_CHECK_VERSION (3, 0, 0)
- g_signal_connect (window, "draw", G_CALLBACK (draw), NULL);
-#else
- g_signal_connect (window, "expose-event", G_CALLBACK (expose), NULL);
-#endif
-
- gtk_window_move (GTK_WINDOW (window), -100, -100);
- gtk_window_resize (GTK_WINDOW (window), 10, 10);
- gtk_widget_show (window);
- return window;
-}
-
-typedef struct {
- GdkRectangle rectangle;
- SelectAreaCallback callback;
-} CallbackData;
-
-static gboolean
-emit_select_callback_in_idle (gpointer user_data)
-{
- CallbackData *data = user_data;
-
- data->callback (&data->rectangle);
-
- g_slice_free (CallbackData, data);
-
- return FALSE;
-}
-
-void
-screenshot_select_area_async (SelectAreaCallback callback)
-{
- GdkCursor *cursor;
- select_area_filter_data data;
- GdkRectangle *rectangle;
- CallbackData *cb_data;
-
- data.rect.x = 0;
- data.rect.y = 0;
- data.rect.width = 0;
- data.rect.height = 0;
- data.button_pressed = FALSE;
- data.window = create_select_window();
-
- cb_data = g_slice_new0 (CallbackData);
- cb_data->callback = callback;
-
- g_signal_connect (data.window, "key-press-event", G_CALLBACK (select_area_key_press), &data);
- g_signal_connect (data.window, "button-press-event", G_CALLBACK (select_area_button_press), &data);
- g_signal_connect (data.window, "button-release-event", G_CALLBACK (select_area_button_release), &data);
- g_signal_connect (data.window, "motion-notify-event", G_CALLBACK (select_area_motion_notify), &data);
-
- cursor = gdk_cursor_new (GDK_CROSSHAIR);
-
- if (gdk_pointer_grab (gtk_widget_get_window (data.window), FALSE,
- GDK_POINTER_MOTION_MASK|GDK_BUTTON_PRESS_MASK|GDK_BUTTON_RELEASE_MASK,
- NULL, cursor,
- GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
- {
- gdk_cursor_unref (cursor);
- goto out;
- }
-
- if (gdk_keyboard_grab (gtk_widget_get_window (data.window), FALSE, GDK_CURRENT_TIME) != GDK_GRAB_SUCCESS)
- {
- gdk_pointer_ungrab (GDK_CURRENT_TIME);
- gdk_cursor_unref (cursor);
- goto out;
- }
-
- gtk_main ();
-
- gdk_keyboard_ungrab (GDK_CURRENT_TIME);
- gdk_pointer_ungrab (GDK_CURRENT_TIME);
-
- gtk_widget_destroy (data.window);
- gdk_cursor_unref (cursor);
-
- gdk_flush ();
-
- out:
- cb_data->rectangle = data.rect;
-
- /* FIXME: we should actually be emitting the callback When
- * the compositor has finished re-drawing, but there seems to be no easy
- * way to know that.
- */
- g_timeout_add (200, emit_select_callback_in_idle, cb_data);
-}
-
-static Window
-find_wm_window (Window xid)
-{
- Window root, parent, *children;
- unsigned int nchildren;
-
- do
- {
- if (XQueryTree (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xid, &root,
- &parent, &children, &nchildren) == 0)
- {
- g_warning ("Couldn't find window manager window");
- return None;
- }
-
- if (root == parent)
- return xid;
-
- xid = parent;
- }
- while (TRUE);
-}
-
-#if GTK_CHECK_VERSION (3, 0, 0)
-static cairo_region_t *
-#else
-static GdkRegion *
-#endif
-make_region_with_monitors (GdkScreen *screen)
-{
-#if GTK_CHECK_VERSION (3, 0, 0)
- cairo_region_t *region;
-#else
- GdkRegion *region;
-#endif
- int num_monitors;
- int i;
-
- num_monitors = gdk_screen_get_n_monitors (screen);
-
-#if GTK_CHECK_VERSION (3, 0, 0)
- region = cairo_region_create ();
-#else
- region = gdk_region_new ();
-#endif
-
- for (i = 0; i < num_monitors; i++)
- {
- GdkRectangle rect;
-
- gdk_screen_get_monitor_geometry (screen, i, &rect);
-#if GTK_CHECK_VERSION (3, 0, 0)
- cairo_region_union_rectangle (region, &rect);
-#else
- gdk_region_union_with_rect (region, &rect);
-#endif
- }
-
- return region;
-}
-
-static void
-blank_rectangle_in_pixbuf (GdkPixbuf *pixbuf, GdkRectangle *rect)
-{
- int x, y;
- int x2, y2;
- guchar *pixels;
- int rowstride;
- int n_channels;
- guchar *row;
- gboolean has_alpha;
-
- g_assert (gdk_pixbuf_get_colorspace (pixbuf) == GDK_COLORSPACE_RGB);
-
- x2 = rect->x + rect->width;
- y2 = rect->y + rect->height;
-
- pixels = gdk_pixbuf_get_pixels (pixbuf);
- rowstride = gdk_pixbuf_get_rowstride (pixbuf);
- has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
- n_channels = gdk_pixbuf_get_n_channels (pixbuf);
-
- for (y = rect->y; y < y2; y++)
- {
- guchar *p;
-
- row = pixels + y * rowstride;
- p = row + rect->x * n_channels;
-
- for (x = rect->x; x < x2; x++)
- {
- *p++ = 0;
- *p++ = 0;
- *p++ = 0;
-
- if (has_alpha)
- *p++ = 255; /* opaque black */
- }
- }
-}
-
-static void
-#if GTK_CHECK_VERSION (3, 0, 0)
-blank_region_in_pixbuf (GdkPixbuf *pixbuf, cairo_region_t *region)
-{
- int n_rects;
- int i;
- int width, height;
- cairo_rectangle_int_t pixbuf_rect;
-
- n_rects = cairo_region_num_rectangles (region);
-#else
-blank_region_in_pixbuf (GdkPixbuf *pixbuf, GdkRegion *region)
-{
- GdkRectangle *rects;
- int n_rects;
- int i;
- int width, height;
- GdkRectangle pixbuf_rect;
-
- gdk_region_get_rectangles (region, &rects, &n_rects);
-#endif
-
- width = gdk_pixbuf_get_width (pixbuf);
- height = gdk_pixbuf_get_height (pixbuf);
-
- pixbuf_rect.x = 0;
- pixbuf_rect.y = 0;
- pixbuf_rect.width = width;
- pixbuf_rect.height = height;
-
- for (i = 0; i < n_rects; i++)
- {
-#if GTK_CHECK_VERSION (3, 0, 0)
- cairo_rectangle_int_t rect, dest;
-
- cairo_region_get_rectangle (region, i, &rect);
- if (gdk_rectangle_intersect (&rect, &pixbuf_rect, &dest))
-#else
- GdkRectangle dest;
-
- if (gdk_rectangle_intersect (rects + i, &pixbuf_rect, &dest))
-#endif
- blank_rectangle_in_pixbuf (pixbuf, &dest);
-
- }
-#if !GTK_CHECK_VERSION (3, 0, 0)
- g_free (rects);
-#endif
-}
-
-/* When there are multiple monitors with different resolutions, the visible area
- * within the root window may not be rectangular (it may have an L-shape, for
- * example). In that case, mask out the areas of the root window which would
- * not be visible in the monitors, so that screenshot do not end up with content
- * that the user won't ever see.
- */
-static void
-mask_monitors (GdkPixbuf *pixbuf, GdkWindow *root_window)
-{
- GdkScreen *screen;
-#if GTK_CHECK_VERSION (3, 0, 0)
- cairo_region_t *region_with_monitors;
- cairo_region_t *invisible_region;
- cairo_rectangle_int_t rect;
-#else
- GdkRegion *region_with_monitors;
- GdkRegion *invisible_region;
- GdkRectangle rect;
-#endif
-
- screen = gdk_window_get_screen (root_window);
-
- region_with_monitors = make_region_with_monitors (screen);
-
- rect.x = 0;
- rect.y = 0;
- rect.width = gdk_screen_get_width (screen);
- rect.height = gdk_screen_get_height (screen);
-
-#if GTK_CHECK_VERSION (3, 0, 0)
- invisible_region = cairo_region_create_rectangle (&rect);
- cairo_region_subtract (invisible_region, region_with_monitors);
-
- blank_region_in_pixbuf (pixbuf, invisible_region);
-
- cairo_region_destroy (region_with_monitors);
- cairo_region_destroy (invisible_region);
-#else
- invisible_region = gdk_region_rectangle (&rect);
- gdk_region_subtract (invisible_region, region_with_monitors);
-
- blank_region_in_pixbuf (pixbuf, invisible_region);
-
- gdk_region_destroy (region_with_monitors);
- gdk_region_destroy (invisible_region);
-#endif
-}
-
-GdkPixbuf *
-screenshot_get_pixbuf (GdkWindow *window,
- GdkRectangle *rectangle,
- gboolean include_pointer,
- gboolean include_border,
- gboolean include_mask)
-{
- GdkWindow *root;
- GdkPixbuf *screenshot;
- gint x_real_orig, y_real_orig, x_orig, y_orig;
- gint width, real_width, height, real_height;
-
- /* If the screenshot should include the border, we look for the WM window. */
-
- if (include_border)
- {
- Window xid, wm;
-
- xid = GDK_WINDOW_XID (window);
- wm = find_wm_window (xid);
-
- if (wm != None)
- window = gdk_x11_window_foreign_new_for_display (gdk_display_get_default (), wm);
-
- /* fallback to no border if we can't find the WM window. */
- }
-
- root = gdk_get_default_root_window ();
-
- real_width = gdk_window_get_width(window);
- real_height = gdk_window_get_height(window);
-
- gdk_window_get_origin (window, &x_real_orig, &y_real_orig);
-
- x_orig = x_real_orig;
- y_orig = y_real_orig;
- width = real_width;
- height = real_height;
-
- if (x_orig < 0)
- {
- width = width + x_orig;
- x_orig = 0;
- }
-
- if (y_orig < 0)
- {
- height = height + y_orig;
- y_orig = 0;
- }
-
- if (x_orig + width > gdk_screen_width ())
- width = gdk_screen_width () - x_orig;
-
- if (y_orig + height > gdk_screen_height ())
- height = gdk_screen_height () - y_orig;
-
- if (rectangle)
- {
- x_orig = rectangle->x - x_orig;
- y_orig = rectangle->y - y_orig;
- width = rectangle->width;
- height = rectangle->height;
- }
-
-#if GTK_CHECK_VERSION (3, 0, 0)
- screenshot = gdk_pixbuf_get_from_window (root,
- x_orig, y_orig,
- width, height);
-#else
- screenshot = gdk_pixbuf_get_from_drawable (NULL, root, NULL,
- x_orig, y_orig, 0, 0,
- width, height);
-#endif
-
- /*
- * Masking currently only works properly with full-screen shots
- */
- if (include_mask)
- mask_monitors (screenshot, root);
-
-#ifdef HAVE_X11_EXTENSIONS_SHAPE_H
- if (include_border)
- {
- XRectangle *rectangles;
- GdkPixbuf *tmp;
- int rectangle_count, rectangle_order, i;
-
- /* we must use XShape to avoid showing what's under the rounder corners
- * of the WM decoration.
- */
-
- rectangles = XShapeGetRectangles (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
- GDK_WINDOW_XID (window),
- ShapeBounding,
- &rectangle_count,
- &rectangle_order);
- if (rectangles && rectangle_count > 0 && window != root)
- {
- gboolean has_alpha = gdk_pixbuf_get_has_alpha (screenshot);
-
- tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
- gdk_pixbuf_fill (tmp, 0);
-
- for (i = 0; i < rectangle_count; i++)
- {
- gint rec_x, rec_y;
- gint rec_width, rec_height;
- gint y;
-
- rec_x = rectangles[i].x;
- rec_y = rectangles[i].y;
- rec_width = rectangles[i].width;
- rec_height = rectangles[i].height;
-
- if (x_real_orig < 0)
- {
- rec_x += x_real_orig;
- rec_x = MAX(rec_x, 0);
- rec_width += x_real_orig;
- }
-
- if (y_real_orig < 0)
- {
- rec_y += y_real_orig;
- rec_y = MAX(rec_y, 0);
- rec_height += y_real_orig;
- }
-
- if (x_orig + rec_x + rec_width > gdk_screen_width ())
- rec_width = gdk_screen_width () - x_orig - rec_x;
-
- if (y_orig + rec_y + rec_height > gdk_screen_height ())
- rec_height = gdk_screen_height () - y_orig - rec_y;
-
- for (y = rec_y; y < rec_y + rec_height; y++)
- {
- guchar *src_pixels, *dest_pixels;
- gint x;
-
- src_pixels = gdk_pixbuf_get_pixels (screenshot)
- + y * gdk_pixbuf_get_rowstride(screenshot)
- + rec_x * (has_alpha ? 4 : 3);
- dest_pixels = gdk_pixbuf_get_pixels (tmp)
- + y * gdk_pixbuf_get_rowstride (tmp)
- + rec_x * 4;
-
- for (x = 0; x < rec_width; x++)
- {
- *dest_pixels++ = *src_pixels++;
- *dest_pixels++ = *src_pixels++;
- *dest_pixels++ = *src_pixels++;
-
- if (has_alpha)
- *dest_pixels++ = *src_pixels++;
- else
- *dest_pixels++ = 255;
- }
- }
- }
-
- g_object_unref (screenshot);
- screenshot = tmp;
- }
- }
-#endif /* HAVE_X11_EXTENSIONS_SHAPE_H */
-
- /* if we have a selected area, there were by definition no cursor in the
- * screenshot */
- if (include_pointer && !rectangle)
- {
- GdkCursor *cursor;
- GdkPixbuf *cursor_pixbuf;
-
- cursor = gdk_cursor_new_for_display (gdk_display_get_default (), GDK_LEFT_PTR);
- cursor_pixbuf = gdk_cursor_get_image (cursor);
-
- if (cursor_pixbuf != NULL)
- {
- GdkRectangle r1, r2;
- gint cx, cy, xhot, yhot;
-
- gdk_window_get_pointer (window, &cx, &cy, NULL);
- sscanf (gdk_pixbuf_get_option (cursor_pixbuf, "x_hot"), "%d", &xhot);
- sscanf (gdk_pixbuf_get_option (cursor_pixbuf, "y_hot"), "%d", &yhot);
-
- /* in r1 we have the window coordinates */
- r1.x = x_real_orig;
- r1.y = y_real_orig;
- r1.width = real_width;
- r1.height = real_height;
-
- /* in r2 we have the cursor window coordinates */
- r2.x = cx + x_real_orig;
- r2.y = cy + y_real_orig;
- r2.width = gdk_pixbuf_get_width (cursor_pixbuf);
- r2.height = gdk_pixbuf_get_height (cursor_pixbuf);
-
- /* see if the pointer is inside the window */
- if (gdk_rectangle_intersect (&r1, &r2, &r2))
- {
- gdk_pixbuf_composite (cursor_pixbuf, screenshot,
- cx - xhot, cy - yhot,
- r2.width, r2.height,
- cx - xhot, cy - yhot,
- 1.0, 1.0,
- GDK_INTERP_BILINEAR,
- 255);
- }
-
- g_object_unref (cursor_pixbuf);
- gdk_cursor_unref (cursor);
- }
- }
-
- return screenshot;
-}
-
-gchar *
-screenshot_get_window_title (GdkWindow *win)
-{
- gchar *name;
-
- win = gdk_window_get_toplevel (win);
- win = look_for_hint (win, gdk_x11_xatom_to_atom (gdk_x11_get_xatom_by_name ("WM_STATE")));
-
- name = get_utf8_property (win, gdk_x11_xatom_to_atom (gdk_x11_get_xatom_by_name ("_NET_WM_NAME")));
- if (name)
- return name;
-
- /* TODO: maybe we should also look at WM_NAME and WM_CLASS? */
-
- return g_strdup (_("Untitled Window"));
-}
-
-void
-screenshot_show_error_dialog (GtkWindow *parent,
- const gchar *message,
- const gchar *detail)
-{
- GtkWidget *dialog;
-
- g_return_if_fail ((parent == NULL) || (GTK_IS_WINDOW (parent)));
- g_return_if_fail (message != NULL);
-
- dialog = gtk_message_dialog_new (parent,
- GTK_DIALOG_DESTROY_WITH_PARENT,
- GTK_MESSAGE_ERROR,
- GTK_BUTTONS_OK,
- "%s", message);
- gtk_window_set_title (GTK_WINDOW (dialog), "");
-
- if (detail)
- gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
- "%s", detail);
-
- if (parent && gtk_window_get_group (parent))
- gtk_window_group_add_window (gtk_window_get_group (parent), GTK_WINDOW (dialog));
-
- gtk_dialog_run (GTK_DIALOG (dialog));
-
- gtk_widget_destroy (dialog);
-}
-
-void
-screenshot_show_gerror_dialog (GtkWindow *parent,
- const gchar *message,
- GError *error)
-{
- g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
- g_return_if_fail (message != NULL);
- g_return_if_fail (error != NULL);
-
- screenshot_show_error_dialog (parent, message, error->message);
-}