xdg-shell: Send XDG_TOPLEVEL_STATE_RESIZING during interactive resize
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 3.1k
- Forks
- 237
- Avg merge
- 1h 43m
- Merged PRs (30d)
- 1
Description
Description
xdg-shell: Send XDG_TOPLEVEL_STATE_RESIZING state during interactive resize
Use Case
Problem
Currently, Wayfire does not send the XDG_TOPLEVEL_STATE_RESIZING state to clients when the user initiates an interactive resize (e.g., dragging a window border).
According to the xdg-shell protocol, compositors SHOULD send the RESIZING state to inform the client that an interactive resize is happening, allowing the toolkit to pause heavy rendering or suppress focus changes.
Furthermore, because Wayfire changes the keyboard focus (sending wl_keyboard_leave) immediately upon starting the resize grab, toolkits like GTK3 receive a focus-out-event before or without knowing that a resize is in progress.
This causes significant issues for applications that rely on window focus. For example, utilities designed to close when they lose focus (notify::is-active or focus-out-event) will incorrectly close while the user is simply trying to resize the window.
Solution
This FR adds the missing xdg-shell state notifications by hooking into the on_request_resize callback in xdg-toplevel-view.cpp:
- When a resize is requested, it calls
wlr_xdg_toplevel_set_resizing(this->xdg_toplevel, true).
- It dynamically connects a listener to the
pointer_buttonsignal to detect when the user releases the mouse buttonWL_POINTER_BUTTON_STATE_RELEASED. Once released, it sets the resizing state to false and disconnects the listeners. - To prevent memory leaks if the view is destroyed during a resize grab, it also connects to the
view-disappearedsignal to safely reset the state and disconnect.
Benefits
This allows clients (like GTK3) to know exactly when an interactive resize starts and ends, restoring compatibility with standard Wayland behavior seen in compositors like Mutter and KWin.
Testing
Tested with a custom GTK3 application that closes on notify::is-active loss.
Before patch: The application closes immediately upon clicking the window border to resize.
After patch: The application remains open during the resize, as the toolkit can now properly intercept the focus loss using the RESIZING state.
Additional context
Code Changes
--- a/src/view/xdg-shell/xdg-toplevel-view.hpp 2026-06-30 16:45:46.503000000 +0200
+++ b/src/view/xdg-shell/xdg-toplevel-view.hpp 2026-08-04 21:34:11.085741111 +0200
@@ -11,6 +11,7 @@
#include <wayfire/toplevel-view.hpp>
#include "wayfire/toplevel.hpp"
#include "wayfire/util.hpp"
+#include <wayfire/signal-definitions.hpp>
#include "xdg-toplevel.hpp"
namespace wf
@@ -48,6 +49,10 @@
std::shared_ptr<wf::xdg_toplevel_t> wtoplevel;
wf::signal::connection_t<xdg_toplevel_applied_state_signal> on_toplevel_applied;
+ /* ------------------------------- */
+ wf::signal::connection_t<wf::input_event_signal<wlr_pointer_button_event>> on_pointer_button;
+ wf::signal::connection_t<wf::view_disappeared_signal> on_view_disappeared_during_resize;
+ /* ------------------------------- */
void map() override;
void destroy() override;
--- a/src/view/xdg-shell/xdg-toplevel-view.cpp 2026-06-30 16:45:46.502657991 +0200
+++ b/src/view/xdg-shell/xdg-toplevel-view.cpp 2026-08-05 09:00:58.699021823 +0200
@@ -218,6 +218,42 @@
if (ev->serial == wf::get_core().seat->priv->last_press_release_serial)
{
wf::get_core().default_wm->resize_request({this}, ev->edges);
+
+ // 1. Turn ON resize flag
+ // LOGI("Resize ON");
+ wlr_xdg_toplevel_set_resizing(this->xdg_toplevel, true);
+
+ // 2. Listen for button release
+ on_pointer_button.set_callback([&] (wf::input_event_signal<wlr_pointer_button_event> *ev)
+ {
+ if (ev->event->state == WL_POINTER_BUTTON_STATE_RELEASED)
+ {
+ // LOGI("Button released. Resize OFF");
+ // Button released — turn OFF resize flag
+ wlr_xdg_toplevel_set_resizing(this->xdg_toplevel, false);
+
+ // Disconnect signals
+ on_pointer_button.disconnect();
+ on_view_disappeared_during_resize.disconnect();
+ }
+ });
+ wf::get_core().connect(&on_pointer_button);
+
+ // 3. Prevent memory leak on view destruction during resize
+ on_view_disappeared_during_resize.set_callback([&] (wf::view_disappeared_signal *ev)
+ {
+ if (ev->view == self())
+ {
+ // LOGI("View disappeared. Resize OFF");
+ wlr_xdg_toplevel_set_resizing(this->xdg_toplevel, false);
+ on_pointer_button.disconnect();
+ on_view_disappeared_during_resize.disconnect();
+ }
+ });
+ wf::get_core().connect(&on_view_disappeared_during_resize);
+ //wf::get_core().connect_signal("view-disappeared", &on_view_disappeared_during_resize);
}
});
on_request_minimize.set_callback([&] (void*)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with src/view/xdg-shell/xdg-toplevel-view.cpp and its header, then inspect on_request_resize and existing signal connection patterns. Exercise interactive resizing with the GTK3 focus-loss test described in the issue; done when clients receive the resizing state during the grab and it is cleared on release or view disappearance.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- desktop-dev
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 65/100