[gtk/wip/muktupavels/work-areas: 57/57] x11: add support for _NET_WORKAREAS_Dn



commit b2b240d7d8983f3c2d414b7d51a619da6736c9f6
Author: Alberts Muktupāvels <alberts muktupavels gmail com>
Date:   Mon Jan 13 00:38:12 2020 +0200

    x11: add support for _NET_WORKAREAS_Dn
    
    If window manager supports _NET_WORKAREAS use per-monitor work areas.
    
    https://mail.gnome.org/archives/wm-spec-list/2018-December/msg00000.html
    https://gitlab.freedesktop.org/xdg/xdg-specs/merge_requests/22
    
    https://gitlab.gnome.org/GNOME/gtk/merge_requests/1300

 gdk/x11/gdkmonitor-x11.c | 28 +++++++++-----
 gdk/x11/gdkscreen-x11.c  | 99 ++++++++++++++++++++++++++++++++++++++++++++++++
 gdk/x11/gdkscreen-x11.h  |  3 ++
 3 files changed, 120 insertions(+), 10 deletions(-)
---
diff --git a/gdk/x11/gdkmonitor-x11.c b/gdk/x11/gdkmonitor-x11.c
index 34d88e98f8..2ed77b9b81 100644
--- a/gdk/x11/gdkmonitor-x11.c
+++ b/gdk/x11/gdkmonitor-x11.c
@@ -67,19 +67,27 @@ gdk_x11_monitor_get_workarea (GdkMonitor   *monitor,
 
   gdk_monitor_get_geometry (monitor, dest);
 
-  /* The EWMH constrains workarea to be a rectangle, so it
-   * can't adequately deal with L-shaped monitor arrangements.
-   * As a workaround, we ignore the workarea for anything
-   * but the primary monitor. Since that is where the 'desktop
-   * chrome' usually lives, this works ok in practice.
-   */
-  if (gdk_monitor_is_primary (monitor) &&
-      !gdk_monitor_has_fullscreen_window (monitor))
+  if (_gdk_x11_screen_get_monitor_work_area (screen, monitor, &workarea))
     {
-      gdk_x11_screen_get_work_area (screen, &workarea);
-      if (gdk_rectangle_intersect (dest, &workarea, &workarea))
+      if (!gdk_monitor_has_fullscreen_window (monitor))
         *dest = workarea;
     }
+  else
+    {
+      /* The EWMH constrains workarea to be a rectangle, so it
+       * can't adequately deal with L-shaped monitor arrangements.
+       * As a workaround, we ignore the workarea for anything
+       * but the primary monitor. Since that is where the 'desktop
+       * chrome' usually lives, this works ok in practice.
+       */
+      if (gdk_monitor_is_primary (monitor) &&
+          !gdk_monitor_has_fullscreen_window (monitor))
+        {
+          gdk_x11_screen_get_work_area (screen, &workarea);
+          if (gdk_rectangle_intersect (dest, &workarea, &workarea))
+            *dest = workarea;
+        }
+    }
 }
 
 static void
diff --git a/gdk/x11/gdkscreen-x11.c b/gdk/x11/gdkscreen-x11.c
index ffba0708f7..f5f2579ed6 100644
--- a/gdk/x11/gdkscreen-x11.c
+++ b/gdk/x11/gdkscreen-x11.c
@@ -179,6 +179,105 @@ get_current_desktop (GdkX11Screen *screen)
   return workspace;
 }
 
+gboolean
+_gdk_x11_screen_get_monitor_work_area (GdkX11Screen *x11_screen,
+                                       GdkMonitor   *monitor,
+                                       GdkRectangle *area)
+{
+  Display *xdisplay;
+  Atom net_workareas;
+  int current_desktop;
+  char *workareas_dn_name;
+  Atom workareas_dn;
+  int screen_number;
+  Window xroot;
+  int result;
+  Atom type;
+  int format;
+  gulong num;
+  gulong leftovers;
+  guchar *ret_workarea;
+  long *workareas;
+  GdkRectangle geometry;
+  int i;
+
+  if (!gdk_x11_screen_supports_net_wm_hint (x11_screen,
+                                            g_intern_static_string ("_NET_WORKAREAS")))
+    return FALSE;
+
+  xdisplay = gdk_x11_display_get_xdisplay (x11_screen->display);
+  net_workareas = XInternAtom (xdisplay, "_NET_WORKAREAS", False);
+
+  if (net_workareas == None)
+    return FALSE;
+
+  current_desktop = get_current_desktop (x11_screen);
+  workareas_dn_name = g_strdup_printf ("_NET_WORKAREAS_D%d", current_desktop);
+  workareas_dn = XInternAtom (xdisplay, workareas_dn_name, True);
+  g_free (workareas_dn_name);
+
+  if (workareas_dn == None)
+    return FALSE;
+
+  screen_number = gdk_x11_screen_get_screen_number (x11_screen);
+  xroot = XRootWindow (xdisplay, screen_number);
+
+  gdk_x11_display_error_trap_push (x11_screen->display);
+
+  ret_workarea = NULL;
+  result = XGetWindowProperty (xdisplay,
+                               xroot,
+                               workareas_dn,
+                               0,
+                               G_MAXLONG,
+                               False,
+                               AnyPropertyType,
+                               &type,
+                               &format,
+                               &num,
+                               &leftovers,
+                               &ret_workarea);
+
+  gdk_x11_display_error_trap_pop_ignored (x11_screen->display);
+
+  if (result != Success ||
+      type == None ||
+      format == 0 ||
+      leftovers ||
+      num % 4 != 0)
+    {
+      XFree (ret_workarea);
+
+      return FALSE;
+    }
+
+  workareas = (long *) ret_workarea;
+
+  gdk_monitor_get_geometry (monitor, &geometry);
+  *area = geometry;
+
+  for (i = 0; i < num / 4; i++)
+    {
+      GdkRectangle work_area;
+
+      work_area = (GdkRectangle) {
+        .x = workareas[0] / x11_screen->surface_scale,
+        .y = workareas[1] / x11_screen->surface_scale,
+        .width = workareas[2] / x11_screen->surface_scale,
+        .height = workareas[3] / x11_screen->surface_scale,
+      };
+
+      if (gdk_rectangle_intersect (area, &work_area, &work_area))
+        *area = work_area;
+
+      workareas += 4;
+    }
+
+  XFree (ret_workarea);
+
+  return TRUE;
+}
+
 void
 gdk_x11_screen_get_work_area (GdkX11Screen *x11_screen,
                               GdkRectangle *area)
diff --git a/gdk/x11/gdkscreen-x11.h b/gdk/x11/gdkscreen-x11.h
index aa5e063447..348a3ef323 100644
--- a/gdk/x11/gdkscreen-x11.h
+++ b/gdk/x11/gdkscreen-x11.h
@@ -108,6 +108,9 @@ void _gdk_x11_screen_get_edge_monitors      (GdkX11Screen *screen,
                                              gint         *right);
 void _gdk_x11_screen_set_surface_scale      (GdkX11Screen *x11_screen,
                                              int           scale);
+gboolean _gdk_x11_screen_get_monitor_work_area (GdkX11Screen *screen,
+                                                GdkMonitor   *monitor,
+                                                GdkRectangle *area);
 void gdk_x11_screen_get_work_area           (GdkX11Screen *screen,
                                              GdkRectangle *area);
 gboolean gdk_x11_screen_get_setting         (GdkX11Screen *screen,


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