From 0ba61788b4a10eb040d2d4e0814123cc95a4c677 Mon Sep 17 00:00:00 2001 From: Alexander Mikhaylenko Date: Sat, 3 Oct 2020 15:49:15 +0500 Subject: Drop X11 support --- meson.build | 11 - meson_options.txt | 6 - src/cheese-flash.c | 226 ---------------- src/cheese-flash.h | 46 ---- src/meson.build | 5 - src/screenshot-area-selection.c | 231 +--------------- src/screenshot-backend-x11.c | 579 ---------------------------------------- src/screenshot-backend-x11.h | 33 --- src/screenshot-utils.c | 33 +-- 9 files changed, 4 insertions(+), 1166 deletions(-) delete mode 100644 meson_options.txt delete mode 100644 src/cheese-flash.c delete mode 100644 src/cheese-flash.h delete mode 100644 src/screenshot-backend-x11.c delete mode 100644 src/screenshot-backend-x11.h diff --git a/meson.build b/meson.build index 3bfb619..bdc4332 100644 --- a/meson.build +++ b/meson.build @@ -34,8 +34,6 @@ gtk_req_version = '>= 3.12.0' libhandy_req_version = '>= 0.90.0' mathlib_dep = cc.find_library('m', required: false) -x11_dep = dependency('x11', required: get_option ('x11')) -xext_dep = dependency('xext', required: get_option ('x11')) glib_dep = dependency('glib-2.0', version: glib_req_version) gtk_dep = dependency('gtk+-3.0', version: gtk_req_version) libhandy_dep = dependency('libhandy-1', version: libhandy_req_version) @@ -45,15 +43,6 @@ config_h = configuration_data() config_h.set_quoted('VERSION', meson.project_version()) config_h.set_quoted('GETTEXT_PACKAGE', meson.project_name()) -has_x11 = x11_dep.found() and xext_dep.found() -if has_x11 - config_h.set('HAVE_X11', 1) - - if cc.has_header('X11/extensions/shape.h') - config_h.set('HAVE_X11_EXTENSIONS_SHAPE_H', 1) - endif -endif - configure_file(output: 'config.h', configuration: config_h) root_inc = include_directories('.') diff --git a/meson_options.txt b/meson_options.txt deleted file mode 100644 index 7228d35..0000000 --- a/meson_options.txt +++ /dev/null @@ -1,6 +0,0 @@ -option ( - 'x11', - type: 'feature', - description: 'Enable fallback X11 backend', - value: 'auto' -) diff --git a/src/cheese-flash.c b/src/cheese-flash.c deleted file mode 100644 index 3f6e399..0000000 --- a/src/cheese-flash.c +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright © 2008 Alexander “weej” Jones - * Copyright © 2008 Thomas Perl - * Copyright © 2009 daniel g. siegel - * - * Licensed under the GNU General Public License Version 2 - * - * 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, see . - */ - -#include "config.h" - -#ifdef HAVE_X11 - -#include - -#include "cheese-flash.h" - -/** - * SECTION:cheese-flash - * @short_description: Flash the screen, like a real camera flash - * @stability: Unstable - * @include: cheese/cheese-flash.h - * - * #CheeseFlash is a window that you can create and invoke a method "flash" on - * to temporarily flood the screen with white. - */ - -/* How long to hold the flash for, in milliseconds. */ -static const guint FLASH_DURATION = 150; - -/* The factor which defines how much the flash fades per frame */ -static const gdouble FLASH_FADE_FACTOR = 0.95; - -/* How many frames per second */ -static const guint FLASH_ANIMATION_RATE = 120; - -/* When to consider the flash finished so we can stop fading */ -static const gdouble FLASH_LOW_THRESHOLD = 0.01; - -/* - * CheeseFlashPrivate: - * @flash_timeout_tag: signal ID of the timeout to start fading in the flash - * @fade_timeout_tag: signal ID of the timeout to start fading out the flash - * - * Private data for #CheeseFlash. - */ -typedef struct -{ - /*< private >*/ - guint flash_timeout_tag; - guint fade_timeout_tag; - gdouble opacity; -} CheeseFlashPrivate; - -G_DEFINE_TYPE_WITH_PRIVATE (CheeseFlash, cheese_flash, GTK_TYPE_WINDOW) - -static void -cheese_flash_init (CheeseFlash *self) -{ - CheeseFlashPrivate *priv = cheese_flash_get_instance_private (self); - cairo_region_t *input_region; - GtkWindow *window = GTK_WINDOW (self); - const GdkRGBA white = { 1.0, 1.0, 1.0, 1.0 }; - - priv->flash_timeout_tag = 0; - priv->fade_timeout_tag = 0; - priv->opacity = 1.0; - - /* make it so it doesn't look like a window on the desktop (+fullscreen) */ - gtk_window_set_decorated (window, FALSE); - gtk_window_set_skip_taskbar_hint (window, TRUE); - gtk_window_set_skip_pager_hint (window, TRUE); - gtk_window_set_keep_above (window, TRUE); - - /* Don't take focus */ - gtk_window_set_accept_focus (window, FALSE); - gtk_window_set_focus_on_map (window, FALSE); - - /* Make it white */ - gtk_widget_override_background_color (GTK_WIDGET (window), GTK_STATE_NORMAL, - &white); - - /* Don't consume input */ - gtk_widget_realize (GTK_WIDGET (window)); - input_region = cairo_region_create (); - gdk_window_input_shape_combine_region (gtk_widget_get_window (GTK_WIDGET (window)), input_region, 0, 0); - cairo_region_destroy (input_region); -} - -static void -cheese_flash_class_init (CheeseFlashClass *klass) -{ -} - -/* - * cheese_flash_opacity_fade: - * @data: the #CheeseFlash - * - * Fade the flash out. - * - * Returns: %TRUE if the fade was completed, %FALSE if the flash must continue - * to fade - */ -static gboolean -cheese_flash_opacity_fade (gpointer data) -{ - CheeseFlashPrivate *priv; - GtkWidget *flash_window; - - flash_window = GTK_WIDGET (data); - priv = cheese_flash_get_instance_private (CHEESE_FLASH (data)); - - /* exponentially decrease */ - priv->opacity *= FLASH_FADE_FACTOR; - - if (priv->opacity <= FLASH_LOW_THRESHOLD) - { - /* the flasher has finished when we reach the quit value */ - priv->fade_timeout_tag = 0; - gtk_widget_destroy (flash_window); - return G_SOURCE_REMOVE; - } - else - { - gtk_widget_set_opacity (flash_window, priv->opacity); - } - - return G_SOURCE_CONTINUE; -} - -/* - * cheese_flash_start_fade: - * @data: the #CheeseFlash - * - * Add a timeout to start the fade animation. - * - * Returns: %FALSE - */ -static gboolean -cheese_flash_start_fade (gpointer data) -{ - CheeseFlashPrivate *priv = cheese_flash_get_instance_private (CHEESE_FLASH (data)); - GtkWindow *flash_window = GTK_WINDOW (data); - - /* If the screen is non-composited, just destroy and finish up */ - if (!gdk_screen_is_composited (gtk_window_get_screen (flash_window))) - { - gtk_widget_destroy (GTK_WIDGET (flash_window)); - return G_SOURCE_REMOVE; - } - - priv->fade_timeout_tag = g_timeout_add (1000.0 / FLASH_ANIMATION_RATE, cheese_flash_opacity_fade, data); - priv->flash_timeout_tag = 0; - return G_SOURCE_REMOVE; -} - -/** - * cheese_flash_fire: - * @flash: a #CheeseFlash - * @rect: a #GdkRectangle - * - * Fire the flash. - */ -void -cheese_flash_fire (CheeseFlash *flash, - GdkRectangle *rect) -{ - CheeseFlashPrivate *priv; - GtkWindow *flash_window; - - g_return_if_fail (CHEESE_IS_FLASH (flash)); - g_return_if_fail (rect != NULL); - - priv = cheese_flash_get_instance_private (flash); - flash_window = GTK_WINDOW (flash); - - if (priv->flash_timeout_tag > 0) - { - g_source_remove (priv->flash_timeout_tag); - priv->flash_timeout_tag = 0; - } - - if (priv->fade_timeout_tag > 0) - { - g_source_remove (priv->fade_timeout_tag); - priv->fade_timeout_tag = 0; - } - - priv->opacity = 1.0; - - gtk_window_resize (flash_window, rect->width, rect->height); - gtk_window_move (flash_window, rect->x, rect->y); - - gtk_widget_set_opacity (GTK_WIDGET (flash_window), 1); - gtk_widget_show_all (GTK_WIDGET (flash_window)); - priv->flash_timeout_tag = g_timeout_add (FLASH_DURATION, cheese_flash_start_fade, (gpointer) flash); -} - -/** - * cheese_flash_new: - * - * Create a new #CheeseFlash. - * - * Returns: a new #CheeseFlash - */ -CheeseFlash * -cheese_flash_new (void) -{ - return g_object_new (CHEESE_TYPE_FLASH, - "type", GTK_WINDOW_POPUP, - NULL); -} - -#endif diff --git a/src/cheese-flash.h b/src/cheese-flash.h deleted file mode 100644 index 09385fb..0000000 --- a/src/cheese-flash.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright © 2008 Alexander “weej” Jones - * - * Licensed under the GNU General Public License Version 2 - * - * 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, see . - */ - -#pragma once - -#include -#include - -G_BEGIN_DECLS - -/** - * CheeseFlash: - * - * Use the accessor functions below. - */ -struct _CheeseFlash -{ - /*< private >*/ - GtkWindow parent_instance; - void *unused; -}; - -#define CHEESE_TYPE_FLASH (cheese_flash_get_type ()) -G_DECLARE_FINAL_TYPE (CheeseFlash, cheese_flash, CHEESE, FLASH, GtkWindow) - -CheeseFlash *cheese_flash_new (void); -void cheese_flash_fire (CheeseFlash *flash, - GdkRectangle *rect); - -G_END_DECLS diff --git a/src/meson.build b/src/meson.build index 91b97e7..212e9bf 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,13 +1,10 @@ sources = [ 'gnome-screenshot.c', - 'cheese-flash.c', - 'screenshot-application.c', 'screenshot-area-selection.c', 'screenshot-backend.c', 'screenshot-backend-shell.c', - 'screenshot-backend-x11.c', 'screenshot-config.c', 'screenshot-dialog.c', 'screenshot-filename-builder.c', @@ -22,8 +19,6 @@ include_directories = [ dependencies = [ mathlib_dep, - x11_dep, - xext_dep, glib_dep, gtk_dep, libhandy_dep, diff --git a/src/screenshot-area-selection.c b/src/screenshot-area-selection.c index 224d93d..eae754f 100644 --- a/src/screenshot-area-selection.c +++ b/src/screenshot-area-selection.c @@ -24,183 +24,6 @@ #include "screenshot-area-selection.h" -typedef struct { - GdkRectangle rect; - gboolean button_pressed; - GtkWidget *window; - - gboolean aborted; -} 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) - { - cairo_region_t *region; - cairo_rectangle_int_t region_rect = { - 0, 0, - draw_rect.width, draw_rect.height - }; - - region = cairo_region_create_rectangle (®ion_rect); - region_rect.x++; - region_rect.y++; - region_rect.width -= 2; - region_rect.height -= 2; - cairo_region_subtract_rectangle (region, ®ion_rect); - - gdk_window_shape_combine_region (gdkwindow, region, 0, 0); - - cairo_region_destroy (region); - } - 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); - - if (data->rect.width == 0 || data->rect.height == 0) - data->aborted = TRUE; - - 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; - data->aborted = TRUE; - - gtk_main_quit (); - } - - return TRUE; -} - -static gboolean -select_window_draw (GtkWidget *window, cairo_t *cr, gpointer unused) -{ - GtkStyleContext *style; - - style = gtk_widget_get_style_context (window); - - if (gtk_widget_get_app_paintable (window)) - { - cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgba (cr, 0, 0, 0, 0); - cairo_paint (cr); - - gtk_style_context_save (style); - gtk_style_context_add_class (style, GTK_STYLE_CLASS_RUBBERBAND); - - gtk_render_background (style, cr, - 0, 0, - gtk_widget_get_allocated_width (window), - gtk_widget_get_allocated_height (window)); - gtk_render_frame (style, cr, - 0, 0, - gtk_widget_get_allocated_width (window), - gtk_widget_get_allocated_height (window)); - - gtk_style_context_restore (style); - } - - return TRUE; -} - -static GtkWidget * -create_select_window (void) -{ - GtkWidget *window; - GdkScreen *screen; - GdkVisual *visual; - - screen = gdk_screen_get_default (); - visual = gdk_screen_get_rgba_visual (screen); - - window = gtk_window_new (GTK_WINDOW_POPUP); - if (gdk_screen_is_composited (screen) && visual) - { - gtk_widget_set_visual (window, visual); - gtk_widget_set_app_paintable (window, TRUE); - } - - g_signal_connect (window, "draw", G_CALLBACK (select_window_draw), NULL); - - 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; @@ -223,56 +46,6 @@ emit_select_callback_in_idle (gpointer user_data) return FALSE; } -static void -screenshot_select_area_x11_async (CallbackData *cb_data) -{ - g_autoptr(GdkCursor) cursor = NULL; - GdkDisplay *display; - select_area_filter_data data; - GdkSeat *seat; - - data.rect.x = 0; - data.rect.y = 0; - data.rect.width = 0; - data.rect.height = 0; - data.button_pressed = FALSE; - data.aborted = FALSE; - data.window = create_select_window(); - - 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); - - display = gtk_widget_get_display (data.window); - cursor = gdk_cursor_new_for_display (display, GDK_CROSSHAIR); - seat = gdk_display_get_default_seat (display); - - gdk_seat_grab (seat, - gtk_widget_get_window (data.window), - GDK_SEAT_CAPABILITY_ALL, - FALSE, - cursor, - NULL, - NULL, - NULL); - - gtk_main (); - - gdk_seat_ungrab (seat); - - gtk_widget_destroy (data.window); - - cb_data->aborted = data.aborted; - 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 void select_area_done (GObject *source_object, GAsyncResult *res, @@ -292,10 +65,8 @@ select_area_done (GObject *source_object, return; } - g_message ("Unable to select area using GNOME Shell's builtin screenshot " - "interface, resorting to fallback X11."); + g_message ("Unable to select area."); - screenshot_select_area_x11_async (cb_data); return; } diff --git a/src/screenshot-backend-x11.c b/src/screenshot-backend-x11.c deleted file mode 100644 index 990e715..0000000 --- a/src/screenshot-backend-x11.c +++ /dev/null @@ -1,579 +0,0 @@ -/* screenshot-backend-x11.c - Fallback X11 backend - * - * Copyright (C) 2001-2006 Jonathan Blandford - * Copyright (C) 2008 Cosimo Cecchi - * Copyright (C) 2020 Alexander Mikhaylenko - * - * 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 Street, Fifth Floor, - */ - -#include "config.h" - -#ifdef HAVE_X11 - -#include "screenshot-backend-x11.h" - -#include "screenshot-config.h" - -#include "cheese-flash.h" - -#include - -#ifdef HAVE_X11_EXTENSIONS_SHAPE_H -#include -#endif - -struct _ScreenshotBackendX11 -{ - GObject parent_instance; -}; - -static void screenshot_backend_x11_backend_init (ScreenshotBackendInterface *iface); - -G_DEFINE_TYPE_WITH_CODE (ScreenshotBackendX11, screenshot_backend_x11, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (SCREENSHOT_TYPE_BACKEND, screenshot_backend_x11_backend_init)) - -static GdkWindow * -screenshot_find_active_window (void) -{ - GdkWindow *window; - GdkScreen *default_screen; - -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - default_screen = gdk_screen_get_default (); - window = gdk_screen_get_active_window (default_screen); -G_GNUC_END_IGNORE_DEPRECATIONS - - 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; -} - -static Window -find_wm_window (GdkWindow *window) -{ - Window xid, root, parent, *children; - unsigned int nchildren; - - if (window == gdk_get_default_root_window ()) - return None; - - xid = GDK_WINDOW_XID (window); - - 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); -} - -static cairo_region_t * -make_region_with_monitors (GdkDisplay *display) -{ - cairo_region_t *region; - int num_monitors; - int i; - - num_monitors = gdk_display_get_n_monitors (display); - - region = cairo_region_create (); - - for (i = 0; i < num_monitors; i++) - { - GdkMonitor *monitor; - GdkRectangle rect; - - monitor = gdk_display_get_monitor (display, i); - gdk_monitor_get_geometry (monitor, &rect); - cairo_region_union_rectangle (region, &rect); - } - - 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 -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); - - 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++) - { - cairo_rectangle_int_t rect, dest; - - cairo_region_get_rectangle (region, i, &rect); - if (gdk_rectangle_intersect (&rect, &pixbuf_rect, &dest)) - blank_rectangle_in_pixbuf (pixbuf, &dest); - } -} - -/* 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) -{ - GdkDisplay *display; - cairo_region_t *region_with_monitors; - cairo_region_t *invisible_region; - cairo_rectangle_int_t rect; - - display = gdk_window_get_display (root_window); - - region_with_monitors = make_region_with_monitors (display); - - rect.x = 0; - rect.y = 0; - rect.width = gdk_pixbuf_get_width (pixbuf); - rect.height = gdk_pixbuf_get_height (pixbuf); - - 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); -} - -static void -screenshot_fallback_get_window_rect_coords (GdkWindow *window, - GdkRectangle *real_coordinates_out, - GdkRectangle *screenshot_coordinates_out) -{ - gint x_orig, y_orig; - gint width, height; - GdkRectangle real_coordinates; - - gdk_window_get_frame_extents (window, &real_coordinates); - - x_orig = real_coordinates.x; - y_orig = real_coordinates.y; - width = real_coordinates.width; - height = real_coordinates.height; - - if (real_coordinates_out != NULL) - *real_coordinates_out = real_coordinates; - - if (x_orig < 0) - { - width = width + x_orig; - x_orig = 0; - } - - if (y_orig < 0) - { - height = height + y_orig; - y_orig = 0; - } - -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - 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; -G_GNUC_END_IGNORE_DEPRECATIONS - - if (screenshot_coordinates_out != NULL) - { - screenshot_coordinates_out->x = x_orig; - screenshot_coordinates_out->y = y_orig; - screenshot_coordinates_out->width = width; - screenshot_coordinates_out->height = height; - } -} - -static void -screenshot_fallback_fire_flash (GdkWindow *window, - GdkRectangle *rectangle) -{ - GdkRectangle rect; - CheeseFlash *flash = NULL; - - if (rectangle != NULL) - rect = *rectangle; - else - screenshot_fallback_get_window_rect_coords (window, NULL, &rect); - - flash = cheese_flash_new (); - cheese_flash_fire (flash, &rect); -} - -GdkWindow * -do_find_current_window (void) -{ - GdkWindow *current_window; - GdkDevice *device; - GdkSeat *seat; - - current_window = screenshot_find_active_window (); - seat = gdk_display_get_default_seat (gdk_display_get_default ()); - device = gdk_seat_get_pointer (seat); - - /* If there's no active window, we fall back to returning the - * window that the cursor is in. - */ - if (!current_window) - current_window = gdk_device_get_window_at_position (device, NULL, NULL); - - if (current_window) - { - if (screenshot_window_is_desktop (current_window)) - /* if the current window is the desktop (e.g. nautilus), 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; -} - -static GdkWindow * -screenshot_fallback_find_current_window (void) -{ - GdkWindow *window = NULL; - - if (screenshot_config->take_window_shot) - { - window = do_find_current_window (); - - if (window == NULL) - screenshot_config->take_window_shot = FALSE; - } - - if (window == NULL) - window = gdk_get_default_root_window (); - - return window; -} - -static GdkPixbuf * -screenshot_backend_x11_get_pixbuf (ScreenshotBackend *backend, - GdkRectangle *rectangle) -{ - GdkWindow *root, *wm_window = NULL; - GdkPixbuf *screenshot = NULL; - GdkRectangle real_coords, screenshot_coords; - Window wm; - GtkBorder frame_offset = { 0, 0, 0, 0 }; - GdkWindow *window; - - window = screenshot_fallback_find_current_window (); - - screenshot_fallback_get_window_rect_coords (window, - &real_coords, - &screenshot_coords); - - wm = find_wm_window (window); - if (wm != None) - { - GdkRectangle wm_real_coords; - - wm_window = gdk_x11_window_foreign_new_for_display - (gdk_window_get_display (window), wm); - - screenshot_fallback_get_window_rect_coords (wm_window, - &wm_real_coords, - NULL); - - frame_offset.left = (gdouble) (real_coords.x - wm_real_coords.x); - frame_offset.top = (gdouble) (real_coords.y - wm_real_coords.y); - frame_offset.right = (gdouble) (wm_real_coords.width - real_coords.width - frame_offset.left); - frame_offset.bottom = (gdouble) (wm_real_coords.height - real_coords.height - frame_offset.top); - } - - if (rectangle) - { - screenshot_coords.x = rectangle->x - screenshot_coords.x; - screenshot_coords.y = rectangle->y - screenshot_coords.y; - screenshot_coords.width = rectangle->width; - screenshot_coords.height = rectangle->height; - } - - root = gdk_get_default_root_window (); - screenshot = gdk_pixbuf_get_from_window (root, - screenshot_coords.x, screenshot_coords.y, - screenshot_coords.width, screenshot_coords.height); - - if (!screenshot_config->take_window_shot && - !screenshot_config->take_area_shot) - mask_monitors (screenshot, root); - -#ifdef HAVE_X11_EXTENSIONS_SHAPE_H - if (wm != None) - { - XRectangle *rectangles; - 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()), - wm, - ShapeBounding, - &rectangle_count, - &rectangle_order); - if (rectangles && rectangle_count > 0) - { - int scale_factor = gdk_window_get_scale_factor (wm_window); - gboolean has_alpha = gdk_pixbuf_get_has_alpha (screenshot); - GdkPixbuf *tmp = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, - gdk_pixbuf_get_width (screenshot), - gdk_pixbuf_get_height (screenshot)); - gdk_pixbuf_fill (tmp, 0); - - for (i = 0; i < rectangle_count; i++) - { - gint rec_x, rec_y; - gint rec_width, rec_height; - gint y; - - /* If we're using invisible borders, the ShapeBounding might not - * have the same size as the frame extents, as it would include the - * areas for the invisible borders themselves. - * In that case, trim every rectangle we get by the offset between the - * WM window size and the frame extents. - * - * Note that the XShape values are in actual pixels, whereas the GDK - * ones are in display pixels (i.e. scaled), so we need to apply the - * scale factor to the former to use display pixels for all our math. - */ - rec_x = rectangles[i].x / scale_factor; - rec_y = rectangles[i].y / scale_factor; - rec_width = rectangles[i].width / scale_factor - (frame_offset.left + frame_offset.right); - rec_height = rectangles[i].height / scale_factor - (frame_offset.top + frame_offset.bottom); - - if (real_coords.x < 0) - { - rec_x += real_coords.x; - rec_x = MAX(rec_x, 0); - rec_width += real_coords.x; - } - - if (real_coords.y < 0) - { - rec_y += real_coords.y; - rec_y = MAX(rec_y, 0); - rec_height += real_coords.y; - } - -G_GNUC_BEGIN_IGNORE_DEPRECATIONS - if (screenshot_coords.x + rec_x + rec_width > gdk_screen_width ()) - rec_width = gdk_screen_width () - screenshot_coords.x - rec_x; - - if (screenshot_coords.y + rec_y + rec_height > gdk_screen_height ()) - rec_height = gdk_screen_height () - screenshot_coords.y - rec_y; -G_GNUC_END_IGNORE_DEPRECATIONS - - /* Undo the scale factor in order to copy the pixbuf data pixel-wise */ - for (y = rec_y * scale_factor; y < (rec_y + rec_height) * scale_factor; y++) - { - guchar *src_pixels, *dest_pixels; - gint x; - - src_pixels = gdk_pixbuf_get_pixels (screenshot) - + y * gdk_pixbuf_get_rowstride(screenshot) - + rec_x * scale_factor * (has_alpha ? 4 : 3); - dest_pixels = gdk_pixbuf_get_pixels (tmp) - + y * gdk_pixbuf_get_rowstride (tmp) - + rec_x * scale_factor * 4; - - for (x = 0; x < rec_width * scale_factor; 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_set_object (&screenshot, tmp); - - XFree (rectangles); - } - } -#endif /* HAVE_X11_EXTENSIONS_SHAPE_H */ - - /* if we have a selected area, there were by definition no cursor in the - * screenshot */ - if (screenshot_config->include_pointer && !rectangle) - { - g_autoptr(GdkCursor) cursor = NULL; - g_autoptr(GdkPixbuf) cursor_pixbuf = NULL; - - cursor = gdk_cursor_new_for_display (gdk_display_get_default (), GDK_LEFT_PTR); - cursor_pixbuf = gdk_cursor_get_image (cursor); - - if (cursor_pixbuf != NULL) - { - GdkSeat *seat; - GdkDevice *device; - GdkRectangle rect; - gint cx, cy, xhot, yhot; - - seat = gdk_display_get_default_seat (gdk_display_get_default ()); - device = gdk_seat_get_pointer (seat); - - if (wm_window != NULL) - gdk_window_get_device_position (wm_window, device, - &cx, &cy, NULL); - else - gdk_window_get_device_position (window, device, - &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 rect we have the cursor window coordinates */ - rect.x = cx + real_coords.x; - rect.y = cy + real_coords.y; - rect.width = gdk_pixbuf_get_width (cursor_pixbuf); - rect.height = gdk_pixbuf_get_height (cursor_pixbuf); - - /* see if the pointer is inside the window */ - if (gdk_rectangle_intersect (&real_coords, &rect, &rect)) - { - gint cursor_x, cursor_y; - - cursor_x = cx - xhot - frame_offset.left; - cursor_y = cy - yhot - frame_offset.top; - gdk_pixbuf_composite (cursor_pixbuf, screenshot, - cursor_x, cursor_y, - rect.width, rect.height, - cursor_x, cursor_y, - 1.0, 1.0, - GDK_INTERP_BILINEAR, - 255); - } - } - } - - screenshot_fallback_fire_flash (window, rectangle); - - return screenshot; -} - -static void -screenshot_backend_x11_class_init (ScreenshotBackendX11Class *klass) -{ -} - -static void -screenshot_backend_x11_init (ScreenshotBackendX11 *self) -{ -} - -static void -screenshot_backend_x11_backend_init (ScreenshotBackendInterface *iface) -{ - iface->get_pixbuf = screenshot_backend_x11_get_pixbuf; -} - -ScreenshotBackend * -screenshot_backend_x11_new (void) -{ - return g_object_new (SCREENSHOT_TYPE_BACKEND_X11, NULL); -} - -#endif /* HAVE_X11 */ diff --git a/src/screenshot-backend-x11.h b/src/screenshot-backend-x11.h deleted file mode 100644 index 3b52b1e..0000000 --- a/src/screenshot-backend-x11.h +++ /dev/null @@ -1,33 +0,0 @@ -/* screenshot-backend-x11.h - Fallback X11 backend - * - * Copyright (C) 2020 Alexander Mikhaylenko - * - * 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 Street, Fifth Floor, - */ - -#pragma once - -#include -#include "screenshot-backend.h" - -G_BEGIN_DECLS - -#define SCREENSHOT_TYPE_BACKEND_X11 (screenshot_backend_x11_get_type()) - -G_DECLARE_FINAL_TYPE (ScreenshotBackendX11, screenshot_backend_x11, SCREENSHOT, BACKEND_X11, GObject) - -ScreenshotBackend *screenshot_backend_x11_new (void); - -G_END_DECLS diff --git a/src/screenshot-utils.c b/src/screenshot-utils.c index 09ff4af..9279e94 100644 --- a/src/screenshot-utils.c +++ b/src/screenshot-utils.c @@ -29,10 +29,6 @@ #include "screenshot-backend-shell.h" -#ifdef HAVE_X11 -#include "screenshot-backend-x11.h" -#endif - void screenshot_play_sound_effect (const gchar *event_id, const gchar *event_desc) @@ -69,36 +65,13 @@ GdkPixbuf * screenshot_get_pixbuf (GdkRectangle *rectangle) { GdkPixbuf *screenshot = NULL; - gboolean force_fallback = FALSE; g_autoptr (ScreenshotBackend) backend = NULL; -#ifdef HAVE_X11 - force_fallback = g_getenv ("GNOME_SCREENSHOT_FORCE_FALLBACK") != NULL; -#endif - - if (!force_fallback) - { - backend = screenshot_backend_shell_new (); - screenshot = screenshot_backend_get_pixbuf (backend, rectangle); - if (!screenshot) -#ifdef HAVE_X11 - g_message ("Unable to use GNOME Shell's builtin screenshot interface, " - "resorting to fallback X11."); -#else - g_message ("Unable to use GNOME Shell's builtin screenshot interface."); -#endif - } - else - g_message ("Using fallback X11 as requested"); + backend = screenshot_backend_shell_new (); + screenshot = screenshot_backend_get_pixbuf (backend, rectangle); -#ifdef HAVE_X11 if (!screenshot) - { - g_clear_object (&backend); - backend = screenshot_backend_x11_new (); - screenshot = screenshot_backend_get_pixbuf (backend, rectangle); - } -#endif + g_message ("Unable to use GNOME Shell's builtin screenshot interface."); return screenshot; } -- cgit v1.2.1