[gtk+/wip/window-scales: 14/16] x11: Initial cut at supporting window scaling for X11



commit 59d2316083a87cbf27e4dc632e89f097f0a06207
Author: Alexander Larsson <alexl redhat com>
Date:   Thu Jun 20 11:40:07 2013 +0200

    x11: Initial cut at supporting window scaling for X11
    
    If you set GDK_SCALE=2 in the environment then all windows will be
    scaled by 2. Its not an ideal solution as it doesn't handle
    multi-monitors at different scales, and only affects gtk apps.
    But it is a good starting points and will help a lot on HiDPI
    laptops.

 gdk/x11/gdkdevice-core-x11.c        |   35 +++++--
 gdk/x11/gdkdevice-xi2.c             |   21 +++--
 gdk/x11/gdkdevicemanager-core-x11.c |   54 ++++++-----
 gdk/x11/gdkdevicemanager-xi2.c      |   65 +++++++-----
 gdk/x11/gdkdisplay-x11.c            |   58 +++++++----
 gdk/x11/gdkdnd-x11.c                |   35 +++++--
 gdk/x11/gdkgeometry-x11.c           |   20 ++--
 gdk/x11/gdkmain-x11.c               |    9 +-
 gdk/x11/gdkprivate-x11.h            |    2 +
 gdk/x11/gdkscreen-x11.c             |   49 ++++++++-
 gdk/x11/gdkscreen-x11.h             |    2 +
 gdk/x11/gdkwindow-x11.c             |  196 +++++++++++++++++++++++------------
 gdk/x11/gdkwindow-x11.h             |    2 +
 13 files changed, 360 insertions(+), 188 deletions(-)
---
diff --git a/gdk/x11/gdkdevice-core-x11.c b/gdk/x11/gdkdevice-core-x11.c
index 0c6ed7f..e21339d 100644
--- a/gdk/x11/gdkdevice-core-x11.c
+++ b/gdk/x11/gdkdevice-core-x11.c
@@ -135,10 +135,12 @@ gdk_x11_device_core_get_history (GdkDevice      *device,
   XTimeCoord *xcoords;
   GdkTimeCoord **coords;
   GdkWindow *impl_window;
+  GdkWindowImplX11 *impl;
   int tmp_n_events;
   int i, j;
 
   impl_window = _gdk_window_get_impl_window (window);
+  impl =  GDK_WINDOW_IMPL_X11 (impl_window->impl);
   xcoords = XGetMotionEvents (GDK_WINDOW_XDISPLAY (window),
                               GDK_WINDOW_XID (impl_window),
                               start, stop, &tmp_n_events);
@@ -149,11 +151,13 @@ gdk_x11_device_core_get_history (GdkDevice      *device,
 
   for (i = 0, j = 0; i < tmp_n_events; i++)
     {
-      if (impl_coord_in_window (window, xcoords[i].x, xcoords[i].y))
+      if (impl_coord_in_window (window,
+                                xcoords[i].x / impl->window_scale,
+                                xcoords[i].y / impl->window_scale))
         {
           coords[j]->time = xcoords[i].time;
-          coords[j]->axes[0] = xcoords[i].x - window->abs_x;
-          coords[j]->axes[1] = xcoords[i].y - window->abs_y;
+          coords[j]->axes[0] = (double)xcoords[i].x / impl->window_scale - window->abs_x;
+          coords[j]->axes[1] = (double)xcoords[i].y / impl->window_scale - window->abs_y;
           j++;
         }
     }
@@ -194,6 +198,7 @@ gdk_x11_device_core_get_state (GdkDevice       *device,
 {
   gint x_int, y_int;
 
+  /* TODO: This rounds the coords, should use double */
   gdk_window_get_device_position (window, device, &x_int, &y_int, mask);
 
   if (axes)
@@ -232,7 +237,9 @@ gdk_x11_device_core_warp (GdkDevice *device,
   xdisplay = GDK_DISPLAY_XDISPLAY (gdk_device_get_display (device));
   dest = GDK_WINDOW_XID (gdk_screen_get_root_window (screen));
 
-  XWarpPointer (xdisplay, None, dest, 0, 0, 0, 0, x, y);
+  XWarpPointer (xdisplay, None, dest, 0, 0, 0, 0,
+                x * GDK_X11_SCREEN (screen)->window_scale,
+                y * GDK_X11_SCREEN (screen)->window_scale);
 }
 
 static void
@@ -246,6 +253,7 @@ gdk_x11_device_core_query_state (GdkDevice        *device,
                                  gint             *win_y,
                                  GdkModifierType  *mask)
 {
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
   GdkDisplay *display;
   GdkScreen *default_screen;
   Window xroot_window, xchild_window;
@@ -291,16 +299,16 @@ gdk_x11_device_core_query_state (GdkDevice        *device,
     *child_window = gdk_x11_window_lookup_for_display (display, xchild_window);
 
   if (root_x)
-    *root_x = xroot_x;
+    *root_x = xroot_x / impl->window_scale;
 
   if (root_y)
-    *root_y = xroot_y;
+    *root_y = xroot_y / impl->window_scale;
 
   if (win_x)
-    *win_x = xwin_x;
+    *win_x = xwin_x / impl->window_scale;
 
   if (win_y)
-    *win_y = xwin_y;
+    *win_y = xwin_y / impl->window_scale;
 
   if (mask)
     *mask = xmask;
@@ -413,6 +421,7 @@ gdk_x11_device_core_window_at_position (GdkDevice       *device,
                                         GdkModifierType *mask,
                                         gboolean         get_toplevel)
 {
+  GdkWindowImplX11 *impl;
   GdkDisplay *display;
   GdkScreen *screen;
   Display *xdisplay;
@@ -464,6 +473,7 @@ gdk_x11_device_core_window_at_position (GdkDevice       *device,
       for (list = toplevels; list != NULL; list = g_list_next (list))
         {
           window = GDK_WINDOW (list->data);
+          impl = GDK_WINDOW_IMPL_X11 (window->impl);
           xwindow = GDK_WINDOW_XID (window);
           gdk_x11_display_error_trap_push (display);
           XQueryPointer (xdisplay, xwindow,
@@ -479,7 +489,7 @@ gdk_x11_device_core_window_at_position (GdkDevice       *device,
               break;
             }
           gdk_window_get_geometry (window, NULL, NULL, &width, &height);
-          if (winx >= 0 && winy >= 0 && winx < width && winy < height)
+          if (winx >= 0 && winy >= 0 && winx < width * impl->window_scale && winy < height * 
impl->window_scale)
             {
               /* A childless toplevel, or below another window? */
               XSetWindowAttributes attributes;
@@ -532,12 +542,15 @@ gdk_x11_device_core_window_at_position (GdkDevice       *device,
   gdk_x11_display_ungrab (display);
 
   window = gdk_x11_window_lookup_for_display (display, last);
+  impl = NULL;
+  if (window)
+    impl = GDK_WINDOW_IMPL_X11 (window->impl);
 
   if (win_x)
-    *win_x = (window) ? xwin_x : -1;
+    *win_x = (window) ? xwin_x / impl->window_scale : -1;
 
   if (win_y)
-    *win_y = (window) ? xwin_y : -1;
+    *win_y = (window) ? xwin_y / impl->window_scale : -1;
 
   if (mask)
     *mask = xmask;
diff --git a/gdk/x11/gdkdevice-xi2.c b/gdk/x11/gdkdevice-xi2.c
index 9755a06..4f85ba1 100644
--- a/gdk/x11/gdkdevice-xi2.c
+++ b/gdk/x11/gdkdevice-xi2.c
@@ -303,7 +303,9 @@ gdk_x11_device_xi2_warp (GdkDevice *device,
   XIWarpPointer (GDK_SCREEN_XDISPLAY (screen),
                  device_xi2->device_id,
                  None, dest,
-                 0, 0, 0, 0, x, y);
+                 0, 0, 0, 0,
+                 x * GDK_X11_SCREEN(screen)->window_scale,
+                 y * GDK_X11_SCREEN(screen)->window_scale);
 }
 
 static void
@@ -317,6 +319,7 @@ gdk_x11_device_xi2_query_state (GdkDevice        *device,
                                 gint             *win_y,
                                 GdkModifierType  *mask)
 {
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
   GdkDisplay *display;
   GdkScreen *default_screen;
@@ -381,16 +384,16 @@ gdk_x11_device_xi2_query_state (GdkDevice        *device,
     *child_window = gdk_x11_window_lookup_for_display (display, xchild_window);
 
   if (root_x)
-    *root_x = (gint) xroot_x;
+    *root_x = (gint) (xroot_x / impl->window_scale);
 
   if (root_y)
-    *root_y = (gint) xroot_y;
+    *root_y = (gint) (xroot_y / impl->window_scale);
 
   if (win_x)
-    *win_x = (gint) xwin_x;
+    *win_x = (gint) (xwin_x / impl->window_scale);
 
   if (win_y)
-    *win_y = (gint) xwin_y;
+    *win_y = (gint) (xwin_y / impl->window_scale);
 
   if (mask)
     *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state, &group_state);
@@ -479,6 +482,7 @@ gdk_x11_device_xi2_window_at_position (GdkDevice       *device,
                                        GdkModifierType *mask,
                                        gboolean         get_toplevel)
 {
+  GdkWindowImplX11 *impl;
   GdkX11DeviceXI2 *device_xi2 = GDK_X11_DEVICE_XI2 (device);
   GdkDisplay *display;
   GdkScreen *screen;
@@ -624,12 +628,15 @@ gdk_x11_device_xi2_window_at_position (GdkDevice       *device,
   gdk_x11_display_ungrab (display);
 
   window = gdk_x11_window_lookup_for_display (display, last);
+  impl = NULL;
+  if (window)
+    impl = GDK_WINDOW_IMPL_X11 (window->impl);
 
   if (win_x)
-    *win_x = (window) ? (gint) xwin_x : -1;
+    *win_x = (window) ? (gint) (xwin_x / impl->window_scale) : -1;
 
   if (win_y)
-    *win_y = (window) ? (gint) xwin_y : -1;
+    *win_y = (window) ? (gint) (xwin_y / impl->window_scale) : -1;
 
   if (mask)
     *mask = _gdk_x11_device_xi2_translate_state (&mod_state, &button_state, &group_state);
diff --git a/gdk/x11/gdkdevicemanager-core-x11.c b/gdk/x11/gdkdevicemanager-core-x11.c
index 0e49fb7..dffef96 100644
--- a/gdk/x11/gdkdevicemanager-core-x11.c
+++ b/gdk/x11/gdkdevicemanager-core-x11.c
@@ -332,9 +332,11 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
                                              GdkEvent           *event,
                                              XEvent             *xevent)
 {
+  GdkWindowImplX11 *impl;
   GdkX11DeviceManagerCore *device_manager;
   GdkWindow *window;
   gboolean return_val;
+  int scale;
   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
 
   device_manager = GDK_X11_DEVICE_MANAGER_CORE (translator);
@@ -342,14 +344,18 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
 
   window = get_event_window (translator, xevent);
 
+  scale = 1;
   if (window)
     {
       if (GDK_WINDOW_DESTROYED (window) || !GDK_IS_WINDOW (window))
         return FALSE;
 
       g_object_ref (window);
+      impl = GDK_WINDOW_IMPL_X11 (window->impl);
+      scale = impl->window_scale;
     }
 
+
   event->any.window = window;
   event->any.send_event = xevent->xany.send_event ? TRUE : FALSE;
 
@@ -458,10 +464,10 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
 
           event->scroll.window = window;
           event->scroll.time = xevent->xbutton.time;
-          event->scroll.x = (gdouble) xevent->xbutton.x;
-          event->scroll.y = (gdouble) xevent->xbutton.y;
-          event->scroll.x_root = (gdouble) xevent->xbutton.x_root;
-          event->scroll.y_root = (gdouble) xevent->xbutton.y_root;
+          event->scroll.x = (gdouble) xevent->xbutton.x / scale;
+          event->scroll.y = (gdouble) xevent->xbutton.y / scale;
+          event->scroll.x_root = (gdouble) xevent->xbutton.x_root / scale;
+          event->scroll.y_root = (gdouble) xevent->xbutton.y_root / scale;
           event->scroll.state = (GdkModifierType) xevent->xbutton.state;
           event->scroll.device = device_manager->core_pointer;
 
@@ -480,10 +486,10 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
           event->button.type = GDK_BUTTON_PRESS;
           event->button.window = window;
           event->button.time = xevent->xbutton.time;
-          event->button.x = (gdouble) xevent->xbutton.x;
-          event->button.y = (gdouble) xevent->xbutton.y;
-          event->button.x_root = (gdouble) xevent->xbutton.x_root;
-          event->button.y_root = (gdouble) xevent->xbutton.y_root;
+          event->button.x = (gdouble) xevent->xbutton.x / scale;
+          event->button.y = (gdouble) xevent->xbutton.y / scale;
+          event->button.x_root = (gdouble) xevent->xbutton.x_root / scale;
+          event->button.y_root = (gdouble) xevent->xbutton.y_root / scale;
           event->button.axes = NULL;
           event->button.state = (GdkModifierType) xevent->xbutton.state;
           event->button.button = xevent->xbutton.button;
@@ -523,10 +529,10 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
       event->button.type = GDK_BUTTON_RELEASE;
       event->button.window = window;
       event->button.time = xevent->xbutton.time;
-      event->button.x = (gdouble) xevent->xbutton.x;
-      event->button.y = (gdouble) xevent->xbutton.y;
-      event->button.x_root = (gdouble) xevent->xbutton.x_root;
-      event->button.y_root = (gdouble) xevent->xbutton.y_root;
+      event->button.x = (gdouble) xevent->xbutton.x / scale;
+      event->button.y = (gdouble) xevent->xbutton.y / scale;
+      event->button.x_root = (gdouble) xevent->xbutton.x_root / scale;
+      event->button.y_root = (gdouble) xevent->xbutton.y_root / scale;
       event->button.axes = NULL;
       event->button.state = (GdkModifierType) xevent->xbutton.state;
       event->button.button = xevent->xbutton.button;
@@ -553,10 +559,10 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
       event->motion.type = GDK_MOTION_NOTIFY;
       event->motion.window = window;
       event->motion.time = xevent->xmotion.time;
-      event->motion.x = (gdouble) xevent->xmotion.x;
-      event->motion.y = (gdouble) xevent->xmotion.y;
-      event->motion.x_root = (gdouble) xevent->xmotion.x_root;
-      event->motion.y_root = (gdouble) xevent->xmotion.y_root;
+      event->motion.x = (gdouble) xevent->xmotion.x / scale;
+      event->motion.y = (gdouble) xevent->xmotion.y / scale;
+      event->motion.x_root = (gdouble) xevent->xmotion.x_root / scale;
+      event->motion.y_root = (gdouble) xevent->xmotion.y_root / scale;
       event->motion.axes = NULL;
       event->motion.state = (GdkModifierType) xevent->xmotion.state;
       event->motion.is_hint = xevent->xmotion.is_hint;
@@ -602,10 +608,10 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
         event->crossing.subwindow = NULL;
 
       event->crossing.time = xevent->xcrossing.time;
-      event->crossing.x = (gdouble) xevent->xcrossing.x;
-      event->crossing.y = (gdouble) xevent->xcrossing.y;
-      event->crossing.x_root = (gdouble) xevent->xcrossing.x_root;
-      event->crossing.y_root = (gdouble) xevent->xcrossing.y_root;
+      event->crossing.x = (gdouble) xevent->xcrossing.x / scale;
+      event->crossing.y = (gdouble) xevent->xcrossing.y / scale;
+      event->crossing.x_root = (gdouble) xevent->xcrossing.x_root / scale;
+      event->crossing.y_root = (gdouble) xevent->xcrossing.y_root / scale;
 
       event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode);
       event->crossing.detail = translate_notify_type (xevent->xcrossing.detail);
@@ -646,10 +652,10 @@ gdk_x11_device_manager_core_translate_event (GdkEventTranslator *translator,
         event->crossing.subwindow = NULL;
 
       event->crossing.time = xevent->xcrossing.time;
-      event->crossing.x = (gdouble) xevent->xcrossing.x;
-      event->crossing.y = (gdouble) xevent->xcrossing.y;
-      event->crossing.x_root = (gdouble) xevent->xcrossing.x_root;
-      event->crossing.y_root = (gdouble) xevent->xcrossing.y_root;
+      event->crossing.x = (gdouble) xevent->xcrossing.x / scale;
+      event->crossing.y = (gdouble) xevent->xcrossing.y / scale;
+      event->crossing.x_root = (gdouble) xevent->xcrossing.x_root / scale;
+      event->crossing.y_root = (gdouble) xevent->xcrossing.y_root / scale;
 
       event->crossing.mode = translate_crossing_mode (xevent->xcrossing.mode);
       event->crossing.detail = translate_notify_type (xevent->xcrossing.detail);
diff --git a/gdk/x11/gdkdevicemanager-xi2.c b/gdk/x11/gdkdevicemanager-xi2.c
index b9093b9..1c95235 100644
--- a/gdk/x11/gdkdevicemanager-xi2.c
+++ b/gdk/x11/gdkdevicemanager-xi2.c
@@ -1113,6 +1113,8 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
   XGenericEventCookie *cookie;
   gboolean return_val = TRUE;
   GdkWindow *window;
+  GdkWindowImplX11 *impl;
+  int scale;
   XIEvent *ev;
 
   device_manager = (GdkX11DeviceManagerXI2 *) translator;
@@ -1134,6 +1136,13 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
   if (window && GDK_WINDOW_DESTROYED (window))
     return FALSE;
 
+  scale = 1;
+  if (window)
+    {
+      impl = GDK_WINDOW_IMPL_X11 (window->impl);
+      scale = impl->window_scale;
+    }
+
   if (ev->evtype == XI_Motion ||
       ev->evtype == XI_ButtonRelease)
     {
@@ -1230,10 +1239,10 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
 
             event->scroll.window = window;
             event->scroll.time = xev->time;
-            event->scroll.x = (gdouble) xev->event_x;
-            event->scroll.y = (gdouble) xev->event_y;
-            event->scroll.x_root = (gdouble) xev->root_x;
-            event->scroll.y_root = (gdouble) xev->root_y;
+            event->scroll.x = (gdouble) xev->event_x / scale;
+            event->scroll.y = (gdouble) xev->event_y / scale;
+            event->scroll.x_root = (gdouble) xev->root_x / scale;
+            event->scroll.y_root = (gdouble) xev->root_y / scale;
             event->scroll.delta_x = 0;
             event->scroll.delta_y = 0;
 
@@ -1257,10 +1266,10 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
 
             event->button.window = window;
             event->button.time = xev->time;
-            event->button.x = (gdouble) xev->event_x;
-            event->button.y = (gdouble) xev->event_y;
-            event->button.x_root = (gdouble) xev->root_x;
-            event->button.y_root = (gdouble) xev->root_y;
+            event->button.x = (gdouble) xev->event_x / scale;
+            event->button.y = (gdouble) xev->event_y / scale;
+            event->button.x_root = (gdouble) xev->root_x / scale;
+            event->button.y_root = (gdouble) xev->root_y / scale;
 
             event->button.device = g_hash_table_lookup (device_manager->id_table,
                                                         GUINT_TO_POINTER (xev->deviceid));
@@ -1348,10 +1357,10 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
 
             event->scroll.window = window;
             event->scroll.time = xev->time;
-            event->scroll.x = (gdouble) xev->event_x;
-            event->scroll.y = (gdouble) xev->event_y;
-            event->scroll.x_root = (gdouble) xev->root_x;
-            event->scroll.y_root = (gdouble) xev->root_y;
+            event->scroll.x = (gdouble) xev->event_x / scale;
+            event->scroll.y = (gdouble) xev->event_y / scale;
+            event->scroll.x_root = (gdouble) xev->root_x / scale;
+            event->scroll.y_root = (gdouble) xev->root_y / scale;
             event->scroll.delta_x = delta_x;
             event->scroll.delta_y = delta_y;
 
@@ -1365,10 +1374,10 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
         event->motion.type = GDK_MOTION_NOTIFY;
         event->motion.window = window;
         event->motion.time = xev->time;
-        event->motion.x = (gdouble) xev->event_x;
-        event->motion.y = (gdouble) xev->event_y;
-        event->motion.x_root = (gdouble) xev->root_x;
-        event->motion.y_root = (gdouble) xev->root_y;
+        event->motion.x = (gdouble) xev->event_x / scale;
+        event->motion.y = (gdouble) xev->event_y / scale;
+        event->motion.x_root = (gdouble) xev->root_x / scale;
+        event->motion.y_root = (gdouble) xev->root_y / scale;
 
         event->motion.device = device;
         gdk_event_set_source_device (event, source_device);
@@ -1421,10 +1430,10 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
 
         event->touch.window = window;
         event->touch.time = xev->time;
-        event->touch.x = (gdouble) xev->event_x;
-        event->touch.y = (gdouble) xev->event_y;
-        event->touch.x_root = (gdouble) xev->root_x;
-        event->touch.y_root = (gdouble) xev->root_y;
+        event->touch.x = (gdouble) xev->event_x / scale;
+        event->touch.y = (gdouble) xev->event_y / scale;
+        event->touch.x_root = (gdouble) xev->root_x / scale;
+        event->touch.y_root = (gdouble) xev->root_y / scale;
 
         event->touch.device = g_hash_table_lookup (device_manager->id_table,
                                                    GUINT_TO_POINTER (xev->deviceid));
@@ -1490,10 +1499,10 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
         event->touch.sequence = GUINT_TO_POINTER (xev->detail);
         event->touch.type = GDK_TOUCH_UPDATE;
         event->touch.time = xev->time;
-        event->touch.x = (gdouble) xev->event_x;
-        event->touch.y = (gdouble) xev->event_y;
-        event->touch.x_root = (gdouble) xev->root_x;
-        event->touch.y_root = (gdouble) xev->root_y;
+        event->touch.x = (gdouble) xev->event_x / scale;
+        event->touch.y = (gdouble) xev->event_y / scale;
+        event->touch.x_root = (gdouble) xev->root_x / scale;
+        event->touch.y_root = (gdouble) xev->root_y / scale;
 
         event->touch.device = g_hash_table_lookup (device_manager->id_table,
                                                    GINT_TO_POINTER (xev->deviceid));
@@ -1538,10 +1547,10 @@ gdk_x11_device_manager_xi2_translate_event (GdkEventTranslator *translator,
 
         event->crossing.type = (ev->evtype == XI_Enter) ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY;
 
-        event->crossing.x = (gdouble) xev->event_x;
-        event->crossing.y = (gdouble) xev->event_y;
-        event->crossing.x_root = (gdouble) xev->root_x;
-        event->crossing.y_root = (gdouble) xev->root_y;
+        event->crossing.x = (gdouble) xev->event_x / scale;
+        event->crossing.y = (gdouble) xev->event_y / scale;
+        event->crossing.x_root = (gdouble) xev->root_x / scale;
+        event->crossing.y_root = (gdouble) xev->root_y / scale;
         event->crossing.time = xev->time;
         event->crossing.focus = xev->focus;
 
diff --git a/gdk/x11/gdkdisplay-x11.c b/gdk/x11/gdkdisplay-x11.c
index 09a4347..6f56e21 100644
--- a/gdk/x11/gdkdisplay-x11.c
+++ b/gdk/x11/gdkdisplay-x11.c
@@ -558,11 +558,16 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
 
       {
        GdkRectangle expose_rect;
+        int x2, y2;
 
-       expose_rect.x = xevent->xexpose.x;
-       expose_rect.y = xevent->xexpose.y;
-       expose_rect.width = xevent->xexpose.width;
-       expose_rect.height = xevent->xexpose.height;
+        expose_rect.x = xevent->xexpose.x / window_impl->window_scale;
+        expose_rect.y = xevent->xexpose.y / window_impl->window_scale;
+
+        x2 = (xevent->xexpose.x + xevent->xexpose.width + window_impl->window_scale -1) / 
window_impl->window_scale;
+        expose_rect.width = x2 - expose_rect.x;
+
+        y2 = (xevent->xexpose.y + xevent->xexpose.height + window_impl->window_scale -1) / 
window_impl->window_scale;
+        expose_rect.height = y2 - expose_rect.y;
 
         _gdk_x11_window_process_expose (window, xevent->xexpose.serial, &expose_rect);
         return_val = FALSE;
@@ -573,6 +578,7 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
     case GraphicsExpose:
       {
        GdkRectangle expose_rect;
+        int x2, y2;
 
         GDK_NOTE (EVENTS,
                  g_message ("graphics expose:\tdrawable: %ld",
@@ -584,10 +590,14 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
             break;
           }
 
-       expose_rect.x = xevent->xgraphicsexpose.x;
-       expose_rect.y = xevent->xgraphicsexpose.y;
-       expose_rect.width = xevent->xgraphicsexpose.width;
-       expose_rect.height = xevent->xgraphicsexpose.height;
+        expose_rect.x = xevent->xgraphicsexpose.x / window_impl->window_scale;
+        expose_rect.y = xevent->xgraphicsexpose.y / window_impl->window_scale;
+
+        x2 = (xevent->xgraphicsexpose.x + xevent->xgraphicsexpose.width + window_impl->window_scale -1) / 
window_impl->window_scale;
+        expose_rect.width = x2 - expose_rect.x;
+
+        y2 = (xevent->xgraphicsexpose.y + xevent->xgraphicsexpose.height + window_impl->window_scale -1) / 
window_impl->window_scale;
+        expose_rect.height = y2 - expose_rect.y;
 
         _gdk_x11_window_process_expose (window, xevent->xgraphicsexpose.serial, &expose_rect);
         return_val = FALSE;
@@ -773,8 +783,8 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
                           : ""));
       if (window && GDK_WINDOW_TYPE (window) == GDK_WINDOW_ROOT)
         {
-         window->width = xevent->xconfigure.width;
-         window->height = xevent->xconfigure.height;
+         window->width = xevent->xconfigure.width / window_impl->window_scale;
+         window->height = xevent->xconfigure.height / window_impl->window_scale;
 
          _gdk_window_update_size (window);
          _gdk_x11_window_update_size (GDK_WINDOW_IMPL_X11 (window->impl));
@@ -799,8 +809,8 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
        {
          event->configure.type = GDK_CONFIGURE;
          event->configure.window = window;
-         event->configure.width = xevent->xconfigure.width;
-         event->configure.height = xevent->xconfigure.height;
+         event->configure.width = xevent->xconfigure.width / window_impl->window_scale;
+         event->configure.height = xevent->xconfigure.height / window_impl->window_scale;
 
          if (!xevent->xconfigure.send_event &&
              !xevent->xconfigure.override_redirect &&
@@ -818,22 +828,22 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
                                         &tx, &ty,
                                         &child_window))
                {
-                 event->configure.x = tx;
-                 event->configure.y = ty;
+                 event->configure.x = tx / window_impl->window_scale;
+                 event->configure.y = ty / window_impl->window_scale;
                }
              gdk_x11_display_error_trap_pop_ignored (display);
            }
          else
            {
-             event->configure.x = xevent->xconfigure.x;
-             event->configure.y = xevent->xconfigure.y;
+             event->configure.x = xevent->xconfigure.x / window_impl->window_scale;
+             event->configure.y = xevent->xconfigure.y / window_impl->window_scale;
            }
          if (!is_substructure)
            {
              window->x = event->configure.x;
              window->y = event->configure.y;
-             window->width = xevent->xconfigure.width;
-             window->height = xevent->xconfigure.height;
+             window->width = xevent->xconfigure.width / window_impl->window_scale;
+             window->height = xevent->xconfigure.height / window_impl->window_scale;
 
              _gdk_window_update_size (window);
              _gdk_x11_window_update_size (GDK_WINDOW_IMPL_X11 (window->impl));
@@ -1015,11 +1025,15 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
          XDamageNotifyEvent *damage_event = (XDamageNotifyEvent *) xevent;
          XserverRegion repair;
          GdkRectangle rect;
+          int x2, y2;
+
+         rect.x = window->x + damage_event->area.x / window_impl->window_scale;
+         rect.y = window->y + damage_event->area.y / window_impl->window_scale;
 
-         rect.x = window->x + damage_event->area.x;
-         rect.y = window->y + damage_event->area.y;
-         rect.width = damage_event->area.width;
-         rect.height = damage_event->area.height;
+          x2 = (rect.x * window_impl->window_scale + damage_event->area.width + window_impl->window_scale 
-1) / window_impl->window_scale;
+          y2 = (rect.y * window_impl->window_scale + damage_event->area.height + window_impl->window_scale 
-1) / window_impl->window_scale;
+         rect.width = x2 - rect.x;
+         rect.height = y2 - rect.y;
 
          repair = XFixesCreateRegion (display_x11->xdisplay,
                                       &damage_event->area, 1);
diff --git a/gdk/x11/gdkdnd-x11.c b/gdk/x11/gdkdnd-x11.c
index b5a6b54..3515fea 100644
--- a/gdk/x11/gdkdnd-x11.c
+++ b/gdk/x11/gdkdnd-x11.c
@@ -510,15 +510,19 @@ gdk_window_cache_new (GdkScreen *screen)
     {
       GList *toplevel_windows, *list;
       GdkWindow *window;
+      GdkWindowImplX11 *impl;
       gint x, y, width, height;
 
       toplevel_windows = gdk_screen_get_toplevel_windows (screen);
       for (list = toplevel_windows; list; list = list->next)
         {
           window = GDK_WINDOW (list->data);
+         impl = GDK_WINDOW_IMPL_X11 (window->impl);
           gdk_window_get_geometry (window, &x, &y, &width, &height);
           gdk_window_cache_add (result, GDK_WINDOW_XID (window),
-                                x, y, width, height,
+                                x * impl->window_scale, y * impl->window_scale, 
+                               width * impl->window_scale, 
+                               height * impl->window_scale,
                                 gdk_window_is_visible (window));
         }
       g_list_free (toplevel_windows);
@@ -556,7 +560,10 @@ gdk_window_cache_new (GdkScreen *screen)
   if (gdk_screen_is_composited (screen))
     {
       cow = XCompositeGetOverlayWindow (xdisplay, GDK_WINDOW_XID (root_window));
-      gdk_window_cache_add (result, cow, 0, 0, gdk_screen_get_width (screen), gdk_screen_get_height 
(screen), TRUE);
+      gdk_window_cache_add (result, cow, 0, 0, 
+                           gdk_screen_get_width (screen) * GDK_X11_SCREEN(screen)->window_scale, 
+                           gdk_screen_get_height (screen) * GDK_X11_SCREEN(screen)->window_scale, 
+                           TRUE);
       XCompositeReleaseOverlayWindow (xdisplay, GDK_WINDOW_XID (root_window));
     }
 #endif
@@ -651,12 +658,12 @@ is_pointer_within_shape (GdkDisplay    *display,
       child->shape = NULL;
       if (gdk_display_supports_shapes (display))
         child->shape = _gdk_x11_xwindow_get_shape (display_x11->xdisplay,
-                                                   child->xid, ShapeBounding);
+                                                   child->xid, 1,  ShapeBounding);
 #ifdef ShapeInput
       input_shape = NULL;
       if (gdk_display_supports_input_shapes (display))
         input_shape = _gdk_x11_xwindow_get_shape (display_x11->xdisplay,
-                                                  child->xid, ShapeInput);
+                                                  child->xid, 1, ShapeInput);
 
       if (child->shape && input_shape)
         {
@@ -1744,6 +1751,7 @@ xdnd_position_filter (GdkXEvent *xev,
                       GdkEvent  *event,
                       gpointer   data)
 {
+  GdkWindowImplX11 *impl;
   XEvent *xevent = (XEvent *)xev;
   guint32 source_window = xevent->xclient.data.l[0];
   gint16 x_root = xevent->xclient.data.l[2] >> 16;
@@ -1774,6 +1782,8 @@ xdnd_position_filter (GdkXEvent *xev,
       (context->protocol == GDK_DRAG_PROTO_XDND) &&
       (GDK_WINDOW_XID (context->source_window) == source_window))
     {
+      impl = GDK_WINDOW_IMPL_X11 (event->any.window->impl);
+
       context_x11 = GDK_X11_DRAG_CONTEXT (context);
 
       event->dnd.type = GDK_DRAG_MOTION;
@@ -1788,11 +1798,11 @@ xdnd_position_filter (GdkXEvent *xev,
       if (!context_x11->xdnd_have_actions)
         context->actions = context->suggested_action;
 
-      event->dnd.x_root = x_root;
-      event->dnd.y_root = y_root;
+      event->dnd.x_root = x_root / impl->window_scale;
+      event->dnd.y_root = y_root / impl->window_scale;
 
-      context_x11->last_x = x_root;
-      context_x11->last_y = y_root;
+      context_x11->last_x = x_root / impl->window_scale;
+      context_x11->last_y = y_root / impl->window_scale;
 
       return GDK_FILTER_TRANSLATE;
     }
@@ -2015,6 +2025,7 @@ gdk_x11_drag_context_find_window (GdkDragContext  *context,
                                   gint             y_root,
                                   GdkDragProtocol *protocol)
 {
+  GdkX11Screen *screen_x11 = GDK_X11_SCREEN(screen);
   GdkX11DragContext *context_x11 = GDK_X11_DRAG_CONTEXT (context);
   GdkWindowCache *window_cache;
   GdkDisplay *display;
@@ -2028,7 +2039,8 @@ gdk_x11_drag_context_find_window (GdkDragContext  *context,
   dest = get_client_window_at_coords (window_cache,
                                       drag_window && GDK_WINDOW_IS_X11 (drag_window) ?
                                       GDK_WINDOW_XID (drag_window) : None,
-                                      x_root, y_root);
+                                      x_root * screen_x11->window_scale,
+                                     y_root * screen_x11->window_scale);
 
   if (context_x11->dest_xid != dest)
     {
@@ -2075,6 +2087,7 @@ gdk_x11_drag_context_drag_motion (GdkDragContext *context,
                                   guint32         time)
 {
   GdkX11DragContext *context_x11 = GDK_X11_DRAG_CONTEXT (context);
+  GdkWindowImplX11 *impl;
 
   context_x11->old_actions = context->actions;
   context->actions = possible_actions;
@@ -2198,12 +2211,14 @@ gdk_x11_drag_context_drag_motion (GdkDragContext *context,
 
   if (context->dest_window)
     {
+      impl = GDK_WINDOW_IMPL_X11 (context->dest_window->impl);
+
       if (context_x11->drag_status == GDK_DRAG_STATUS_DRAG)
         {
           switch (context->protocol)
             {
             case GDK_DRAG_PROTO_XDND:
-              xdnd_send_motion (context_x11, x_root, y_root, suggested_action, time);
+              xdnd_send_motion (context_x11, x_root * impl->window_scale, y_root * impl->window_scale, 
suggested_action, time);
               break;
 
             case GDK_DRAG_PROTO_ROOTWIN:
diff --git a/gdk/x11/gdkgeometry-x11.c b/gdk/x11/gdkgeometry-x11.c
index 63620e7..a09a81b 100644
--- a/gdk/x11/gdkgeometry-x11.c
+++ b/gdk/x11/gdkgeometry-x11.c
@@ -42,18 +42,22 @@ _gdk_x11_window_move_resize_child (GdkWindow *window,
                                    gint       width,
                                    gint       height)
 {
+  GdkWindowImplX11 *impl;
+
   g_return_if_fail (window != NULL);
   g_return_if_fail (GDK_IS_WINDOW (window));
 
-  if (width > 65535 ||
-      height > 65535)
+  impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
+  if (width * impl->window_scale > 65535 ||
+      height * impl->window_scale > 65535)
     {
       g_warning ("Native children wider or taller than 65535 pixels are not supported");
 
-      if (width > 65535)
-        width = 65535;
-      if (height > 65535)
-        height = 65535;
+      if (width * impl->window_scale > 65535)
+        width = 65535 / impl->window_scale;
+      if (height * impl->window_scale > 65535)
+        height = 65535 / impl->window_scale;
     }
 
   window->x = x;
@@ -69,8 +73,8 @@ _gdk_x11_window_move_resize_child (GdkWindow *window,
   _gdk_x11_window_tmp_unset_bg (window, TRUE);
   XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
                      GDK_WINDOW_XID (window),
-                     window->x + window->parent->abs_x,
-                     window->y + window->parent->abs_y,
+                     (window->x + window->parent->abs_x) * impl->window_scale,
+                     (window->y + window->parent->abs_y) * impl->window_scale,
                      width, height);
   _gdk_x11_window_tmp_reset_parent_bg (window);
   _gdk_x11_window_tmp_reset_bg (window, TRUE);
diff --git a/gdk/x11/gdkmain-x11.c b/gdk/x11/gdkmain-x11.c
index 5065f9c..955313b 100644
--- a/gdk/x11/gdkmain-x11.c
+++ b/gdk/x11/gdkmain-x11.c
@@ -368,6 +368,7 @@ void
 _gdk_x11_region_get_xrectangles (const cairo_region_t *region,
                                  gint             x_offset,
                                  gint             y_offset,
+                                 gint             scale,
                                  XRectangle     **rects,
                                  gint            *n_rects)
 {
@@ -381,10 +382,10 @@ _gdk_x11_region_get_xrectangles (const cairo_region_t *region,
   for (i = 0; i < n; i++)
     {
       cairo_region_get_rectangle (region, i, &box);
-      rectangles[i].x = CLAMP (box.x + x_offset, G_MINSHORT, G_MAXSHORT);
-      rectangles[i].y = CLAMP (box.y + y_offset, G_MINSHORT, G_MAXSHORT);
-      rectangles[i].width = CLAMP (box.width, G_MINSHORT, G_MAXSHORT);
-      rectangles[i].height = CLAMP (box.height, G_MINSHORT, G_MAXSHORT);
+      rectangles[i].x = CLAMP ((box.x + x_offset) * scale, G_MINSHORT, G_MAXSHORT);
+      rectangles[i].y = CLAMP ((box.y + y_offset) * scale, G_MINSHORT, G_MAXSHORT);
+      rectangles[i].width = CLAMP (box.width * scale, G_MINSHORT, G_MAXSHORT);
+      rectangles[i].height = CLAMP (box.height * scale, G_MINSHORT, G_MAXSHORT);
     }
 
   *n_rects = n;
diff --git a/gdk/x11/gdkprivate-x11.h b/gdk/x11/gdkprivate-x11.h
index defd47e..57f7d89 100644
--- a/gdk/x11/gdkprivate-x11.h
+++ b/gdk/x11/gdkprivate-x11.h
@@ -140,11 +140,13 @@ gboolean _gdk_x11_selection_filter_clear_event (XSelectionClearEvent *event);
 
 cairo_region_t* _gdk_x11_xwindow_get_shape  (Display *xdisplay,
                                              Window   window,
+                                             gint     scale,
                                              gint     shape_type);
 
 void     _gdk_x11_region_get_xrectangles   (const cairo_region_t  *region,
                                             gint                   x_offset,
                                             gint                   y_offset,
+                                            gint                   scale,
                                             XRectangle           **rects,
                                             gint                  *n_rects);
 
diff --git a/gdk/x11/gdkscreen-x11.c b/gdk/x11/gdkscreen-x11.c
index 760da2b..74e042f 100644
--- a/gdk/x11/gdkscreen-x11.c
+++ b/gdk/x11/gdkscreen-x11.c
@@ -96,13 +96,13 @@ gdk_x11_screen_get_display (GdkScreen *screen)
 static gint
 gdk_x11_screen_get_width (GdkScreen *screen)
 {
-  return WidthOfScreen (GDK_X11_SCREEN (screen)->xscreen);
+  return WidthOfScreen (GDK_X11_SCREEN (screen)->xscreen) / GDK_X11_SCREEN (screen)->window_scale;
 }
 
 static gint
 gdk_x11_screen_get_height (GdkScreen *screen)
 {
-  return HeightOfScreen (GDK_X11_SCREEN (screen)->xscreen);
+  return HeightOfScreen (GDK_X11_SCREEN (screen)->xscreen) / GDK_X11_SCREEN (screen)->window_scale;
 }
 
 static gint
@@ -253,7 +253,13 @@ gdk_x11_screen_get_monitor_geometry (GdkScreen    *screen,
   GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen);
 
   if (dest)
-    *dest = x11_screen->monitors[monitor_num].geometry;
+    {
+      *dest = x11_screen->monitors[monitor_num].geometry;
+      dest->x /= x11_screen->window_scale;
+      dest->y /= x11_screen->window_scale;
+      dest->width /= x11_screen->window_scale;
+      dest->height /= x11_screen->window_scale;
+    }
 }
 
 static int
@@ -297,6 +303,7 @@ static void
 get_work_area (GdkScreen    *screen,
                GdkRectangle *area)
 {
+  GdkX11Screen   *x11_screen = GDK_X11_SCREEN (screen);
   Atom            workarea;
   Atom            type;
   Window          win;
@@ -318,8 +325,8 @@ get_work_area (GdkScreen    *screen,
   /* Defaults in case of error */
   area->x = 0;
   area->y = 0;
-  area->width = gdk_screen_get_width (screen);
-  area->height = gdk_screen_get_height (screen);
+  area->width = gdk_screen_get_width (screen) / x11_screen->window_scale;
+  area->height = gdk_screen_get_height (screen) / x11_screen->window_scale;
 
   if (!gdk_x11_screen_supports_net_wm_hint (screen,
                                             gdk_atom_intern_static_string ("_NET_WORKAREA")))
@@ -356,6 +363,11 @@ get_work_area (GdkScreen    *screen,
   area->width = workareas[desktop * 4 + 2];
   area->height = workareas[desktop * 4 + 3];
 
+  area->x /= x11_screen->window_scale;
+  area->y /= x11_screen->window_scale;
+  area->width /= x11_screen->window_scale;
+  area->height /= x11_screen->window_scale;
+
   XFree (ret_workarea);
 }
 
@@ -382,6 +394,15 @@ gdk_x11_screen_get_monitor_workarea (GdkScreen    *screen,
     }
 }
 
+static gint
+gdk_x11_screen_get_monitor_scale_factor (GdkScreen *screen,
+                                        gint       monitor_num)
+{
+  GdkX11Screen *screen_x11 = GDK_X11_SCREEN (screen);
+
+  return screen_x11->window_scale;
+}
+
 static GdkVisual *
 gdk_x11_screen_get_rgba_visual (GdkScreen *screen)
 {
@@ -1029,6 +1050,7 @@ _gdk_x11_screen_new (GdkDisplay *display,
   GdkScreen *screen;
   GdkX11Screen *x11_screen;
   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
+  const char *scale_str;
 
   screen = g_object_new (GDK_TYPE_X11_SCREEN, NULL);
 
@@ -1041,7 +1063,21 @@ _gdk_x11_screen_new (GdkDisplay *display,
   x11_screen->wmspec_check_window = None;
   /* we want this to be always non-null */
   x11_screen->window_manager_name = g_strdup ("unknown");
-  
+
+#ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE
+  scale_str = g_getenv ("GDK_SCALE");
+#else
+  scale_str = NULL;
+#endif
+  if (scale_str)
+    {
+      x11_screen->window_scale = atol (scale_str);
+      if (x11_screen->window_scale == 0)
+        x11_screen->window_scale = 1;
+    }
+  else
+    x11_screen->window_scale = 1;
+
   init_multihead (screen);
   init_randr_support (screen);
   
@@ -1627,6 +1663,7 @@ gdk_x11_screen_class_init (GdkX11ScreenClass *klass)
   screen_class->get_monitor_plug_name = gdk_x11_screen_get_monitor_plug_name;
   screen_class->get_monitor_geometry = gdk_x11_screen_get_monitor_geometry;
   screen_class->get_monitor_workarea = gdk_x11_screen_get_monitor_workarea;
+  screen_class->get_monitor_scale_factor = gdk_x11_screen_get_monitor_scale_factor;
   screen_class->get_system_visual = _gdk_x11_screen_get_system_visual;
   screen_class->get_rgba_visual = gdk_x11_screen_get_rgba_visual;
   screen_class->is_composited = gdk_x11_screen_is_composited;
diff --git a/gdk/x11/gdkscreen-x11.h b/gdk/x11/gdkscreen-x11.h
index 5c88a1a..7b27657 100644
--- a/gdk/x11/gdkscreen-x11.h
+++ b/gdk/x11/gdkscreen-x11.h
@@ -47,6 +47,8 @@ struct _GdkX11Screen
   GdkX11Monitor *monitors;
   gint primary_monitor;
 
+  gint window_scale;
+
   /* Xft resources for the display, used for default values for
    * the Xft/ XSETTINGS
    */
diff --git a/gdk/x11/gdkwindow-x11.c b/gdk/x11/gdkwindow-x11.c
index 1f1dbf1..a1c6be9 100644
--- a/gdk/x11/gdkwindow-x11.c
+++ b/gdk/x11/gdkwindow-x11.c
@@ -194,8 +194,8 @@ _gdk_x11_window_update_size (GdkWindowImplX11 *impl)
   if (impl->cairo_surface)
     {
       cairo_xlib_surface_set_size (impl->cairo_surface,
-                                   gdk_window_get_width (impl->wrapper),
-                                   gdk_window_get_height (impl->wrapper));
+                                   gdk_window_get_width (impl->wrapper) * impl->window_scale,
+                                   gdk_window_get_height (impl->wrapper) * impl->window_scale);
     }
 }
 
@@ -464,8 +464,11 @@ gdk_x11_ref_cairo_surface (GdkWindow *window)
   if (!impl->cairo_surface)
     {
       impl->cairo_surface = gdk_x11_create_cairo_surface (impl,
-                                                          gdk_window_get_width (window),
-                                                          gdk_window_get_height (window));
+                                                          gdk_window_get_width (window) * impl->window_scale,
+                                                          gdk_window_get_height (window) * 
impl->window_scale);
+#ifdef HAVE_CAIRO_SURFACE_SET_DEVICE_SCALE
+      cairo_surface_set_device_scale (impl->cairo_surface, impl->window_scale, impl->window_scale);
+#endif
       
       if (impl->cairo_surface)
        cairo_surface_set_user_data (impl->cairo_surface, &gdk_x11_cairo_key,
@@ -727,6 +730,7 @@ _gdk_x11_screen_init_root_window (GdkScreen *screen)
   
   impl->xid = x11_screen->xroot_window;
   impl->wrapper = window;
+  impl->window_scale = x11_screen->window_scale;
   
   window->window_type = GDK_WINDOW_ROOT;
   window->depth = DefaultDepthOfScreen (x11_screen->xscreen);
@@ -735,8 +739,8 @@ _gdk_x11_screen_init_root_window (GdkScreen *screen)
   window->y = 0;
   window->abs_x = 0;
   window->abs_y = 0;
-  window->width = WidthOfScreen (x11_screen->xscreen);
-  window->height = HeightOfScreen (x11_screen->xscreen);
+  window->width = WidthOfScreen (x11_screen->xscreen) / impl->window_scale;
+  window->height = HeightOfScreen (x11_screen->xscreen) / impl->window_scale;
   window->viewable = TRUE;
 
   /* see init_randr_support() in gdkscreen-x11.c */
@@ -872,6 +876,7 @@ setup_toplevel_window (GdkWindow *window,
                       GdkWindow *parent)
 {
   GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
   GdkDisplay *display = gdk_window_get_display (window);
   Display *xdisplay = GDK_WINDOW_XDISPLAY (window);
   XID xid = GDK_WINDOW_XID (window);
@@ -900,8 +905,8 @@ setup_toplevel_window (GdkWindow *window,
    * correct value???
    */
   size_hints.flags = PSize;
-  size_hints.width = window->width;
-  size_hints.height = window->height;
+  size_hints.width = window->width * impl->window_scale;
+  size_hints.height = window->height * impl->window_scale;
   
   XSetWMNormalHints (xdisplay, xid, &size_hints);
   
@@ -1006,6 +1011,7 @@ _gdk_x11_display_create_window_impl (GdkDisplay    *display,
   impl = g_object_new (GDK_TYPE_WINDOW_IMPL_X11, NULL);
   window->impl = GDK_WINDOW_IMPL (impl);
   impl->wrapper = GDK_WINDOW (window);
+  impl->window_scale = x11_screen->window_scale;
 
   xdisplay = x11_screen->xdisplay;
 
@@ -1076,21 +1082,21 @@ _gdk_x11_display_create_window_impl (GdkDisplay    *display,
       class = InputOnly;
     }
 
-  if (window->width > 65535 ||
-      window->height > 65535)
+  if (window->width * impl->window_scale > 65535 ||
+      window->height * impl->window_scale > 65535)
     {
       g_warning ("Native Windows wider or taller than 65535 pixels are not supported");
 
-      if (window->width > 65535)
-        window->width = 65535;
-      if (window->height > 65535)
-        window->height = 65535;
+      if (window->width * impl->window_scale > 65535)
+        window->width = 65535 / impl->window_scale;
+      if (window->height  * impl->window_scale > 65535)
+        window->height = 65535 /  impl->window_scale;
     }
 
   impl->xid = XCreateWindow (xdisplay, xparent,
-                             window->x + window->parent->abs_x,
-                             window->y + window->parent->abs_y,
-                             window->width, window->height,
+                             (window->x + window->parent->abs_x) * impl->window_scale,
+                             (window->y + window->parent->abs_y) * impl->window_scale,
+                             window->width * impl->window_scale, window->height * impl->window_scale,
                              0, window->depth, class, xvisual,
                              xattributes_mask, &xattributes);
 
@@ -1219,6 +1225,7 @@ gdk_x11_window_foreign_new_for_display (GdkDisplay *display,
 
   impl = GDK_WINDOW_IMPL_X11 (win->impl);
   impl->wrapper = win;
+  impl->window_scale = GDK_X11_SCREEN (screen)->window_scale;
 
   win->parent = gdk_x11_window_lookup_for_display (display, parent);
 
@@ -1231,10 +1238,10 @@ gdk_x11_window_foreign_new_for_display (GdkDisplay *display,
 
   impl->xid = window;
 
-  win->x = attrs.x;
-  win->y = attrs.y;
-  win->width = attrs.width;
-  win->height = attrs.height;
+  win->x = attrs.x / impl->window_scale;
+  win->y = attrs.y / impl->window_scale;
+  win->width = attrs.width / impl->window_scale;
+  win->height = attrs.height  / impl->window_scale;
   win->window_type = GDK_WINDOW_FOREIGN;
   win->destroyed = FALSE;
 
@@ -1765,7 +1772,7 @@ window_x11_move (GdkWindow *window,
     {
       XMoveWindow (GDK_WINDOW_XDISPLAY (window),
                    GDK_WINDOW_XID (window),
-                   x, y);
+                   x * impl->window_scale, y * impl->window_scale);
 
       if (impl->override_redirect)
         {
@@ -1800,7 +1807,7 @@ window_x11_resize (GdkWindow *window,
 
       XResizeWindow (GDK_WINDOW_XDISPLAY (window),
                      GDK_WINDOW_XID (window),
-                     width, height);
+                     width * impl->window_scale, height * impl->window_scale);
 
       if (impl->override_redirect)
         {
@@ -1844,7 +1851,8 @@ window_x11_move_resize (GdkWindow *window,
 
       XMoveResizeWindow (GDK_WINDOW_XDISPLAY (window),
                          GDK_WINDOW_XID (window),
-                         x, y, width, height);
+                         x * impl->window_scale, y * impl->window_scale,
+                         width * impl->window_scale, height * impl->window_scale);
 
       if (impl->override_redirect)
         {
@@ -1898,7 +1906,8 @@ gdk_window_x11_reparent (GdkWindow *window,
   XReparentWindow (GDK_WINDOW_XDISPLAY (window),
                   GDK_WINDOW_XID (window),
                   GDK_WINDOW_XID (new_parent),
-                  new_parent->abs_x + x, new_parent->abs_y + y);
+                  (new_parent->abs_x + x)  * impl->window_scale,
+                   (new_parent->abs_y + y) * impl->window_scale);
   _gdk_x11_window_tmp_reset_parent_bg (window);
   _gdk_x11_window_tmp_reset_bg (window, TRUE);
 
@@ -2390,6 +2399,7 @@ gdk_x11_window_set_geometry_hints (GdkWindow         *window,
                                   const GdkGeometry *geometry,
                                   GdkWindowHints     geom_mask)
 {
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
   XSizeHints size_hints;
   
   if (GDK_WINDOW_DESTROYED (window) ||
@@ -2422,31 +2432,37 @@ gdk_x11_window_set_geometry_hints (GdkWindow         *window,
   if (geom_mask & GDK_HINT_MIN_SIZE)
     {
       size_hints.flags |= PMinSize;
-      size_hints.min_width = geometry->min_width;
-      size_hints.min_height = geometry->min_height;
+      size_hints.min_width = geometry->min_width * impl->window_scale;
+      size_hints.min_height = geometry->min_height * impl->window_scale;
     }
   
   if (geom_mask & GDK_HINT_MAX_SIZE)
     {
       size_hints.flags |= PMaxSize;
-      size_hints.max_width = MAX (geometry->max_width, 1);
-      size_hints.max_height = MAX (geometry->max_height, 1);
+      size_hints.max_width = MAX (geometry->max_width, 1) * impl->window_scale;
+      size_hints.max_height = MAX (geometry->max_height, 1) * impl->window_scale;
     }
   
   if (geom_mask & GDK_HINT_BASE_SIZE)
     {
       size_hints.flags |= PBaseSize;
-      size_hints.base_width = geometry->base_width;
-      size_hints.base_height = geometry->base_height;
+      size_hints.base_width = geometry->base_width * impl->window_scale;
+      size_hints.base_height = geometry->base_height * impl->window_scale;
     }
   
   if (geom_mask & GDK_HINT_RESIZE_INC)
     {
       size_hints.flags |= PResizeInc;
-      size_hints.width_inc = geometry->width_inc;
-      size_hints.height_inc = geometry->height_inc;
+      size_hints.width_inc = geometry->width_inc * impl->window_scale;
+      size_hints.height_inc = geometry->height_inc * impl->window_scale;
     }
-  
+  else if (impl->window_scale > 1)
+    {
+      size_hints.flags |= PResizeInc;
+      size_hints.width_inc = impl->window_scale;
+      size_hints.height_inc = impl->window_scale;
+    }
+
   if (geom_mask & GDK_HINT_ASPECT)
     {
       size_hints.flags |= PAspect;
@@ -2491,6 +2507,7 @@ gdk_window_get_geometry_hints (GdkWindow      *window,
                                GdkGeometry    *geometry,
                                GdkWindowHints *geom_mask)
 {
+  GdkWindowImplX11 *impl;
   XSizeHints *size_hints;  
   glong junk_supplied_mask = 0;
 
@@ -2504,6 +2521,8 @@ gdk_window_get_geometry_hints (GdkWindow      *window,
       !WINDOW_IS_TOPLEVEL_OR_FOREIGN (window))
     return;
 
+  impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
   size_hints = XAllocSizeHints ();
   if (!size_hints)
     return;
@@ -2517,22 +2536,22 @@ gdk_window_get_geometry_hints (GdkWindow      *window,
   if (size_hints->flags & PMinSize)
     {
       *geom_mask |= GDK_HINT_MIN_SIZE;
-      geometry->min_width = size_hints->min_width;
-      geometry->min_height = size_hints->min_height;
+      geometry->min_width = size_hints->min_width / impl->window_scale;
+      geometry->min_height = size_hints->min_height / impl->window_scale;
     }
 
   if (size_hints->flags & PMaxSize)
     {
       *geom_mask |= GDK_HINT_MAX_SIZE;
-      geometry->max_width = MAX (size_hints->max_width, 1);
-      geometry->max_height = MAX (size_hints->max_height, 1);
+      geometry->max_width = MAX (size_hints->max_width, 1) / impl->window_scale;
+      geometry->max_height = MAX (size_hints->max_height, 1) / impl->window_scale;
     }
 
   if (size_hints->flags & PResizeInc)
     {
       *geom_mask |= GDK_HINT_RESIZE_INC;
-      geometry->width_inc = size_hints->width_inc;
-      geometry->height_inc = size_hints->height_inc;
+      geometry->width_inc = size_hints->width_inc / impl->window_scale;
+      geometry->height_inc = size_hints->height_inc / impl->window_scale;
     }
 
   if (size_hints->flags & PAspect)
@@ -2793,6 +2812,7 @@ static void
 gdk_window_x11_set_background (GdkWindow      *window,
                                cairo_pattern_t *pattern)
 {
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
   double r, g, b, a;
   cairo_surface_t *surface;
   cairo_matrix_t matrix;
@@ -2831,12 +2851,14 @@ gdk_window_x11_set_background (GdkWindow      *window,
           cairo_xlib_surface_get_visual (surface) == GDK_VISUAL_XVISUAL (gdk_window_get_visual ((window))) &&
           cairo_xlib_surface_get_display (surface) == GDK_WINDOW_XDISPLAY (window))
         {
-          double x, y;
+          double x, y, sx, sy;
 
           cairo_surface_get_device_offset (surface, &x, &y);
+          cairo_surface_get_device_scale (surface, &sx, &sy);
           /* XXX: This still bombs for non-pixmaps, but there's no way to
            * detect we're not a pixmap in Cairo... */
-          if (x == 0.0 && y == 0.0)
+          if (x == 0.0 && y == 0.0 &&
+              sx == impl->window_scale && sy == impl->window_scale)
             {
               XSetWindowBackgroundPixmap (GDK_WINDOW_XDISPLAY (window),
                                           GDK_WINDOW_XID (window),
@@ -2900,6 +2922,7 @@ gdk_window_x11_get_geometry (GdkWindow *window,
                              gint      *width,
                              gint      *height)
 {
+  GdkWindowImplX11 *impl;
   Window root;
   gint tx;
   gint ty;
@@ -2910,18 +2933,20 @@ gdk_window_x11_get_geometry (GdkWindow *window,
   
   if (!GDK_WINDOW_DESTROYED (window))
     {
+      impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
       XGetGeometry (GDK_WINDOW_XDISPLAY (window),
                    GDK_WINDOW_XID (window),
                    &root, &tx, &ty, &twidth, &theight, &tborder_width, &tdepth);
       
       if (x)
-       *x = tx;
+       *x = tx / impl->window_scale;
       if (y)
-       *y = ty;
+       *y = ty / impl->window_scale;
       if (width)
-       *width = twidth;
+       *width = twidth / impl->window_scale;
       if (height)
-       *height = theight;
+       *height = theight / impl->window_scale;
     }
 }
 
@@ -2932,6 +2957,7 @@ gdk_window_x11_get_root_coords (GdkWindow *window,
                                gint      *root_x,
                                gint      *root_y)
 {
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
   gint return_val;
   Window child;
   gint tx;
@@ -2940,13 +2966,13 @@ gdk_window_x11_get_root_coords (GdkWindow *window,
   return_val = XTranslateCoordinates (GDK_WINDOW_XDISPLAY (window),
                                      GDK_WINDOW_XID (window),
                                      GDK_WINDOW_XROOTWIN (window),
-                                     x, y, &tx, &ty,
+                                     x * impl->window_scale, y * impl->window_scale, &tx, &ty,
                                      &child);
   
   if (root_x)
-    *root_x = tx;
+    *root_x = tx / impl->window_scale;
   if (root_y)
-    *root_y = ty;
+    *root_y = ty / impl->window_scale;
   
   return return_val;
 }
@@ -3001,13 +3027,14 @@ gdk_x11_window_get_frame_extents (GdkWindow    *window,
   while (window->parent && (window->parent)->parent)
     window = window->parent;
 
+  impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
   /* Refine our fallback answer a bit using local information */
-  rect->x = window->x;
-  rect->y = window->y;
-  rect->width = window->width;
-  rect->height = window->height;
+  rect->x = window->x * impl->window_scale;
+  rect->y = window->y * impl->window_scale;
+  rect->width = window->width * impl->window_scale;
+  rect->height = window->height * impl->window_scale;
 
-  impl = GDK_WINDOW_IMPL_X11 (window->impl);
   if (GDK_WINDOW_DESTROYED (window) || impl->override_redirect)
     return;
 
@@ -3126,6 +3153,10 @@ gdk_x11_window_get_frame_extents (GdkWindow    *window,
   if (vroots)
     XFree (vroots);
 
+  rect->x /= impl->window_scale;
+  rect->y /= impl->window_scale;
+  rect->width /= impl->window_scale;
+  rect->height /= impl->window_scale;
   gdk_x11_display_error_trap_pop_ignored (display);
 }
 
@@ -3143,6 +3174,7 @@ gdk_window_x11_get_device_state (GdkWindow       *window,
   if (GDK_WINDOW_DESTROYED (window))
     return FALSE;
 
+  /*HIDPI: handle coords here?*/
   GDK_DEVICE_GET_CLASS (device)->query_state (device, window,
                                               NULL, &child,
                                               NULL, NULL,
@@ -3199,6 +3231,8 @@ do_shape_combine_region (GdkWindow       *window,
                         gint             offset_y,
                         gint             shape)
 {
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
@@ -3237,7 +3271,7 @@ do_shape_combine_region (GdkWindow       *window,
       XRectangle *xrects = NULL;
 
       _gdk_x11_region_get_xrectangles (shape_region,
-                                       0, 0,
+                                       0, 0, impl->window_scale,
                                        &xrects, &n_rects);
       
       if (shape == ShapeBounding)
@@ -3248,7 +3282,8 @@ do_shape_combine_region (GdkWindow       *window,
       XShapeCombineRectangles (GDK_WINDOW_XDISPLAY (window),
                                GDK_WINDOW_XID (window),
                                shape,
-                               offset_x, offset_y,
+                               offset_x * impl->window_scale,
+                               offset_y * impl->window_scale,
                                xrects, n_rects,
                                ShapeSet,
                                YXBanded);
@@ -4307,6 +4342,7 @@ gdk_x11_window_set_functions (GdkWindow    *window,
 cairo_region_t *
 _gdk_x11_xwindow_get_shape (Display *xdisplay,
                             Window   window,
+                            gint     scale,
                             gint     shape_type)
 {
   cairo_region_t *shape;
@@ -4340,13 +4376,15 @@ _gdk_x11_xwindow_get_shape (Display *xdisplay,
       return NULL;
     }
 
+  /* NOTE: The scale divisions here may lose some precision if someone
+     else set the shape to be non-scale precision */
   rl = g_new (GdkRectangle, rn);
   for (i = 0; i < rn; i++)
     {
-      rl[i].x = xrl[i].x;
-      rl[i].y = xrl[i].y;
-      rl[i].width = xrl[i].width;
-      rl[i].height = xrl[i].height;
+      rl[i].x = xrl[i].x / scale;
+      rl[i].y = xrl[i].y / scale;
+      rl[i].width = xrl[i].width / scale;
+      rl[i].height = xrl[i].height / scale;
     }
   XFree (xrl);
 
@@ -4360,10 +4398,13 @@ _gdk_x11_xwindow_get_shape (Display *xdisplay,
 static cairo_region_t *
 gdk_x11_window_get_shape (GdkWindow *window)
 {
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
   if (!GDK_WINDOW_DESTROYED (window) &&
       gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
     return _gdk_x11_xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
                                        GDK_WINDOW_XID (window),
+                                       impl->window_scale,
                                        ShapeBounding);
 
   return NULL;
@@ -4373,10 +4414,13 @@ static cairo_region_t *
 gdk_x11_window_get_input_shape (GdkWindow *window)
 {
 #if defined(ShapeInput)
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
   if (!GDK_WINDOW_DESTROYED (window) &&
       gdk_display_supports_input_shapes (GDK_WINDOW_DISPLAY (window)))
     return _gdk_x11_xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
                                        GDK_WINDOW_XID (window),
+                                       impl->window_scale,
                                        ShapeInput);
 #endif
 
@@ -4467,6 +4511,7 @@ wmspec_send_message (GdkDisplay *display,
                      gint        action,
                      gint        button)
 {
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
   XClientMessageEvent xclient;
 
   memset (&xclient, 0, sizeof (xclient));
@@ -4475,8 +4520,8 @@ wmspec_send_message (GdkDisplay *display,
   xclient.message_type =
     gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_MOVERESIZE");
   xclient.format = 32;
-  xclient.data.l[0] = root_x;
-  xclient.data.l[1] = root_y;
+  xclient.data.l[0] = root_x * impl->window_scale;
+  xclient.data.l[1] = root_y * impl->window_scale;
   xclient.data.l[2] = action;
   xclient.data.l[3] = button;
   xclient.data.l[4] = 1;  /* source indication */
@@ -4798,6 +4843,7 @@ _gdk_x11_moveresize_handle_event (XEvent *event)
   guint button_mask = 0;
   GdkDisplay *display = gdk_x11_lookup_xdisplay (event->xany.display);
   MoveResizeData *mv_resize = get_move_resize_data (display, FALSE);
+  GdkWindowImplX11 *impl;
 
   if (!mv_resize || !mv_resize->moveresize_window)
     {
@@ -4805,6 +4851,8 @@ _gdk_x11_moveresize_handle_event (XEvent *event)
       return FALSE;
     }
 
+  impl = GDK_WINDOW_IMPL_X11 (mv_resize->moveresize_window->impl);
+
   button_mask = GDK_BUTTON1_MASK << (mv_resize->moveresize_button - 1);
 
   switch (event->xany.type)
@@ -4824,8 +4872,8 @@ _gdk_x11_moveresize_handle_event (XEvent *event)
         break;
 
       update_pos (mv_resize,
-                  event->xmotion.x_root,
-                  event->xmotion.y_root);
+                  event->xmotion.x_root / impl->window_scale,
+                  event->xmotion.y_root / impl->window_scale);
 
       /* This should never be triggered in normal cases, but in the
        * case where the drag started without an implicit grab being
@@ -4839,8 +4887,8 @@ _gdk_x11_moveresize_handle_event (XEvent *event)
 
     case ButtonRelease:
       update_pos (mv_resize,
-                  event->xbutton.x_root,
-                  event->xbutton.y_root);
+                  event->xbutton.x_root / impl->window_scale,
+                  event->xbutton.y_root / impl->window_scale);
 
       if (event->xbutton.button == mv_resize->moveresize_button)
         finish_drag (mv_resize);
@@ -4856,14 +4904,14 @@ _gdk_x11_moveresize_handle_event (XEvent *event)
         switch (ev->evtype)
           {
           case XI_Motion:
-            update_pos (mv_resize, xev->root_x, xev->root_y);
+            update_pos (mv_resize, xev->root_x / impl->window_scale, xev->root_y / impl->window_scale);
             state = _gdk_x11_device_xi2_translate_state (&xev->mods, &xev->buttons, &xev->group);
             if ((state & button_mask) == 0)
             finish_drag (mv_resize);
             break;
 
           case XI_ButtonRelease:
-            update_pos (mv_resize, xev->root_x, xev->root_y);
+            update_pos (mv_resize, xev->root_x / impl->window_scale, xev->root_y / impl->window_scale);
             if (xev->detail == mv_resize->moveresize_button)
               finish_drag (mv_resize);
             break;
@@ -5307,6 +5355,17 @@ gdk_x11_window_get_xid (GdkWindow *window)
   return GDK_WINDOW_IMPL_X11 (window->impl)->xid;
 }
 
+static gint
+gdk_x11_window_get_scale_factor (GdkWindow *window)
+{
+  GdkWindowImplX11 *impl = GDK_WINDOW_IMPL_X11 (window->impl);
+
+  if (GDK_WINDOW_DESTROYED (window))
+    return 1;
+
+  return impl->window_scale;
+}
+
 static void
 gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
 {
@@ -5394,4 +5453,5 @@ gdk_window_impl_x11_class_init (GdkWindowImplX11Class *klass)
   impl_class->get_property = _gdk_x11_window_get_property;
   impl_class->change_property = _gdk_x11_window_change_property;
   impl_class->delete_property = _gdk_x11_window_delete_property;
+  impl_class->get_scale_factor = gdk_x11_window_get_scale_factor;
 }
diff --git a/gdk/x11/gdkwindow-x11.h b/gdk/x11/gdkwindow-x11.h
index 5079b5d..5a9b31d 100644
--- a/gdk/x11/gdkwindow-x11.h
+++ b/gdk/x11/gdkwindow-x11.h
@@ -64,6 +64,8 @@ struct _GdkWindowImplX11
 
   Window xid;
 
+  gint window_scale;
+
   GdkToplevelX11 *toplevel;    /* Toplevel-specific information */
   GdkCursor *cursor;
   GHashTable *device_cursor;


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