gdk/toplevel: Add gdk_toplevel_titlebar_gesture()
authorFlorian Müllner <fmuellner@gnome.org>
Thu, 29 Jul 2021 01:55:36 +0000 (03:55 +0200)
committerFlorian Müllner <fmuellner@gnome.org>
Thu, 29 Jul 2021 19:39:32 +0000 (21:39 +0200)
Where supported, this allows delegating the titlebar action to the
compositor instead of trying to replicate its behavior client-side.

https://gitlab.gnome.org/GNOME/mutter/-/issues/602

gdk/gdktoplevel.c
gdk/gdktoplevel.h
gdk/gdktoplevelprivate.h
gdk/wayland/gdkdisplay-wayland.c
gdk/wayland/gdksurface-wayland.c
gdk/wayland/protocol/gtk-shell.xml

index d50a88675da448e9dd24df655def3101c381f126..f020d81765e21ad236d911267bdd3a9380b0011d 100644 (file)
@@ -78,6 +78,13 @@ gdk_toplevel_default_show_window_menu (GdkToplevel *toplevel,
   return FALSE;
 }
 
+static gboolean
+gdk_toplevel_default_titlebar_gesture (GdkToplevel        *toplevel,
+                                       GdkTitlebarGesture  gesture)
+{
+  return FALSE;
+}
+
 static gboolean
 gdk_toplevel_default_supports_edge_constraints (GdkToplevel *toplevel)
 {
@@ -114,6 +121,7 @@ gdk_toplevel_default_init (GdkToplevelInterface *iface)
   iface->supports_edge_constraints = gdk_toplevel_default_supports_edge_constraints;
   iface->inhibit_system_shortcuts = gdk_toplevel_default_inhibit_system_shortcuts;
   iface->restore_system_shortcuts = gdk_toplevel_default_restore_system_shortcuts;
+  iface->titlebar_gesture = gdk_toplevel_default_titlebar_gesture;
 
   /**
    * GdkToplevel:state: (attributes org.gtk.Property.get=gdk_toplevel_get_state)
@@ -716,3 +724,13 @@ gdk_toplevel_begin_move (GdkToplevel *toplevel,
                                                  x, y,
                                                  timestamp);
 }
+
+gboolean
+gdk_toplevel_titlebar_gesture (GdkToplevel        *toplevel,
+                               GdkTitlebarGesture  gesture)
+{
+  g_return_val_if_fail (GDK_IS_TOPLEVEL (toplevel), FALSE);
+
+  return GDK_TOPLEVEL_GET_IFACE (toplevel)->titlebar_gesture (toplevel,
+                                                              gesture);
+}
index 1d3f9c627d5a9889a8d5df5b3f44b65f0760f0cf..68613a902455e410fba3a027130d9d25ee4ecf9a 100644 (file)
@@ -115,6 +115,13 @@ typedef enum
   GDK_TOPLEVEL_STATE_LEFT_RESIZABLE   = 1 << 15
 } GdkToplevelState;
 
+typedef enum
+{
+  GDK_TITLEBAR_GESTURE_DOUBLE_CLICK   = 1,
+  GDK_TITLEBAR_GESTURE_RIGHT_CLICK    = 2,
+  GDK_TITLEBAR_GESTURE_MIDDLE_CLICK   = 3
+} GdkTitlebarGesture;
+
 
 #define GDK_TYPE_TOPLEVEL (gdk_toplevel_get_type ())
 
@@ -196,6 +203,10 @@ void          gdk_toplevel_begin_move                (GdkToplevel    *toplevel,
                                                       double          y,
                                                       guint32         timestamp);
 
+GDK_AVAILABLE_IN_4_4
+gboolean      gdk_toplevel_titlebar_gesture          (GdkToplevel        *toplevel,
+                                                      GdkTitlebarGesture  gesture);
+
 G_END_DECLS
 
 #endif /* __GDK_TOPLEVEL_H__ */
index 52dcdca0adf767e098a2550a6a93da09bad0bc7f..2d1f0122f36fb98d1cf8b9ef8b8d7bf25ebb0df0 100644 (file)
@@ -38,6 +38,8 @@ struct _GdkToplevelInterface
                                          double             x,
                                          double             y,
                                          guint32            timestamp);
+  gboolean      (* titlebar_gesture)    (GdkToplevel       *toplevel,
+                                         GdkTitlebarGesture gesture);
 };
 
 typedef enum
index 0312411e0c3591075e1492133451bc01f8784f01..ad033076b41796f9cff07b72058e66ffd9d50147 100644 (file)
@@ -87,7 +87,7 @@
 
 #define MIN_SYSTEM_BELL_DELAY_MS 20
 
-#define GTK_SHELL1_VERSION       4
+#define GTK_SHELL1_VERSION       5
 #define OUTPUT_VERSION_WITH_DONE 2
 #define NO_XDG_OUTPUT_DONE_SINCE_VERSION 3
 #define XDG_ACTIVATION_VERSION   1
index 5689241c7dee3ec24e39b615bc2b704a753e7244..84ec54a335db36839e0db38deb3e8e4ca90c4e6a 100644 (file)
@@ -4190,6 +4190,65 @@ gdk_wayland_surface_show_window_menu (GdkSurface *surface,
   return TRUE;
 }
 
+static gboolean
+translate_gesture (GdkTitlebarGesture         gesture,
+                   enum gtk_surface1_gesture *out_gesture)
+{
+  switch (gesture)
+    {
+    case GDK_TITLEBAR_GESTURE_DOUBLE_CLICK:
+      *out_gesture = GTK_SURFACE1_GESTURE_DOUBLE_CLICK;
+      break;
+
+    case GDK_TITLEBAR_GESTURE_RIGHT_CLICK:
+      *out_gesture = GTK_SURFACE1_GESTURE_RIGHT_CLICK;
+      break;
+
+    case GDK_TITLEBAR_GESTURE_MIDDLE_CLICK:
+      *out_gesture = GTK_SURFACE1_GESTURE_MIDDLE_CLICK;
+      break;
+
+    default:
+      g_warning ("Not handling unknown titlebar gesture %u", gesture);
+      return FALSE;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+gdk_wayland_surface_titlebar_gesture (GdkSurface         *surface,
+                                      GdkTitlebarGesture  gesture)
+{
+  GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
+  struct gtk_surface1 *gtk_surface = impl->display_server.gtk_surface;
+  enum gtk_surface1_gesture gtk_gesture;
+  GdkSeat *seat;
+  struct wl_seat *wl_seat;
+  uint32_t serial;
+
+  if (!gtk_surface)
+    return FALSE;
+
+  if (gtk_surface1_get_version (gtk_surface) < GTK_SURFACE1_TITLEBAR_GESTURE_SINCE_VERSION)
+    return FALSE;
+
+  if (!translate_gesture (gesture, &gtk_gesture))
+    return FALSE;
+
+  seat = gdk_display_get_default_seat (surface->display);
+  wl_seat = gdk_wayland_seat_get_wl_seat (seat);
+
+  serial = _gdk_wayland_seat_get_last_implicit_grab_serial (GDK_WAYLAND_SEAT (seat), NULL);
+
+  gtk_surface1_titlebar_gesture (impl->display_server.gtk_surface,
+                                 serial,
+                                 wl_seat,
+                                 gtk_gesture);
+
+  return TRUE;
+}
+
 static gboolean
 gdk_wayland_surface_supports_edge_constraints (GdkSurface *surface)
 {
@@ -4987,6 +5046,13 @@ gdk_wayland_toplevel_show_window_menu (GdkToplevel *toplevel,
   return gdk_wayland_surface_show_window_menu (GDK_SURFACE (toplevel), event);
 }
 
+static gboolean
+gdk_wayland_toplevel_titlebar_gesture (GdkToplevel        *toplevel,
+                                       GdkTitlebarGesture  gesture)
+{
+  return gdk_wayland_surface_titlebar_gesture (GDK_SURFACE (toplevel), gesture);
+}
+
 static gboolean
 gdk_wayland_toplevel_supports_edge_constraints (GdkToplevel *toplevel)
 {
@@ -5065,6 +5131,7 @@ gdk_wayland_toplevel_iface_init (GdkToplevelInterface *iface)
   iface->lower = gdk_wayland_toplevel_lower;
   iface->focus = gdk_wayland_toplevel_focus;
   iface->show_window_menu = gdk_wayland_toplevel_show_window_menu;
+  iface->titlebar_gesture = gdk_wayland_toplevel_titlebar_gesture;
   iface->supports_edge_constraints = gdk_wayland_toplevel_supports_edge_constraints;
   iface->inhibit_system_shortcuts = gdk_wayland_toplevel_inhibit_system_shortcuts;
   iface->restore_system_shortcuts = gdk_wayland_toplevel_restore_system_shortcuts;
index 1aab593c424832597e39171d9204b22f87907207..a8d51c65d39af98cbf27bd0ceb6f77f7952ccdf3 100644 (file)
@@ -1,6 +1,6 @@
 <protocol name="gtk">
 
-  <interface name="gtk_shell1" version="4">
+  <interface name="gtk_shell1" version="5">
     <description summary="gtk specific extensions">
       gtk_shell is a protocol extension providing additional features for
       clients implementing it.
@@ -35,7 +35,7 @@
     </request>
   </interface>
 
-  <interface name="gtk_surface1" version="4">
+  <interface name="gtk_surface1" version="5">
     <request name="set_dbus_properties">
       <arg name="application_id" type="string" allow-null="true"/>
       <arg name="app_menu_path" type="string" allow-null="true"/>
 
     <!-- Version 4 additions -->
     <request name="release" type="destructor" since="4"/>
+
+    <!-- Version 5 additions -->
+    <enum name="gesture" since="5">
+      <entry name="double_click" value="1"/>
+      <entry name="right_click" value="2"/>
+      <entry name="middle_click" value="3"/>
+    </enum>
+
+    <enum name="error" since="5">
+      <entry name="invalid_gesture" value="0"/>
+    </enum>
+
+    <request name="titlebar_gesture" since="5">
+      <arg name="serial" type="uint"/>
+      <arg name="seat" type="object" interface="wl_seat"/>
+      <arg name="gesture" type="uint" enum="gesture"/>
+    </request>
   </interface>
 
 </protocol>