FLTK logo

[master] 70a9c4d - Update libdecor to upstream commit 09875530 dated March 3, 2024

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[master] 70a9c4d - Update libdecor to upstream commit 09875530 dated March 3, 2024 "ManoloFLTK" 06:17 Mar 12  
 
commit 70a9c4d40768a1221dcc8fd9614aec55f0496394
Author:     ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>
AuthorDate: Tue Mar 12 14:09:35 2024 +0100
Commit:     ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>
CommitDate: Tue Mar 12 14:09:35 2024 +0100

    Update libdecor to upstream commit 09875530 dated March 3, 2024

 documentation/src/bundled-libs.dox      |   4 +-
 libdecor/build/fl_libdecor-plugins.c    |  64 +++---
 libdecor/build/fl_libdecor.c            |   2 +-
 libdecor/src/libdecor.c                 |  85 +++++++-
 libdecor/src/libdecor.h                 |  50 ++++-
 libdecor/src/plugins/gtk/libdecor-gtk.c | 353 ++++++++++++++++++++++----------
 6 files changed, 418 insertions(+), 140 deletions(-)

diff --git documentation/src/bundled-libs.dox documentation/src/bundled-libs.dox
index 28e3651..331c8a2 100644
--- documentation/src/bundled-libs.dox
+++ documentation/src/bundled-libs.dox
@@ -23,14 +23,14 @@ The nanosvg library is not affected.
 
 \section bundled-status Current status
 \code
-Current versions of bundled libraries (as of February 17, 2024):
+Current versions of bundled libraries (as of March 12, 2024):
   Library       Version/git commit Release date         FLTK Version
   --------------------------------------------------------------------------
   jpeg          jpeg-9f            2024-01-14           1.4.0
   nanosvg       7aeda550a8 [1]     2023-12-02           1.4.0
   png           libpng-1.6.42      2024-01-29           1.4.0
   zlib          zlib-1.3.1         2024-01-22           1.4.0
-  libdecor      7807ae34   [2]     2024-01-15           1.4.0
+  libdecor      09875530   [2]     2024-03-03           1.4.0
   --------------------------------------------------------------------------
 
 Previous versions of bundled libraries (FLTK 1.3.x):
diff --git libdecor/build/fl_libdecor-plugins.c libdecor/build/fl_libdecor-plugins.c
index 39f3442..fbf4eb6 100644
--- libdecor/build/fl_libdecor-plugins.c
+++ libdecor/build/fl_libdecor-plugins.c
@@ -1,7 +1,7 @@
 //
 // Interface with the libdecor library for the Fast Light Tool Kit (FLTK).
 //
-// Copyright 2022-2023 by Bill Spitzak and others.
+// Copyright 2022-2024 by Bill Spitzak and others.
 //
 // This library is free software. Distribution and use rights are outlined in
 // the file "COPYING" which should have been included with this file.  If this
@@ -26,6 +26,7 @@
 #include <string.h>
 #include "../src/libdecor.h"
 #include <pango/pangocairo.h>
+#include <dlfcn.h>
 
 #ifndef HAVE_GTK
 #  define HAVE_GTK 0
@@ -137,25 +138,6 @@ struct libdecor_frame_cairo {
 
 /* Definitions derived from libdecor-gtk.c */
 
-struct libdecor_plugin_gtk {
-  struct libdecor_plugin plugin;
-  struct wl_callback *globals_callback;
-  struct wl_callback *globals_callback_shm;
-  struct libdecor *context;
-  struct wl_registry *wl_registry;
-  struct wl_subcompositor *wl_subcompositor;
-  struct wl_compositor *wl_compositor;
-  struct wl_shm *wl_shm;
-  struct wl_callback *shm_callback;
-  bool has_argb;
-  struct wl_list visible_frame_list;
-  struct wl_list seat_list;
-  struct wl_list output_list;
-  char *cursor_theme_name;
-  int cursor_size;
-  int double_click_time_ms;
-};
-
 typedef struct _GtkWidget GtkWidget;
 enum header_element { HEADER_NONE }; /* details are not needed */
 
@@ -201,6 +183,15 @@ struct libdecor_frame_gtk {
   struct header_element_data hdr_focus;
   cairo_surface_t *shadow_blur;
   struct wl_list link;
+  struct {
+    enum titlebar_gesture_state {TITLEBAR_GESTURE_STATE_INIT} state;
+    int button_pressed_count;
+    uint32_t first_pressed_button;
+    uint32_t first_pressed_time;
+    double pressed_x;
+    double pressed_y;
+    uint32_t pressed_serial;
+  } titlebar_gesture;
 };
 
 #endif // USE_SYSTEM_LIBDECOR || !HAVE_GTK
@@ -310,9 +301,27 @@ unsigned char *fl_libdecor_titlebar_buffer(struct libdecor_frame *frame,
 }
 
 
-struct libdecor { // copied from libdecor.c
+// When the libdecor version after 0.2.2 will be released, support of older versions
+// will be removed from FLTK. LIBDECOR_MR131 stuff also will be removed.
+struct libdecor_022 { // for libdecor versions â?¤ 0.2.2
+  int ref_count;
+  const struct libdecor_interface *iface;
+  struct libdecor_plugin *plugin;
+  bool plugin_ready;
+  struct wl_display *wl_display;
+  struct wl_registry *wl_registry;
+  struct xdg_wm_base *xdg_wm_base;
+  struct zxdg_decoration_manager_v1 *decoration_manager;
+  struct wl_callback *init_callback;
+  bool init_done;
+  bool has_error;
+  struct wl_list frames;
+};
+
+struct libdecor { // copied from libdecor.c, for libdecor versions > 0.2.2
   int ref_count;
-  struct libdecor_interface *iface;
+  const struct libdecor_interface *iface;
+  void *user_data; // added after libdecor version 0.2.2
   struct libdecor_plugin *plugin;
   bool plugin_ready;
   struct wl_display *wl_display;
@@ -329,9 +338,18 @@ struct libdecor { // copied from libdecor.c
 /* Returns whether surface is a GTK-titlebar created by libdecor-gtk */
 bool fl_is_surface_gtk_titlebar(struct wl_surface *surface, struct libdecor *context) {
   if (!context || get_plugin_kind(NULL) != GTK3) return false;
+  static void *new_symbol = NULL;
+  static bool first = true;
+  if (first) {
+    first = false;
+    // new_symbol is NULL for libdecor versions â?¤ 0.2.2
+    new_symbol = dlsym(RTLD_DEFAULT, "libdecor_frame_get_user_data");
+  }
+  struct wl_list *frames_addr = (new_symbol ? &context->frames :
+                                 &(((struct libdecor_022*)context)->frames) );
   // loop over all decorations created by libdecor-gtk
   struct libdecor_frame *frame;
-  wl_list_for_each(frame, &context->frames, link) {
+  wl_list_for_each(frame, frames_addr, link) {
     struct libdecor_frame_gtk *frame_gtk = (struct libdecor_frame_gtk*)frame;
     if (frame_gtk->headerbar.wl_surface == surface) return true;
   }
diff --git libdecor/build/fl_libdecor.c libdecor/build/fl_libdecor.c
index 978b63d..71a4fc3 100644
--- libdecor/build/fl_libdecor.c
+++ libdecor/build/fl_libdecor.c
@@ -104,7 +104,7 @@ LIBDECOR_EXPORT void libdecor_frame_set_minimized(struct libdecor_frame *frame)
  so a plugin may be loaded that way only if FLTK was built with FLTK_USE_SYSTEM_LIBDECOR turned ON.
  
  */
-LIBDECOR_EXPORT struct libdecor *libdecor_new(struct wl_display *wl_display, struct libdecor_interface *iface)
+LIBDECOR_EXPORT struct libdecor *libdecor_new(struct wl_display *wl_display, const struct libdecor_interface *iface)
 {
   struct libdecor *context;
   context = zalloc(sizeof *context);
diff --git libdecor/src/libdecor.c libdecor/src/libdecor.c
index 6fc184c..3ede712 100644
--- libdecor/src/libdecor.c
+++ libdecor/src/libdecor.c
@@ -51,7 +51,8 @@
 struct libdecor {
 	int ref_count;
 
-	struct libdecor_interface *iface;
+	const struct libdecor_interface *iface;
+	void *user_data;
 
 	struct libdecor_plugin *plugin;
 	bool plugin_ready;
@@ -100,7 +101,7 @@ struct libdecor_frame_private {
 
 	struct wl_surface *wl_surface;
 
-	struct libdecor_frame_interface *iface;
+	const struct libdecor_frame_interface *iface;
 	void *user_data;
 
 	struct xdg_surface *xdg_surface;
@@ -127,6 +128,8 @@ struct libdecor_frame_private {
 
 	enum libdecor_capabilities capabilities;
 
+	enum libdecor_wm_capabilities wm_capabilities;
+
 	/* original limits for interactive resize */
 	struct libdecor_limits interactive_limits;
 
@@ -396,6 +399,9 @@ parse_states(struct wl_array *states)
 		case XDG_TOPLEVEL_STATE_TILED_BOTTOM:
 			pending_state |= LIBDECOR_WINDOW_STATE_TILED_BOTTOM;
 			break;
+		case XDG_TOPLEVEL_STATE_RESIZING:
+			pending_state |= LIBDECOR_WINDOW_STATE_RESIZING;
+			break;
 #ifdef HAVE_XDG_SHELL_V6
 		case XDG_TOPLEVEL_STATE_SUSPENDED:
 			pending_state |= LIBDECOR_WINDOW_STATE_SUSPENDED;
@@ -452,10 +458,34 @@ xdg_toplevel_configure_bounds(void *data,
 }
 
 static void
-xdg_toplevel_wm_capabilities(void *data,
+xdg_toplevel_wm_capabilities(void *user_data,
 			     struct xdg_toplevel *xdg_toplevel,
 			     struct wl_array *capabilities)
 {
+	struct libdecor_frame *frame = user_data;
+	struct libdecor_frame_private *frame_priv = frame->priv;
+	enum xdg_toplevel_wm_capabilities *wm_cap;
+
+	frame_priv->wm_capabilities = 0;
+
+	wl_array_for_each(wm_cap, capabilities) {
+		switch (*wm_cap) {
+		case XDG_TOPLEVEL_WM_CAPABILITIES_WINDOW_MENU:
+			frame_priv->wm_capabilities |= LIBDECOR_WM_CAPABILITIES_WINDOW_MENU;
+			break;
+		case XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE:
+			frame_priv->wm_capabilities |= LIBDECOR_WM_CAPABILITIES_MAXIMIZE;
+			break;
+		case XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN:
+			frame_priv->wm_capabilities |= LIBDECOR_WM_CAPABILITIES_FULLSCREEN;
+			break;
+		case XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE:
+			frame_priv->wm_capabilities |= LIBDECOR_WM_CAPABILITIES_MINIMIZE;
+			break;
+		default:
+			break;
+		}
+	}
 }
 #endif
 
@@ -546,7 +576,7 @@ init_shell_surface(struct libdecor_frame *frame)
 LIBDECOR_EXPORT struct libdecor_frame *
 libdecor_decorate(struct libdecor *context,
 		  struct wl_surface *wl_surface,
-		  struct libdecor_frame_interface *iface,
+		  const struct libdecor_frame_interface *iface,
 		  void *user_data)
 {
 	struct libdecor_plugin *plugin = context->plugin;
@@ -569,6 +599,10 @@ libdecor_decorate(struct libdecor *context,
 	frame_priv->wl_surface = wl_surface;
 	frame_priv->iface = iface;
 	frame_priv->user_data = user_data;
+	frame_priv->wm_capabilities = LIBDECOR_WM_CAPABILITIES_WINDOW_MENU |
+				      LIBDECOR_WM_CAPABILITIES_MAXIMIZE |
+				      LIBDECOR_WM_CAPABILITIES_FULLSCREEN |
+				      LIBDECOR_WM_CAPABILITIES_MINIMIZE;
 
 	wl_list_insert(&context->frames, &frame->link);
 
@@ -628,6 +662,18 @@ libdecor_frame_unref(struct libdecor_frame *frame)
 	}
 }
 
+LIBDECOR_EXPORT void *
+libdecor_frame_get_user_data(struct libdecor_frame *frame)
+{
+	return frame->priv->user_data;
+}
+
+LIBDECOR_EXPORT void
+libdecor_frame_set_user_data(struct libdecor_frame *frame, void *user_data)
+{
+	frame->priv->user_data = user_data;
+}
+
 LIBDECOR_EXPORT void
 libdecor_frame_set_visibility(struct libdecor_frame *frame,
 			      bool visible)
@@ -1235,6 +1281,14 @@ libdecor_frame_get_window_state(struct libdecor_frame *frame)
 	return frame_priv->window_state;
 }
 
+LIBDECOR_EXPORT enum libdecor_wm_capabilities
+libdecor_frame_get_wm_capabilities(struct libdecor_frame *frame)
+{
+	struct libdecor_frame_private *frame_priv = frame->priv;
+
+	return frame_priv->wm_capabilities;
+}
+
 LIBDECOR_EXPORT int
 libdecor_plugin_init(struct libdecor_plugin *plugin,
 		     struct libdecor *context,
@@ -1624,6 +1678,18 @@ retry_next:
 	return 0;
 }
 
+LIBDECOR_EXPORT void *
+libdecor_get_user_data(struct libdecor *context)
+{
+	return context->user_data;
+}
+
+LIBDECOR_EXPORT void
+libdecor_set_user_data(struct libdecor *context, void *user_data)
+{
+	context->user_data = user_data;
+}
+
 LIBDECOR_EXPORT int
 libdecor_get_fd(struct libdecor *context)
 {
@@ -1701,7 +1767,15 @@ libdecor_unref(struct libdecor *context)
 
 LIBDECOR_EXPORT struct libdecor *
 libdecor_new(struct wl_display *wl_display,
-	     struct libdecor_interface *iface)
+	     const struct libdecor_interface *iface)
+{
+	return libdecor_new_with_user_data(wl_display, iface, NULL);
+}
+
+LIBDECOR_EXPORT struct libdecor *
+libdecor_new_with_user_data(struct wl_display *wl_display,
+	     const struct libdecor_interface *iface,
+	     void *user_data)
 {
 	struct libdecor *context;
 
@@ -1709,6 +1783,7 @@ libdecor_new(struct wl_display *wl_display,
 
 	context->ref_count = 1;
 	context->iface = iface;
+	context->user_data = user_data;
 	context->wl_display = wl_display;
 	context->wl_registry = wl_display_get_registry(wl_display);
 	wl_registry_add_listener(context->wl_registry,
diff --git libdecor/src/libdecor.h libdecor/src/libdecor.h
index af67e2f..e52ced0 100644
--- libdecor/src/libdecor.h
+++ libdecor/src/libdecor.h
@@ -82,6 +82,7 @@ enum libdecor_window_state {
 	LIBDECOR_WINDOW_STATE_TILED_TOP = 1 << 5,
 	LIBDECOR_WINDOW_STATE_TILED_BOTTOM = 1 << 6,
 	LIBDECOR_WINDOW_STATE_SUSPENDED = 1 << 7,
+	LIBDECOR_WINDOW_STATE_RESIZING = 1 << 8,
 };
 
 enum libdecor_resize_edge {
@@ -104,6 +105,13 @@ enum libdecor_capabilities {
 	LIBDECOR_ACTION_CLOSE = 1 << 4,
 };
 
+enum libdecor_wm_capabilities {
+	LIBDECOR_WM_CAPABILITIES_WINDOW_MENU = 1 << 0,
+	LIBDECOR_WM_CAPABILITIES_MAXIMIZE = 1 << 1,
+	LIBDECOR_WM_CAPABILITIES_FULLSCREEN = 1 << 2,
+	LIBDECOR_WM_CAPABILITIES_MINIMIZE = 1 << 3
+};
+
 struct libdecor_interface {
 	/**
 	 * An error event
@@ -185,7 +193,27 @@ libdecor_unref(struct libdecor *context);
  */
 struct libdecor *
 libdecor_new(struct wl_display *display,
-	     struct libdecor_interface *iface);
+	     const struct libdecor_interface *iface);
+
+/**
+ * Create a new libdecor context for the given wl_display and attach user data.
+ */
+struct libdecor *
+libdecor_new_with_user_data(struct wl_display *display,
+	     const struct libdecor_interface *iface,
+	     void *user_data);
+
+/**
+ * Get the user data associated with this libdecor context.
+ */
+void *
+libdecor_get_user_data(struct libdecor *context);
+
+/**
+ * Set the user data associated with this libdecor context.
+ */
+void
+libdecor_set_user_data(struct libdecor *context, void *user_data);
 
 /**
  * Get the file descriptor used by libdecor. This is similar to
@@ -218,7 +246,7 @@ libdecor_dispatch(struct libdecor *context,
 struct libdecor_frame *
 libdecor_decorate(struct libdecor *context,
 		  struct wl_surface *surface,
-		  struct libdecor_frame_interface *iface,
+		  const struct libdecor_frame_interface *iface,
 		  void *user_data);
 
 /**
@@ -235,6 +263,18 @@ void
 libdecor_frame_unref(struct libdecor_frame *frame);
 
 /**
+ * Get the user data associated with this libdecor frame.
+ */
+void *
+libdecor_frame_get_user_data(struct libdecor_frame *frame);
+
+/**
+ * Set the user data associated with this libdecor frame.
+ */
+void
+libdecor_frame_set_user_data(struct libdecor_frame *frame, void *user_data);
+
+/**
  * Set the visibility of the frame.
  *
  * If an application wants to be borderless, it can set the frame visibility to
@@ -498,6 +538,12 @@ struct xdg_toplevel *
 libdecor_frame_get_xdg_toplevel(struct libdecor_frame *frame);
 
 /**
+ * Get the supported window manager capabilities for the window.
+ */
+enum libdecor_wm_capabilities
+libdecor_frame_get_wm_capabilities(struct libdecor_frame *frame);
+
+/**
  * Create a new content surface state.
  */
 struct libdecor_state *
diff --git libdecor/src/plugins/gtk/libdecor-gtk.c libdecor/src/plugins/gtk/libdecor-gtk.c
index ef638f1..2d0ebde 100644
--- libdecor/src/plugins/gtk/libdecor-gtk.c
+++ libdecor/src/plugins/gtk/libdecor-gtk.c
@@ -70,6 +70,13 @@ enum header_element {
 	HEADER_CLOSE,
 };
 
+enum titlebar_gesture_state {
+	TITLEBAR_GESTURE_STATE_INIT,
+	TITLEBAR_GESTURE_STATE_BUTTON_PRESSED,
+	TITLEBAR_GESTURE_STATE_CONSUMED,
+	TITLEBAR_GESTURE_STATE_DISCARDED,
+};
+
 struct header_element_data {
 	const char *name;
 	enum header_element type;
@@ -206,7 +213,6 @@ struct seat {
 
 	int pointer_x, pointer_y;
 
-	uint32_t pointer_button_time_stamp;
 	uint32_t touch_down_time_stamp;
 
 	uint32_t serial;
@@ -297,6 +303,16 @@ struct libdecor_frame_gtk {
 	cairo_surface_t *shadow_blur;
 
 	struct wl_list link;
+
+	struct {
+		enum titlebar_gesture_state state;
+		int button_pressed_count;
+		uint32_t first_pressed_button;
+		uint32_t first_pressed_time;
+		double pressed_x;
+		double pressed_y;
+		uint32_t pressed_serial;
+	} titlebar_gesture;
 };
 
 struct libdecor_plugin_gtk {
@@ -323,6 +339,7 @@ struct libdecor_plugin_gtk {
 	int cursor_size;
 
 	int double_click_time_ms;
+	int drag_threshold;
 };
 
 static const char *libdecor_gtk_proxy_tag = "libdecor-gtk";
@@ -912,7 +929,10 @@ ensure_title_bar_surfaces(struct libdecor_frame_gtk *frame_gtk)
 
 	g_object_get(gtk_widget_get_settings(frame_gtk->window),
 		     "gtk-double-click-time",
-		     &frame_gtk->plugin_gtk->double_click_time_ms, NULL);
+		     &frame_gtk->plugin_gtk->double_click_time_ms,
+		     "gtk-dnd-drag-threshold",
+		     &frame_gtk->plugin_gtk->drag_threshold,
+		     NULL);
 	/* set as "default" decoration */
 	g_object_set(frame_gtk->header,
 		     "title", libdecor_frame_get_title(&frame_gtk->frame),
@@ -2114,6 +2134,10 @@ pointer_leave(void *data,
 
 	seat->pointer_focus = NULL;
 	if (frame_gtk) {
+		frame_gtk->titlebar_gesture.state =
+			TITLEBAR_GESTURE_STATE_INIT;
+		frame_gtk->titlebar_gesture.first_pressed_button = 0;
+
 		frame_gtk->active = NULL;
 		frame_gtk->hdr_focus.widget = NULL;
 		frame_gtk->hdr_focus.type = HEADER_NONE;
@@ -2132,6 +2156,7 @@ pointer_motion(void *data,
 {
 	struct seat *seat = data;
 	struct libdecor_frame_gtk *frame_gtk;
+	struct header_element_data new_focus;
 
 	if (!seat->pointer_focus || !own_surface(seat->pointer_focus))
 		return;
@@ -2143,133 +2168,247 @@ pointer_motion(void *data,
 
 	frame_gtk = wl_surface_get_user_data(seat->pointer_focus);
 	/* avoid warnings after decoration has been turned off */
-	if (GTK_IS_WIDGET(frame_gtk->header) && frame_gtk->active->type == HEADER) {
-		struct header_element_data new_focus =  get_header_focus(
-					  GTK_HEADER_BAR(frame_gtk->header),
-					  seat->pointer_x, seat->pointer_y);
-		/* only update if widget change so that we keep the state */
-		if (frame_gtk->hdr_focus.widget != new_focus.widget) {
-			frame_gtk->hdr_focus = new_focus;
-		}
-		frame_gtk->hdr_focus.state |= GTK_STATE_FLAG_PRELIGHT;
-		/* redraw with updated button visuals */
-		draw_title_bar(frame_gtk);
-		libdecor_frame_toplevel_commit(&frame_gtk->frame);
-	} else {
+	if (!GTK_IS_WIDGET(frame_gtk->header) || frame_gtk->active->type != HEADER) {
 		frame_gtk->hdr_focus.type = HEADER_NONE;
 	}
+
+	new_focus =  get_header_focus(GTK_HEADER_BAR(frame_gtk->header),
+				      seat->pointer_x, seat->pointer_y);
+
+	/* only update if widget change so that we keep the state */
+	if (frame_gtk->hdr_focus.widget != new_focus.widget) {
+		frame_gtk->hdr_focus = new_focus;
+	}
+	frame_gtk->hdr_focus.state |= GTK_STATE_FLAG_PRELIGHT;
+	/* redraw with updated button visuals */
+	draw_title_bar(frame_gtk);
+	libdecor_frame_toplevel_commit(&frame_gtk->frame);
+
+	switch (frame_gtk->titlebar_gesture.state) {
+	case TITLEBAR_GESTURE_STATE_BUTTON_PRESSED:
+		if (frame_gtk->titlebar_gesture.first_pressed_button == BTN_LEFT) {
+			if (ABS ((double) seat->pointer_x -
+				 (double) frame_gtk->titlebar_gesture.pressed_x) >
+			    frame_gtk->plugin_gtk->drag_threshold ||
+			    ABS ((double) seat->pointer_y -
+				 (double) frame_gtk->titlebar_gesture.pressed_y) >
+			    frame_gtk->plugin_gtk->drag_threshold) {
+				libdecor_frame_move(&frame_gtk->frame,
+						    seat->wl_seat,
+						    frame_gtk->titlebar_gesture.pressed_serial);
+			}
+		}
+	case TITLEBAR_GESTURE_STATE_INIT:
+	case TITLEBAR_GESTURE_STATE_CONSUMED:
+	case TITLEBAR_GESTURE_STATE_DISCARDED:
+		break;
+	}
 }
 
 static void
-pointer_button(void *data,
-	       struct wl_pointer *wl_pointer,
-	       uint32_t serial,
-	       uint32_t time,
-	       uint32_t button,
-	       uint32_t state)
+handle_button_on_shadow(struct libdecor_frame_gtk *frame_gtk,
+			struct seat *seat,
+			uint32_t serial,
+			uint32_t time,
+			uint32_t button,
+			uint32_t state)
 {
-	struct seat *seat = data;
-	struct libdecor_frame_gtk *frame_gtk;
+	enum libdecor_resize_edge edge = LIBDECOR_RESIZE_EDGE_NONE;
 
-	if (!seat->pointer_focus || !own_surface(seat->pointer_focus))
-		return;
+	edge = component_edge(frame_gtk->active,
+			      seat->pointer_x,
+			      seat->pointer_y,
+			      SHADOW_MARGIN);
 
-	frame_gtk = wl_surface_get_user_data(seat->pointer_focus);
-	if (!frame_gtk)
-		return;
+	if (edge != LIBDECOR_RESIZE_EDGE_NONE && resizable(frame_gtk)) {
+		libdecor_frame_resize(&frame_gtk->frame,
+				      seat->wl_seat,
+				      serial,
+				      edge);
+	}
+}
+
+enum titlebar_gesture {
+	TITLEBAR_GESTURE_DOUBLE_CLICK,
+	TITLEBAR_GESTURE_MIDDLE_CLICK,
+	TITLEBAR_GESTURE_RIGHT_CLICK,
+};
 
-	if (button == BTN_LEFT) {
+static void
+handle_titlebar_gesture(struct libdecor_frame_gtk *frame_gtk,
+			struct seat *seat,
+			uint32_t serial,
+			enum titlebar_gesture gesture)
+{
+	switch (gesture) {
+	case TITLEBAR_GESTURE_DOUBLE_CLICK:
+		toggle_maximized(&frame_gtk->frame);
+		break;
+	case TITLEBAR_GESTURE_MIDDLE_CLICK:
+		break;
+	case TITLEBAR_GESTURE_RIGHT_CLICK:
+		const int title_height = gtk_widget_get_allocated_height(frame_gtk->header);
+
+		libdecor_frame_show_window_menu(&frame_gtk->frame,
+						seat->wl_seat,
+						serial,
+						seat->pointer_x,
+						seat->pointer_y
+						-title_height);
+		break;
+	}
+}
+
+static void
+handle_button_on_header(struct libdecor_frame_gtk *frame_gtk,
+			struct seat *seat,
+			uint32_t serial,
+			uint32_t time,
+			uint32_t button,
+			uint32_t state)
+{
+	switch (frame_gtk->titlebar_gesture.state) {
+	case TITLEBAR_GESTURE_STATE_INIT:
+		if (state != WL_POINTER_BUTTON_STATE_PRESSED)
+			return;
+
+		if (button == BTN_RIGHT) {
+			handle_titlebar_gesture(frame_gtk,
+						seat,
+						serial,
+						TITLEBAR_GESTURE_RIGHT_CLICK);
+			frame_gtk->titlebar_gesture.state =
+				TITLEBAR_GESTURE_STATE_CONSUMED;
+		} else {
+			if (button == BTN_LEFT &&
+			    frame_gtk->titlebar_gesture.first_pressed_button == BTN_LEFT &&
+			    time - frame_gtk->titlebar_gesture.first_pressed_time <
+			    (uint32_t) frame_gtk->plugin_gtk->double_click_time_ms) {
+				handle_titlebar_gesture(frame_gtk,
+							seat,
+							serial,
+							TITLEBAR_GESTURE_DOUBLE_CLICK);
+				frame_gtk->titlebar_gesture.state =
+					TITLEBAR_GESTURE_STATE_CONSUMED;
+			} else {
+				frame_gtk->titlebar_gesture.first_pressed_button = button;
+				frame_gtk->titlebar_gesture.first_pressed_time = time;
+				frame_gtk->titlebar_gesture.pressed_x = seat->pointer_x;
+				frame_gtk->titlebar_gesture.pressed_y = seat->pointer_y;
+				frame_gtk->titlebar_gesture.pressed_serial = serial;
+				frame_gtk->titlebar_gesture.state =
+					TITLEBAR_GESTURE_STATE_BUTTON_PRESSED;
+			}
+		}
+
+		frame_gtk->titlebar_gesture.button_pressed_count = 1;
+
+		switch (frame_gtk->hdr_focus.type) {
+		case HEADER_MIN:
+		case HEADER_MAX:
+		case HEADER_CLOSE:
+			frame_gtk->hdr_focus.state |= GTK_STATE_FLAG_ACTIVE;
+			draw_title_bar(frame_gtk);
+			libdecor_frame_toplevel_commit(&frame_gtk->frame);
+			break;
+		default:
+			break;
+		}
+
+		break;
+	case TITLEBAR_GESTURE_STATE_BUTTON_PRESSED:
 		if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
-			enum libdecor_resize_edge edge =
-					LIBDECOR_RESIZE_EDGE_NONE;
-			switch (frame_gtk->active->type) {
-			case SHADOW:
-				edge = component_edge(frame_gtk->active,
-						      seat->pointer_x,
-						      seat->pointer_y,
-						      SHADOW_MARGIN);
-				break;
-			case HEADER:
-				switch (frame_gtk->hdr_focus.type) {
-				case HEADER_MIN:
-				case HEADER_MAX:
-				case HEADER_CLOSE:
-					frame_gtk->hdr_focus.state |= GTK_STATE_FLAG_ACTIVE;
-					draw_title_bar(frame_gtk);
-					libdecor_frame_toplevel_commit(&frame_gtk->frame);
-					break;
-				default:
-					if (time-seat->pointer_button_time_stamp <
-					    (uint32_t)frame_gtk->plugin_gtk->double_click_time_ms) {
+			frame_gtk->titlebar_gesture.state =
+				TITLEBAR_GESTURE_STATE_DISCARDED;
+			frame_gtk->titlebar_gesture.button_pressed_count++;
+		} else {
+			frame_gtk->titlebar_gesture.button_pressed_count--;
+
+			if (frame_gtk->titlebar_gesture.button_pressed_count == 0) {
+				frame_gtk->titlebar_gesture.state =
+					TITLEBAR_GESTURE_STATE_INIT;
+				if (frame_gtk->titlebar_gesture.first_pressed_button == button &&
+				    button == BTN_LEFT) {
+					libdecor_frame_ref(&frame_gtk->frame);
+					switch (frame_gtk->hdr_focus.type) {
+					case HEADER_MIN:
+						if (minimizable(frame_gtk))
+							libdecor_frame_set_minimized(
+								&frame_gtk->frame);
+						break;
+					case HEADER_MAX:
 						toggle_maximized(&frame_gtk->frame);
+						break;
+					case HEADER_CLOSE:
+						if (closeable(frame_gtk)) {
+							libdecor_frame_close(
+								&frame_gtk->frame);
+							seat->pointer_focus = NULL;
+						}
+						break;
+					default:
+						break;
 					}
-					else if (moveable(frame_gtk)) {
-						seat->pointer_button_time_stamp = time;
-						libdecor_frame_move(&frame_gtk->frame,
-								    seat->wl_seat,
-								    serial);
-					}
-					break;
-				}
-				break;
-			default:
-				break;
-			}
 
-			if (edge != LIBDECOR_RESIZE_EDGE_NONE &&
-			    resizable(frame_gtk)) {
-				libdecor_frame_resize(
-					&frame_gtk->frame,
-					seat->wl_seat,
-					serial,
-					edge);
-			}
-		}
-		else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
-			switch (frame_gtk->active->type) {
-			case HEADER:
-				libdecor_frame_ref(&frame_gtk->frame);
-				switch (frame_gtk->hdr_focus.type) {
-				case HEADER_MIN:
-					if (minimizable(frame_gtk))
-						libdecor_frame_set_minimized(
-							&frame_gtk->frame);
-					break;
-				case HEADER_MAX:
-					toggle_maximized(&frame_gtk->frame);
-					break;
-				case HEADER_CLOSE:
-					if (closeable(frame_gtk)) {
-					       libdecor_frame_close(
-						       &frame_gtk->frame);
-					       seat->pointer_focus = NULL;
+					frame_gtk->hdr_focus.state &= ~GTK_STATE_FLAG_ACTIVE;
+					if (GTK_IS_WIDGET(frame_gtk->header)) {
+						draw_title_bar(frame_gtk);
+						libdecor_frame_toplevel_commit(&frame_gtk->frame);
 					}
-					break;
-				default:
-					break;
+					libdecor_frame_unref(&frame_gtk->frame);
 				}
-				/* unset active/clicked state once released */
+			} else {
 				frame_gtk->hdr_focus.state &= ~GTK_STATE_FLAG_ACTIVE;
 				if (GTK_IS_WIDGET(frame_gtk->header)) {
 					draw_title_bar(frame_gtk);
 					libdecor_frame_toplevel_commit(&frame_gtk->frame);
 				}
-				libdecor_frame_unref(&frame_gtk->frame);
-				break;
-			default:
-				break;
 			}
+
 		}
-	} else if (button == BTN_RIGHT &&
-		 state == WL_POINTER_BUTTON_STATE_PRESSED &&
-		 seat->pointer_focus == frame_gtk->headerbar.wl_surface) {
-		const int title_height = gtk_widget_get_allocated_height(frame_gtk->header);
-				libdecor_frame_show_window_menu(&frame_gtk->frame,
-								seat->wl_seat,
-								serial,
-								seat->pointer_x,
-								seat->pointer_y
-								-title_height);
+		break;
+	case TITLEBAR_GESTURE_STATE_CONSUMED:
+	case TITLEBAR_GESTURE_STATE_DISCARDED:
+		if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+			frame_gtk->titlebar_gesture.button_pressed_count++;
+		} else {
+			frame_gtk->titlebar_gesture.button_pressed_count--;
+			if (frame_gtk->titlebar_gesture.button_pressed_count == 0) {
+				frame_gtk->titlebar_gesture.state =
+					TITLEBAR_GESTURE_STATE_INIT;
+				frame_gtk->titlebar_gesture.first_pressed_button = 0;
+			}
+		}
+		break;
+	}
+}
+
+static void
+pointer_button(void *data,
+	       struct wl_pointer *wl_pointer,
+	       uint32_t serial,
+	       uint32_t time,
+	       uint32_t button,
+	       uint32_t state)
+{
+	struct seat *seat = data;
+	struct libdecor_frame_gtk *frame_gtk;
+
+	if (!seat->pointer_focus || !own_surface(seat->pointer_focus))
+		return;
+
+	frame_gtk = wl_surface_get_user_data(seat->pointer_focus);
+	if (!frame_gtk)
+		return;
+
+	switch (frame_gtk->active->type) {
+	case SHADOW:
+		handle_button_on_shadow (frame_gtk, seat, serial, time, button, state);
+		break;
+	case HEADER:
+		handle_button_on_header (frame_gtk, seat, serial, time, button, state);
+		break;
+	default:
 	}
 }
 
Direct Link to Message ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.