x11: Add support for _GTK_EDGE_CONSTRAINTS atom
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>
Fri, 18 Aug 2017 23:09:15 +0000 (20:09 -0300)
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>
Tue, 3 Oct 2017 23:06:46 +0000 (20:06 -0300)
Following the previous patch, where edge constraints support
was added to the Wayland backend, this patch introduces the
necessary code to handle the _GTK_EDGE_CONSTRAINTS atom from
X11 backend.

https://bugzilla.gnome.org/show_bug.cgi?id=783669

gdk/x11/gdkdisplay-x11.c
gdk/x11/gdkwindow-x11.h

index ad65e297b1aadae97e8e9338e3665d398da2f03e..e9a263f23dd6d0014c96a366f5e0ab46d387665f 100644 (file)
@@ -189,6 +189,147 @@ gdk_x11_display_event_translator_init (GdkEventTranslatorIface *iface)
   iface->translate_event = gdk_x11_display_translate_event;
 }
 
+static void
+do_edge_constraint_state_check (GdkWindow      *window,
+                                GdkWindowState  old_state,
+                                GdkWindowState *set,
+                                GdkWindowState *unset)
+{
+  GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+  GdkWindowState local_set, local_unset;
+  GdkScreen *screen = GDK_WINDOW_SCREEN (window);
+  guint edge_constraints;
+
+  local_set = *set;
+  local_unset = *unset;
+  edge_constraints = toplevel->edge_constraints;
+
+  /* If the WM doesn't support _GTK_EDGE_CONSTRAINTS, rely on the fallback
+   * implementation. If it supports _GTK_EDGE_CONSTRAINTS, however, remove
+   * the GDK_WINDOW_STATE_TILED flag explicitly.
+   */
+  if (!gdk_x11_screen_supports_net_wm_hint (screen,
+                                            gdk_atom_intern_static_string ("_GTK_EDGE_CONSTRAINTS")))
+    {
+      /* FIXME: we rely on implementation details of mutter here:
+       * mutter only tiles horizontally, and sets maxvert when it does
+       * and if it tiles, it always affects all edges
+       */
+      if (old_state & GDK_WINDOW_STATE_TILED)
+        {
+          if (!toplevel->have_maxvert)
+            local_unset |= GDK_WINDOW_STATE_TILED;
+        }
+      else
+        {
+          if (toplevel->have_maxvert && !toplevel->have_maxhorz)
+            local_set |= GDK_WINDOW_STATE_TILED;
+        }
+    }
+  else
+    {
+      if (!(old_state & GDK_WINDOW_STATE_TILED))
+        {
+          local_set |= GDK_WINDOW_STATE_TILED;
+        }
+    }
+
+  /* Top edge */
+  if (old_state & GDK_WINDOW_STATE_TOP_TILED)
+    {
+      if ((edge_constraints & GDK_WINDOW_STATE_TOP_TILED) == 0)
+        local_unset |= GDK_WINDOW_STATE_TOP_TILED;
+    }
+  else
+    {
+      if (edge_constraints & GDK_WINDOW_STATE_TOP_TILED)
+        local_set |= GDK_WINDOW_STATE_TOP_TILED;
+    }
+
+  if (old_state & GDK_WINDOW_STATE_TOP_RESIZABLE)
+    {
+      if ((edge_constraints & GDK_WINDOW_STATE_TOP_RESIZABLE) == 0)
+        local_unset |= GDK_WINDOW_STATE_TOP_RESIZABLE;
+    }
+  else
+    {
+      if (edge_constraints & GDK_WINDOW_STATE_TOP_RESIZABLE)
+        local_set |= GDK_WINDOW_STATE_TOP_RESIZABLE;
+    }
+
+  /* Right edge */
+  if (old_state & GDK_WINDOW_STATE_RIGHT_TILED)
+    {
+      if ((edge_constraints & GDK_WINDOW_STATE_RIGHT_TILED) == 0)
+        local_unset |= GDK_WINDOW_STATE_RIGHT_TILED;
+    }
+  else
+    {
+      if (edge_constraints & GDK_WINDOW_STATE_RIGHT_TILED)
+        local_set |= GDK_WINDOW_STATE_RIGHT_TILED;
+    }
+
+  if (old_state & GDK_WINDOW_STATE_RIGHT_RESIZABLE)
+    {
+      if ((edge_constraints & GDK_WINDOW_STATE_RIGHT_RESIZABLE) == 0)
+        local_unset |= GDK_WINDOW_STATE_RIGHT_RESIZABLE;
+    }
+  else
+    {
+      if (edge_constraints & GDK_WINDOW_STATE_RIGHT_RESIZABLE)
+        local_set |= GDK_WINDOW_STATE_RIGHT_RESIZABLE;
+    }
+
+  /* Bottom edge */
+  if (old_state & GDK_WINDOW_STATE_BOTTOM_TILED)
+    {
+      if ((edge_constraints & GDK_WINDOW_STATE_BOTTOM_TILED) == 0)
+        local_unset |= GDK_WINDOW_STATE_BOTTOM_TILED;
+    }
+  else
+    {
+      if (edge_constraints & GDK_WINDOW_STATE_BOTTOM_TILED)
+        local_set |= GDK_WINDOW_STATE_BOTTOM_TILED;
+    }
+
+  if (old_state & GDK_WINDOW_STATE_BOTTOM_RESIZABLE)
+    {
+      if ((edge_constraints & GDK_WINDOW_STATE_BOTTOM_RESIZABLE) == 0)
+        local_unset |= GDK_WINDOW_STATE_BOTTOM_RESIZABLE;
+    }
+  else
+    {
+      if (edge_constraints & GDK_WINDOW_STATE_BOTTOM_RESIZABLE)
+        local_set |= GDK_WINDOW_STATE_BOTTOM_RESIZABLE;
+    }
+
+  /* Left edge */
+  if (old_state & GDK_WINDOW_STATE_LEFT_TILED)
+    {
+      if ((edge_constraints & GDK_WINDOW_STATE_LEFT_TILED) == 0)
+        local_unset |= GDK_WINDOW_STATE_LEFT_TILED;
+    }
+  else
+    {
+      if (edge_constraints & GDK_WINDOW_STATE_LEFT_TILED)
+        local_set |= GDK_WINDOW_STATE_LEFT_TILED;
+    }
+
+  if (old_state & GDK_WINDOW_STATE_LEFT_RESIZABLE)
+    {
+      if ((edge_constraints & GDK_WINDOW_STATE_LEFT_RESIZABLE) == 0)
+        local_unset |= GDK_WINDOW_STATE_LEFT_RESIZABLE;
+    }
+  else
+    {
+      if (edge_constraints & GDK_WINDOW_STATE_LEFT_RESIZABLE)
+        local_set |= GDK_WINDOW_STATE_LEFT_RESIZABLE;
+    }
+
+  *set = local_set;
+  *unset = local_unset;
+}
+
 static void
 do_net_wm_state_changes (GdkWindow *window)
 {
@@ -242,21 +383,6 @@ do_net_wm_state_changes (GdkWindow *window)
         set |= GDK_WINDOW_STATE_MAXIMIZED;
     }
 
-  /* FIXME: we rely on implementation details of mutter here:
-   * mutter only tiles horizontally, and sets maxvert when it does
-   * and if it tiles, it always affects all edges
-   */
-  if (old_state & GDK_WINDOW_STATE_TILED)
-    {
-      if (!toplevel->have_maxvert)
-        unset |= GDK_WINDOW_STATE_TILED;
-    }
-  else
-    {
-      if (toplevel->have_maxvert && !toplevel->have_maxhorz)
-        set |= GDK_WINDOW_STATE_TILED;
-    }
-
   if (old_state & GDK_WINDOW_STATE_FOCUSED)
     {
       if (!toplevel->have_focused)
@@ -279,6 +405,9 @@ do_net_wm_state_changes (GdkWindow *window)
         set |= GDK_WINDOW_STATE_ICONIFIED;
     }
 
+  /* Update edge constraints and tiling */
+  do_edge_constraint_state_check (window, old_state, &set, &unset);
+
   gdk_synthesize_window_state (window, unset, set);
 }
 
@@ -395,6 +524,49 @@ gdk_check_wm_state_changed (GdkWindow *window)
     do_net_wm_state_changes (window);
 }
 
+static void
+gdk_check_edge_constraints_changed (GdkWindow *window)
+{
+  GdkToplevelX11 *toplevel = _gdk_x11_window_get_toplevel (window);
+  GdkDisplay *display = GDK_WINDOW_DISPLAY (window);
+
+  Atom type;
+  gint format;
+  gulong nitems;
+  gulong bytes_after;
+  guchar *data;
+  gulong *constraints;
+
+  type = None;
+  gdk_x11_display_error_trap_push (display);
+  XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
+                      GDK_WINDOW_XID (window),
+                      gdk_x11_get_xatom_by_name_for_display (display, "_GTK_EDGE_CONSTRAINTS"),
+                      0, G_MAXLONG, False, XA_CARDINAL, &type,
+                      &format, &nitems,
+                      &bytes_after, &data);
+  gdk_x11_display_error_trap_pop_ignored (display);
+
+  if (type != None)
+    {
+      constraints = (gulong *)data;
+
+      /* The GDK enum for these states does not begin at zero so, to avoid
+       * messing around with shifts, just make the passed value and GDK's
+       * enum values match by shifting to the first tiled state.
+       */
+      toplevel->edge_constraints = constraints[0] << 9;
+
+      XFree (constraints);
+    }
+  else
+    {
+      toplevel->edge_constraints = 0;
+    }
+
+  do_net_wm_state_changes (window);
+}
+
 static Window
 get_event_xwindow (XEvent             *xevent)
 {
@@ -879,6 +1051,9 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
 
          if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP"))
            gdk_check_wm_desktop_changed (window);
+
+         if (xevent->xproperty.atom == gdk_x11_get_xatom_by_name_for_display (display, "_GTK_EDGE_CONSTRAINTS"))
+           gdk_check_edge_constraints_changed (window);
        }
 
       if (window->event_mask & GDK_PROPERTY_CHANGE_MASK)
index ed0cbb6cf38758ad93d5592a0a3dc41bfd4b2e44..2b5749c4bdac97020132b25de842769c46e198ec 100644 (file)
@@ -166,6 +166,9 @@ struct _GdkToplevelX11
   GdkWindowHints last_geometry_hints_mask;
   GdkGeometry last_geometry_hints;
   
+  /* Constrained edge information */
+  guint edge_constraints;
+
 #ifdef HAVE_XSYNC
   XID update_counter;
   XID extended_update_counter;