Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions waybox/seat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,19 @@ static void handle_new_pointer(struct wb_server *server, struct wlr_input_device
wlr_cursor_attach_input_device(server->cursor->cursor, device);
}

/* Advertise the seat's input capabilities to clients. waybox always owns a
* cursor, so POINTER is always advertised; KEYBOARD is advertised once at least
* one keyboard exists. This must run whenever an input device is added through
* ANY path — including the virtual-pointer/virtual-keyboard protocols, which
* bypass new_input_notify — otherwise clients never receive input from a
* virtual device (e.g. under the headless backend used by the tests). */
static void update_seat_capabilities(struct wb_server *server) {
uint32_t caps = WL_SEAT_CAPABILITY_POINTER;
if (!wl_list_empty(&server->seat->keyboards))
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
wlr_seat_set_capabilities(server->seat->seat, caps);
}

static void new_input_notify(struct wb_server *server, void *data) {
struct wlr_input_device *device = static_cast<struct wlr_input_device *>(data);
switch (device->type) {
Expand All @@ -681,11 +694,7 @@ static void new_input_notify(struct wb_server *server, void *data) {
break;
}

uint32_t caps = WL_SEAT_CAPABILITY_POINTER;
if (!wl_list_empty(&server->seat->keyboards)) {
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
}
wlr_seat_set_capabilities(server->seat->seat, caps);
update_seat_capabilities(server);
}

void seat_focus_surface(struct wb_seat *seat, struct wlr_surface *surface) {
Expand Down Expand Up @@ -731,6 +740,7 @@ struct wb_seat *wb_seat_create(struct wb_server *server) {
auto *virtual_keyboard =
static_cast<struct wlr_virtual_keyboard_v1 *>(data);
handle_new_keyboard(server, &virtual_keyboard->keyboard.base);
update_seat_capabilities(server);
});
server->virtual_pointer_manager =
wlr_virtual_pointer_manager_v1_create(server->wl_display);
Expand All @@ -740,6 +750,7 @@ struct wb_seat *wb_seat_create(struct wb_server *server) {
auto *event =
static_cast<struct wlr_virtual_pointer_v1_new_pointer_event *>(data);
handle_new_pointer(server, &event->new_pointer->pointer.base);
update_seat_capabilities(server);
});

seat->seat = wlr_seat_create(server->wl_display, "seat0");
Expand Down
30 changes: 22 additions & 8 deletions waybox/xdg_shell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -751,6 +751,12 @@ void set_toplevel_maximized(struct wb_toplevel *toplevel, bool horz, bool vert)
void set_toplevel_fullscreen(struct wb_toplevel *toplevel, bool fullscreen) {
if (!toplevel->xdg_toplevel->base->initialized)
return;
/* No-op if the state is already what was asked for. Clients (notably GTK)
* send redundant unset_fullscreen requests while managing their state;
* acting on them would corrupt geometry (restoring an unset restore rect)
* or needlessly re-fullscreen. */
if (fullscreen == toplevel->xdg_toplevel->current.fullscreen)
return;

if (fullscreen) {
toplevel->restore_fullscreen = toplevel->geometry;
Expand Down Expand Up @@ -788,22 +794,30 @@ void set_toplevel_fullscreen(struct wb_toplevel *toplevel, bool fullscreen) {

static void xdg_toplevel_request_fullscreen(
struct wb_toplevel *toplevel, void *data) {
/* Toggle fullscreen on the client's request (e.g. a video player). A
* request before the first commit would assert in wlroots, so it is
* ignored until the surface is initialized; the client can re-request. */
/* Apply the state the client actually asked for. wlroots raises this event
* for both set_fullscreen and unset_fullscreen, with the desired value in
* requested.fullscreen — toggling instead would turn a client's redundant
* "unset fullscreen" (which GTK sends while managing its window state) into
* an unexpected fullscreen, blowing the window up to full screen. A request
* before the first commit would assert in wlroots, so ignore it until the
* surface is initialized; the client can re-request. */
if (!toplevel->xdg_toplevel->base->initialized)
return;
set_toplevel_fullscreen(toplevel,
!toplevel->xdg_toplevel->current.fullscreen);
toplevel->xdg_toplevel->requested.fullscreen);
}

static void xdg_toplevel_request_maximize(struct wb_toplevel *toplevel, void *data) {
/* The client asked to (un)maximize, e.g. via its CSD maximize button.
* Toggle full maximize. Ignored until initialized (see above). */
/* Apply the maximize state the client asked for (requested.maximized), for
* the same reason as fullscreen above: a redundant unset_maximized must not
* be toggled into a maximize. Ignored until initialized. */
if (!toplevel->xdg_toplevel->base->initialized)
return;
const bool full = toplevel->max_horz && toplevel->max_vert;
set_toplevel_maximized(toplevel, !full, !full);
bool maximize = toplevel->xdg_toplevel->requested.maximized;
bool currently_full = toplevel->max_horz && toplevel->max_vert;
if (maximize == currently_full)
return; /* redundant request (e.g. GTK's unset while not maximized) */
set_toplevel_maximized(toplevel, maximize, maximize);
}

static void xdg_toplevel_request_minimize(struct wb_toplevel *toplevel, void *data) {
Expand Down