[gnome-flashback] screenshot: fix missing cursor with CSD windows



commit f70b5d1e7302b765b06edddb03462be19d32157f
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Tue Oct 3 23:29:39 2017 +0300

    screenshot: fix missing cursor with CSD windows
    
    https://bugzilla.gnome.org/show_bug.cgi?id=780394

 gnome-flashback/libscreenshot/gf-screenshot.c |  210 +++++++++++++++----------
 1 files changed, 128 insertions(+), 82 deletions(-)
---
diff --git a/gnome-flashback/libscreenshot/gf-screenshot.c b/gnome-flashback/libscreenshot/gf-screenshot.c
index 3491362..7ab2558 100644
--- a/gnome-flashback/libscreenshot/gf-screenshot.c
+++ b/gnome-flashback/libscreenshot/gf-screenshot.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 Alberts Muktupāvels
+ * Copyright (C) 2015-2017 Alberts Muktupāvels
  *
  * 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
@@ -103,7 +103,9 @@ pixels_to_pixbuf (gulong *pixels,
 }
 
 static GdkPixbuf *
-get_cursor_pixbuf (GdkDisplay *display)
+get_cursor_pixbuf (GdkDisplay *display,
+                   gint       *xhot,
+                   gint       *yhot)
 {
   Display *xdisplay;
   gint event_base;
@@ -123,20 +125,126 @@ get_cursor_pixbuf (GdkDisplay *display)
 
   pixbuf = pixels_to_pixbuf (image->pixels, image->width, image->height);
 
-  if (pixbuf)
+  *xhot = image->xhot;
+  *yhot = image->yhot;
+
+  XFree (image);
+
+  return pixbuf;
+}
+
+static gint
+get_window_scaling_factor (void)
+{
+  GValue gvalue = G_VALUE_INIT;
+  GdkScreen *screen;
+
+  g_value_init (&gvalue, G_TYPE_INT);
+
+  screen = gdk_screen_get_default ();
+  if (gdk_screen_get_setting (screen, "gdk-window-scaling-factor", &gvalue))
+    return g_value_get_int (&gvalue);
+
+  return 1;
+}
+
+static void
+screenshot_add_cursor (GdkPixbuf      *pixbuf,
+                       ScreenshotType  type,
+                       gboolean        include_cursor,
+                       GdkWindow      *window,
+                       gint            frame_offset_x,
+                       gint            frame_offset_y)
+{
+  GdkDisplay *display;
+  GdkPixbuf *cursor_pixbuf;
+  gint scale;
+  gint xhot;
+  gint yhot;
+
+  /* If we have a selected area, there were by definition no cursor
+   * in the screenshot.
+   */
+  if (!include_cursor || type == SCREENSHOT_AREA)
+    return;
+
+  display = gdk_display_get_default ();
+  cursor_pixbuf = get_cursor_pixbuf (display, &xhot, &yhot);
+  scale = get_window_scaling_factor ();
+
+  if (cursor_pixbuf == NULL)
     {
-      gchar hot[6];
+      GdkCursor *cursor;
+      cairo_surface_t *surface;
+      gdouble x_hot;
+      gdouble y_hot;
+      gint width;
+      gint height;
+
+      cursor = gdk_cursor_new_for_display (display, GDK_LEFT_PTR);
 
-      g_ascii_dtostr (hot, 6, (gdouble) image->xhot);
-      gdk_pixbuf_set_option (pixbuf, "x_hot", hot);
+      if (cursor == NULL)
+        return;
 
-      g_ascii_dtostr (hot, 6, (gdouble) image->yhot);
-      gdk_pixbuf_set_option (pixbuf, "y_hot", hot);
+      surface = gdk_cursor_get_surface (cursor, &x_hot, &y_hot);
+      g_object_unref (cursor);
+
+      if (surface == NULL)
+        return;
+
+      width = cairo_image_surface_get_width (surface);
+      height = cairo_image_surface_get_height (surface);
+
+      cursor_pixbuf = gdk_pixbuf_get_from_surface (surface, 0, 0, width, height);
+      cairo_surface_destroy (surface);
+
+      xhot = x_hot * scale;
+      yhot = y_hot * scale;
     }
 
-  XFree (image);
+  if (cursor_pixbuf != NULL)
+    {
+      GdkSeat *seat;
+      GdkDevice *device;
+      gdouble cx;
+      gdouble cy;
+      GdkRectangle pixbuf_rect;
+      GdkRectangle cursor_rect;
 
-  return pixbuf;
+      seat = gdk_display_get_default_seat (display);
+      device = gdk_seat_get_pointer (seat);
+
+      gdk_window_get_device_position_double (window, device, &cx, &cy, NULL);
+
+      pixbuf_rect.x = pixbuf_rect.y = 0;
+      pixbuf_rect.width = gdk_pixbuf_get_width (pixbuf);
+      pixbuf_rect.height = gdk_pixbuf_get_height (pixbuf);
+
+      cursor_rect.x = cx * scale - xhot - frame_offset_x;
+      cursor_rect.y = cy * scale - yhot - frame_offset_y;
+      cursor_rect.width = gdk_pixbuf_get_width (cursor_pixbuf);
+      cursor_rect.height = gdk_pixbuf_get_height (cursor_pixbuf);
+
+      /* see if the pointer is inside the window */
+      if (gdk_rectangle_intersect (&pixbuf_rect, &cursor_rect, &cursor_rect))
+        {
+          gint cursor_x;
+          gint cursor_y;
+
+          cursor_x = cx * scale - xhot - frame_offset_x;
+          cursor_y = cy * scale - yhot - frame_offset_y;
+
+          gdk_pixbuf_composite (cursor_pixbuf, pixbuf,
+                                cursor_rect.x, cursor_rect.y,
+                                cursor_rect.width, cursor_rect.height,
+                                cursor_x, cursor_y,
+                                1.0, 1.0,
+                                GDK_INTERP_BILINEAR,
+                                255);
+        }
+
+      g_object_unref (cursor_pixbuf);
+    }
 }
 
 static gchar *
@@ -600,6 +708,7 @@ take_screenshot_real (GfScreenshot    *screenshot,
 {
   GdkDisplay *display;
   GdkWindow *window;
+  gint scale;
   GtkBorder extents;
   GdkRectangle real;
   GdkRectangle s;
@@ -615,6 +724,8 @@ take_screenshot_real (GfScreenshot    *screenshot,
   if (window == NULL)
     return FALSE;
 
+  scale = get_window_scaling_factor ();
+
   if (type == SCREENSHOT_WINDOW && get_gtk_frame_extents (window, &extents))
     {
       gdk_window_get_frame_extents (window, &real);
@@ -635,6 +746,9 @@ take_screenshot_real (GfScreenshot    *screenshot,
       pixbuf = gdk_pixbuf_get_from_window (window, real.x, real.y,
                                            real.width, real.height);
 
+      screenshot_add_cursor (pixbuf, type, include_cursor, window,
+                             real.x * scale, real.y *scale);
+
       gdk_window_get_frame_extents (window, &real);
 
       *x = real.x;
@@ -786,78 +900,10 @@ take_screenshot_real (GfScreenshot    *screenshot,
         }
     }
 
-  /* If we have a selected area, there were by definition no cursor in the
-   * screenshot. */
-  if (include_cursor && type != SCREENSHOT_AREA)
-    {
-      GdkPixbuf *cursor_pixbuf;
-
-      cursor_pixbuf = get_cursor_pixbuf (display);
-
-      if (cursor_pixbuf == NULL)
-        {
-          GdkCursor *cursor;
-
-          cursor = gdk_cursor_new_for_display (display, GDK_LEFT_PTR);
-          cursor_pixbuf = gdk_cursor_get_image (cursor);
-
-          g_clear_object (&cursor);
-        }
-
-      if (cursor_pixbuf != NULL)
-        {
-          GdkSeat *seat;
-          GdkDevice *device;
-          GdkRectangle pixbuf_rect;
-          GdkRectangle cursor_rect;
-          gint cx;
-          gint cy;
-          gint xhot;
-          gint yhot;
-
-          seat = gdk_display_get_default_seat (display);
-          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);
-
-          pixbuf_rect.x = 0;
-          pixbuf_rect.y = 0;
-          pixbuf_rect.width = gdk_pixbuf_get_width (pixbuf);
-          pixbuf_rect.height = gdk_pixbuf_get_height (pixbuf);
-
-          /* in rect we have the cursor window coordinates */
-          cursor_rect.x = cx - xhot - frame_offset.left;
-          cursor_rect.y = cy - yhot - frame_offset.top;
-          cursor_rect.width = gdk_pixbuf_get_width (cursor_pixbuf);
-          cursor_rect.height = gdk_pixbuf_get_height (cursor_pixbuf);
-
-          /* see if the pointer is inside the window */
-          if (gdk_rectangle_intersect (&pixbuf_rect, &cursor_rect, &cursor_rect))
-            {
-              gint cursor_x;
-              gint cursor_y;
-
-              cursor_x = cx - xhot - frame_offset.left;
-              cursor_y = cy - yhot - frame_offset.top;
-
-              gdk_pixbuf_composite (cursor_pixbuf, pixbuf,
-                                    cursor_rect.x, cursor_rect.y,
-                                    cursor_rect.width, cursor_rect.height,
-                                    cursor_x, cursor_y,
-                                    1.0, 1.0,
-                                    GDK_INTERP_BILINEAR,
-                                    255);
-            }
-        }
-
-      g_clear_object (&cursor_pixbuf);
-    }
+  screenshot_add_cursor (pixbuf, type, include_cursor,
+                         wm_window != NULL ? wm_window : window,
+                         frame_offset.left * scale,
+                         frame_offset.top * scale);
 
   if (type == SCREENSHOT_WINDOW)
     {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]