Handle all known xdg top level states

This commit is contained in:
Kovid Goyal 2021-04-07 13:33:06 +05:30
parent f849f383cb
commit 5a1bd93518
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 62 additions and 46 deletions

View File

@ -393,16 +393,16 @@ change_csd_title(_GLFWwindow *window) {
void
set_csd_window_geometry(_GLFWwindow *window, int32_t *width, int32_t *height) {
bool has_csd = window->decorated && !window->wl.decorations.serverSide && window->wl.decorations.left.surface && !window->wl.fullscreened;
bool has_csd = window->decorated && !window->wl.decorations.serverSide && window->wl.decorations.left.surface && !(window->wl.toplevel_states & TOPLEVEL_STATE_FULLSCREEN);
bool size_specified_by_compositor = *width > 0 && *height > 0;
if (!size_specified_by_compositor) { *width = window->wl.width; *height = window->wl.height; }
int32_t scale = window->wl.scale >= 1 ? window->wl.scale : 1;
struct { int32_t x, y, width, height; } geometry = {.x = 0, .y = 0, .width = scale * *width, .height = scale * *height};
struct { int32_t x, y, width, height; } geometry = {.x = 0, .y = 0, .width = *width, .height = *height};
if (has_csd) {
// I dont know why GNOME wants geometry.x to be zero, but thats what works
geometry.y = -decs.metrics.width * scale;
int32_t visible_titlebar_height = decs.metrics.top - decs.metrics.width;
geometry.y = -decs.metrics.width;
*height -= visible_titlebar_height;
}
xdg_surface_set_window_geometry(window->wl.xdg.surface, geometry.x, geometry.y, geometry.width, geometry.height);
xdg_surface_set_window_geometry(window->wl.xdg.surface, geometry.x * scale, geometry.y * scale, geometry.width * scale, geometry.height * scale);
}

24
glfw/wl_platform.h vendored
View File

@ -111,6 +111,22 @@ typedef struct _GLFWWaylandCSDEdge {
int x, y;
} _GLFWWaylandCSDEdge;
typedef enum WaylandWindowState {
TOPLEVEL_STATE_NONE = 0,
TOPLEVEL_STATE_MAXIMIZED = 1,
TOPLEVEL_STATE_FULLSCREEN = 2,
TOPLEVEL_STATE_RESIZING = 4,
TOPLEVEL_STATE_ACTIVATED = 8,
TOPLEVEL_STATE_TILED_LEFT = 16,
TOPLEVEL_STATE_TILED_RIGHT = 32,
TOPLEVEL_STATE_TILED_TOP = 64,
TOPLEVEL_STATE_TILED_BOTTOM = 128,
} WaylandWindowState;
static const WaylandWindowState TOPLEVEL_STATE_DOCKED = TOPLEVEL_STATE_MAXIMIZED | TOPLEVEL_STATE_FULLSCREEN | TOPLEVEL_STATE_TILED_TOP | TOPLEVEL_STATE_TILED_LEFT | TOPLEVEL_STATE_TILED_RIGHT | TOPLEVEL_STATE_TILED_BOTTOM;
// Wayland-specific per-window data
//
@ -118,7 +134,6 @@ typedef struct _GLFWwindowWayland
{
int width, height;
bool visible;
bool maximized;
bool hovered;
bool transparent;
struct wl_surface* surface;
@ -152,8 +167,6 @@ typedef struct _GLFWwindowWayland
struct zwp_idle_inhibitor_v1* idleInhibitor;
bool fullscreened;
struct {
bool serverSide;
_GLFWdecorationSideWayland focus;
@ -187,7 +200,10 @@ typedef struct _GLFWwindowWayland
struct {
int32_t width, height;
} size_before_maximize;
} size_before_docking;
uint32_t toplevel_states;
bool maximize_on_first_show;
} _GLFWwindowWayland;

76
glfw/wl_window.c vendored
View File

@ -389,7 +389,7 @@ static void setFullscreen(_GLFWwindow* window, _GLFWmonitor* monitor, bool on)
bool
_glfwPlatformToggleFullscreen(_GLFWwindow *window, unsigned int flags UNUSED) {
bool already_fullscreen = window->wl.fullscreened;
bool already_fullscreen = window->wl.toplevel_states & TOPLEVEL_STATE_FULLSCREEN;
setFullscreen(window, NULL, !already_fullscreen);
return !already_fullscreen;
}
@ -403,44 +403,41 @@ static void xdgToplevelHandleConfigure(void* data,
_GLFWwindow* window = data;
float aspectRatio;
float targetRatio;
uint32_t* state;
bool maximized = false;
bool fullscreen = false;
bool activated = false;
enum xdg_toplevel_state* state;
uint32_t new_states = 0;
const bool report_event = true;
if (report_event) printf("top-level configure event: size: %dx%d states: ", width, height);
wl_array_for_each(state, states)
{
switch (*state)
{
case XDG_TOPLEVEL_STATE_MAXIMIZED:
maximized = true;
break;
case XDG_TOPLEVEL_STATE_FULLSCREEN:
fullscreen = true;
break;
case XDG_TOPLEVEL_STATE_RESIZING:
break;
case XDG_TOPLEVEL_STATE_ACTIVATED:
activated = true;
break;
wl_array_for_each(state, states) {
switch (*state) {
#define C(x) case XDG_##x: new_states |= x; if (report_event) printf("%s ", #x); break
C(TOPLEVEL_STATE_RESIZING);
C(TOPLEVEL_STATE_MAXIMIZED);
C(TOPLEVEL_STATE_FULLSCREEN);
C(TOPLEVEL_STATE_ACTIVATED);
C(TOPLEVEL_STATE_TILED_LEFT);
C(TOPLEVEL_STATE_TILED_RIGHT);
C(TOPLEVEL_STATE_TILED_TOP);
C(TOPLEVEL_STATE_TILED_BOTTOM);
#undef C
}
}
bool window_maximized = !window->wl.maximized && maximized;
bool window_unmaximized = window->wl.maximized && !maximized;
if (window_maximized) {
window->wl.size_before_maximize.width = window->wl.width;
window->wl.size_before_maximize.height = window->wl.height;
} else if (window_unmaximized && window->wl.size_before_maximize.width > 0 && window->wl.size_before_maximize.height > 0) {
width = window->wl.size_before_maximize.width;
height = window->wl.size_before_maximize.height;
window->wl.size_before_maximize.width = 0;
window->wl.size_before_maximize.height = 0;
if (report_event) printf("\n");
if ((window->wl.toplevel_states & TOPLEVEL_STATE_DOCKED) && !(new_states & TOPLEVEL_STATE_DOCKED)) {
width = window->wl.size_before_docking.width;
height = window->wl.size_before_docking.height;
window->wl.size_before_docking.width = 0;
window->wl.size_before_docking.height = 0;
if (report_event) printf("Restoring size on undock to: %dx%d\n", width, height);
} else if (!(window->wl.toplevel_states & TOPLEVEL_STATE_DOCKED) && (new_states & TOPLEVEL_STATE_DOCKED)) {
window->wl.size_before_docking.width = window->wl.width;
window->wl.size_before_docking.height = window->wl.height;
if (report_event) printf("Saving size on undock to: %dx%d\n", window->wl.width, window->wl.height);
}
window->wl.maximized = maximized;
if (width != 0 && height != 0)
{
if (!maximized && !fullscreen)
if (!(new_states & TOPLEVEL_STATE_DOCKED))
{
if (window->numer != GLFW_DONT_CARE && window->denom != GLFW_DONT_CARE)
{
@ -453,11 +450,12 @@ static void xdgToplevelHandleConfigure(void* data,
}
}
}
window->wl.fullscreened = fullscreen;
bool focus_changed = (window->wl.toplevel_states & TOPLEVEL_STATE_ACTIVATED) != (new_states & TOPLEVEL_STATE_ACTIVATED);
window->wl.toplevel_states = new_states;
set_csd_window_geometry(window, &width, &height);
wl_surface_commit(window->wl.surface);
dispatchChangesAfterConfigure(window, width, height);
_glfwInputWindowFocus(window, activated);
if (focus_changed) _glfwInputWindowFocus(window, window->wl.toplevel_states & TOPLEVEL_STATE_ACTIVATED);
ensure_csd_resources(window);
}
@ -548,9 +546,9 @@ static bool createXdgSurface(_GLFWwindow* window)
window->monitor->wl.output);
setIdleInhibitor(window, true);
}
else if (window->wl.maximized)
else if (window->wl.maximize_on_first_show)
{
window->wl.maximized = false;
window->wl.maximize_on_first_show = false;
xdg_toplevel_set_maximized(window->wl.xdg.toplevel);
setIdleInhibitor(window, false);
setXdgDecorations(window);
@ -745,6 +743,8 @@ int _glfwPlatformCreateWindow(_GLFWwindow* window,
if (wndconfig->title)
window->wl.title = _glfw_strdup(wndconfig->title);
if (wndconfig->maximized)
window->wl.maximize_on_first_show = true;
if (wndconfig->visible)
{
@ -957,7 +957,7 @@ void _glfwPlatformRestoreWindow(_GLFWwindow* window)
{
if (window->monitor)
xdg_toplevel_unset_fullscreen(window->wl.xdg.toplevel);
if (window->wl.maximized)
if (window->wl.toplevel_states & TOPLEVEL_STATE_MAXIMIZED)
xdg_toplevel_unset_maximized(window->wl.xdg.toplevel);
// There is no way to unset minimized, or even to know if we are
// minimized, so there is nothing to do in this case.
@ -1058,7 +1058,7 @@ int _glfwPlatformWindowVisible(_GLFWwindow* window)
int _glfwPlatformWindowMaximized(_GLFWwindow* window)
{
return window->wl.maximized;
return window->wl.toplevel_states & TOPLEVEL_STATE_MAXIMIZED;
}
int _glfwPlatformWindowHovered(_GLFWwindow* window)