Skip to content

Commit 75bdb7a

Browse files
committed
Merge pull request godotengine#114082 from deralmas/telekinesis
Wayland: Allow non-interactive window resizing
2 parents d1c9883 + 47a7e77 commit 75bdb7a

3 files changed

Lines changed: 137 additions & 11 deletions

File tree

platform/linuxbsd/wayland/display_server_wayland.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,11 +1204,12 @@ void DisplayServerWayland::window_set_size(const Size2i p_size, DisplayServer::W
12041204
ERR_FAIL_COND(!windows.has(p_window_id));
12051205
WindowData &wd = windows[p_window_id];
12061206

1207-
// The XDG spec doesn't allow non-interactive resizes. Let's update the
1208-
// window's internal representation to account for that.
1209-
if (wd.rect_changed_callback.is_valid()) {
1210-
wd.rect_changed_callback.call(wd.rect);
1207+
Size2i new_size = p_size;
1208+
if (wd.visible) {
1209+
new_size = wayland_thread.window_set_size(p_window_id, p_size);
12111210
}
1211+
1212+
_update_window_rect(Rect2i(wd.rect.position, new_size), p_window_id);
12121213
}
12131214

12141215
Size2i DisplayServerWayland::window_get_size(DisplayServer::WindowID p_window_id) const {

platform/linuxbsd/wayland/wayland_thread.cpp

Lines changed: 117 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,17 +1348,46 @@ void WaylandThread::_xdg_toplevel_on_configure(void *data, struct xdg_toplevel *
13481348
// Expect the window to be in a plain state. It will get properly set if the
13491349
// compositor reports otherwise below.
13501350
ws->mode = DisplayServer::WINDOW_MODE_WINDOWED;
1351+
ws->maximized = false;
1352+
ws->fullscreen = false;
1353+
ws->resizing = false;
1354+
ws->tiled_left = false;
1355+
ws->tiled_right = false;
1356+
ws->tiled_top = false;
1357+
ws->tiled_bottom = false;
13511358
ws->suspended = false;
13521359

13531360
uint32_t *state = nullptr;
13541361
wl_array_for_each(state, states) {
13551362
switch (*state) {
13561363
case XDG_TOPLEVEL_STATE_MAXIMIZED: {
13571364
ws->mode = DisplayServer::WINDOW_MODE_MAXIMIZED;
1365+
ws->maximized = true;
13581366
} break;
13591367

13601368
case XDG_TOPLEVEL_STATE_FULLSCREEN: {
13611369
ws->mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
1370+
ws->fullscreen = true;
1371+
} break;
1372+
1373+
case XDG_TOPLEVEL_STATE_RESIZING: {
1374+
ws->resizing = true;
1375+
} break;
1376+
1377+
case XDG_TOPLEVEL_STATE_TILED_LEFT: {
1378+
ws->tiled_left = true;
1379+
} break;
1380+
1381+
case XDG_TOPLEVEL_STATE_TILED_RIGHT: {
1382+
ws->tiled_right = true;
1383+
} break;
1384+
1385+
case XDG_TOPLEVEL_STATE_TILED_TOP: {
1386+
ws->tiled_top = true;
1387+
} break;
1388+
1389+
case XDG_TOPLEVEL_STATE_TILED_BOTTOM: {
1390+
ws->tiled_bottom = true;
13621391
} break;
13631392

13641393
case XDG_TOPLEVEL_STATE_SUSPENDED: {
@@ -1537,15 +1566,42 @@ void WaylandThread::libdecor_frame_on_configure(struct libdecor_frame *frame, st
15371566
// Expect the window to be in a plain state. It will get properly set if the
15381567
// compositor reports otherwise below.
15391568
ws->mode = DisplayServer::WINDOW_MODE_WINDOWED;
1569+
ws->maximized = false;
1570+
ws->fullscreen = false;
1571+
ws->resizing = false;
1572+
ws->tiled_left = false;
1573+
ws->tiled_right = false;
1574+
ws->tiled_top = false;
1575+
ws->tiled_bottom = false;
15401576
ws->suspended = false;
15411577

15421578
if (libdecor_configuration_get_window_state(configuration, &window_state)) {
15431579
if (window_state & LIBDECOR_WINDOW_STATE_MAXIMIZED) {
15441580
ws->mode = DisplayServer::WINDOW_MODE_MAXIMIZED;
1581+
ws->maximized = true;
15451582
}
15461583

15471584
if (window_state & LIBDECOR_WINDOW_STATE_FULLSCREEN) {
15481585
ws->mode = DisplayServer::WINDOW_MODE_FULLSCREEN;
1586+
ws->fullscreen = true;
1587+
}
1588+
1589+
// libdecor doesn't have the resizing state for whatever reason.
1590+
1591+
if (window_state & LIBDECOR_WINDOW_STATE_TILED_LEFT) {
1592+
ws->tiled_left = true;
1593+
}
1594+
1595+
if (window_state & LIBDECOR_WINDOW_STATE_TILED_RIGHT) {
1596+
ws->tiled_right = true;
1597+
}
1598+
1599+
if (window_state & LIBDECOR_WINDOW_STATE_TILED_TOP) {
1600+
ws->tiled_top = true;
1601+
}
1602+
1603+
if (window_state & LIBDECOR_WINDOW_STATE_TILED_BOTTOM) {
1604+
ws->tiled_bottom = true;
15491605
}
15501606

15511607
if (window_state & LIBDECOR_WINDOW_STATE_SUSPENDED) {
@@ -3997,6 +4053,58 @@ const WaylandThread::WindowState *WaylandThread::window_get_state(DisplayServer:
39974053
return windows.getptr(p_window_id);
39984054
}
39994055

4056+
Size2i WaylandThread::window_set_size(DisplayServer::WindowID p_window_id, const Size2i &p_size) {
4057+
ERR_FAIL_COND_V(!windows.has(p_window_id), p_size);
4058+
WindowState &ws = windows[p_window_id];
4059+
4060+
double window_scale = window_state_get_scale_factor(&ws);
4061+
4062+
if (ws.maximized) {
4063+
// Can't do anything.
4064+
return scale_vector2i(ws.rect.size, window_scale);
4065+
}
4066+
4067+
Size2i new_size = scale_vector2i(p_size, 1 / window_scale);
4068+
4069+
if (ws.tiled_left && ws.tiled_right) {
4070+
// Tiled left and right, we shouldn't change from our current width or else
4071+
// it'll look wonky.
4072+
new_size.width = ws.rect.size.width;
4073+
}
4074+
4075+
if (ws.tiled_top && ws.tiled_bottom) {
4076+
// Tiled top and bottom. Same as above, but for the height.
4077+
new_size.height = ws.rect.size.height;
4078+
}
4079+
4080+
if (ws.resizing && ws.rect.size.width > 0 && ws.rect.size.height > 0) {
4081+
// The spec says that we shall not resize further than the config size. We can
4082+
// resize less than that though.
4083+
new_size = new_size.min(ws.rect.size);
4084+
}
4085+
4086+
// NOTE: Older versions of libdecor (~2022) do not have a way to get the max
4087+
// content size. Let's also check for its pointer so that we can preserve
4088+
// compatibility with older distros.
4089+
if (ws.libdecor_frame && libdecor_frame_get_max_content_size) {
4090+
int max_width = new_size.width;
4091+
int max_height = new_size.height;
4092+
4093+
// NOTE: Max content size is dynamic on libdecor, as plugins can override it
4094+
// to accommodate their decorations.
4095+
libdecor_frame_get_max_content_size(ws.libdecor_frame, &max_width, &max_height);
4096+
4097+
if (max_width > 0 && max_height > 0) {
4098+
new_size.width = MIN(new_size.width, max_width);
4099+
new_size.height = MIN(new_size.height, max_height);
4100+
}
4101+
}
4102+
4103+
window_state_update_size(&ws, new_size.width, new_size.height);
4104+
4105+
return scale_vector2i(new_size, window_scale);
4106+
}
4107+
40004108
void WaylandThread::beep() const {
40014109
if (registry.xdg_system_bell) {
40024110
xdg_system_bell_v1_ring(registry.xdg_system_bell, nullptr);
@@ -4177,8 +4285,12 @@ bool WaylandThread::window_can_set_mode(DisplayServer::WindowID p_window_id, Dis
41774285
};
41784286

41794287
case DisplayServer::WINDOW_MODE_MAXIMIZED: {
4180-
// NOTE: libdecor doesn't seem to have a maximize capability query?
4181-
// The fact that there's a fullscreen one makes me suspicious.
4288+
if (ws.libdecor_frame) {
4289+
// NOTE: libdecor doesn't seem to have a maximize capability query?
4290+
// The fact that there's a fullscreen one makes me suspicious. Anyways,
4291+
// let's act as if we always can.
4292+
return true;
4293+
}
41824294
return ws.can_maximize;
41834295
};
41844296

@@ -5436,7 +5548,9 @@ void WaylandThread::destroy() {
54365548
zwp_tablet_tool_v2_destroy(tool);
54375549
}
54385550

5439-
zwp_text_input_v3_destroy(ss->wp_text_input);
5551+
if (ss->wp_text_input) {
5552+
zwp_text_input_v3_destroy(ss->wp_text_input);
5553+
}
54405554

54415555
memdelete(ss);
54425556
}

platform/linuxbsd/wayland/wayland_thread.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -247,15 +247,25 @@ class WaylandThread {
247247

248248
Rect2i rect;
249249
DisplayServer::WindowMode mode = DisplayServer::WINDOW_MODE_WINDOWED;
250-
bool suspended = false;
250+
251+
// Toplevel states.
252+
bool maximized = false; // MUST obey configure size.
253+
bool fullscreen = false; // Can be smaller than configure size.
254+
bool resizing = false; // Configure size is a max.
255+
// No need for `activated` (yet)
256+
bool tiled_left = false;
257+
bool tiled_right = false;
258+
bool tiled_top = false;
259+
bool tiled_bottom = false;
260+
bool suspended = false; // We can stop drawing.
251261

252262
// These are true by default as it isn't guaranteed that we'll find an
253263
// xdg-shell implementation with wm_capabilities available. If and once we
254264
// receive a wm_capabilities event these will get reset and updated with
255265
// whatever the compositor says.
256-
bool can_minimize = false;
257-
bool can_maximize = false;
258-
bool can_fullscreen = false;
266+
bool can_minimize = true;
267+
bool can_maximize = true;
268+
bool can_fullscreen = true;
259269

260270
HashSet<struct wl_output *> wl_outputs;
261271

@@ -1101,6 +1111,7 @@ class WaylandThread {
11011111
struct wl_surface *window_get_wl_surface(DisplayServer::WindowID p_window_id) const;
11021112
WindowState *window_get_state(DisplayServer::WindowID p_window_id);
11031113
const WindowState *window_get_state(DisplayServer::WindowID p_window_id) const;
1114+
Size2i window_set_size(DisplayServer::WindowID p_window_id, const Size2i &p_size);
11041115

11051116
void window_start_resize(DisplayServer::WindowResizeEdge p_edge, DisplayServer::WindowID p_window);
11061117

0 commit comments

Comments
 (0)