summaryrefslogtreecommitdiff
path: root/libdecor/src
diff options
context:
space:
mode:
Diffstat (limited to 'libdecor/src')
-rw-r--r--libdecor/src/libdecor.c85
-rw-r--r--libdecor/src/libdecor.h50
-rw-r--r--libdecor/src/plugins/gtk/libdecor-gtk.c353
3 files changed, 374 insertions, 114 deletions
diff --git a/libdecor/src/libdecor.c b/libdecor/src/libdecor.c
index 6fc184c10..3ede71280 100644
--- a/libdecor/src/libdecor.c
+++ b/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 a/libdecor/src/libdecor.h b/libdecor/src/libdecor.h
index af67e2fd5..e52ced0cd 100644
--- a/libdecor/src/libdecor.h
+++ b/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 a/libdecor/src/plugins/gtk/libdecor-gtk.c b/libdecor/src/plugins/gtk/libdecor-gtk.c
index ef638f1a9..2d0ebde45 100644
--- a/libdecor/src/plugins/gtk/libdecor-gtk.c
+++ b/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:
}
}