gdk/toplevel: Add gdk_toplevel_titlebar_gesture()

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
This commit is contained in:
Florian Müllner 2021-07-29 03:55:36 +02:00
parent cc6ecc8b62
commit 0c7b1431d7
6 changed files with 118 additions and 3 deletions

View 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);
}

View 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__ */

View File

@ -38,6 +38,8 @@ struct _GdkToplevelInterface
double x,
double y,
guint32 timestamp);
gboolean (* titlebar_gesture) (GdkToplevel *toplevel,
GdkTitlebarGesture gesture);
};
typedef enum

View 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

View 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;

View 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"/>
@ -85,6 +85,23 @@
<!-- 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>