diff --git a/glfw/wl_client_side_decorations.c b/glfw/wl_client_side_decorations.c index 1f3e0ef34..934ebb15f 100644 --- a/glfw/wl_client_side_decorations.c +++ b/glfw/wl_client_side_decorations.c @@ -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); } diff --git a/glfw/wl_platform.h b/glfw/wl_platform.h index 1a6e9c44e..06444d13f 100644 --- a/glfw/wl_platform.h +++ b/glfw/wl_platform.h @@ -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; diff --git a/glfw/wl_window.c b/glfw/wl_window.c index a1ffeb22b..d5b1a6491 100644 --- a/glfw/wl_window.c +++ b/glfw/wl_window.c @@ -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)