From 1b575ce81619fd1e6c4b9e103c7dd725714403a8 Mon Sep 17 00:00:00 2001 From: 01micko <01micko@gmx.com> Date: Thu, 21 Aug 2025 20:03:33 +1000 Subject: [PATCH 1/6] docs/labnag.1.scd: fix typo --- docs/labnag.1.scd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/labnag.1.scd b/docs/labnag.1.scd index 60970141..5dc91ed8 100644 --- a/docs/labnag.1.scd +++ b/docs/labnag.1.scd @@ -14,13 +14,13 @@ _labnag_ [options...] Create a button with the text _text_ that optionally executes _action_ when pressed. Multiple buttons can be defined by providing the flag multiple times. Buttons will appear in the order they are provided from - lef to right. + left to right. *-Z, --button-dismiss* [] Create a button with the text _text_ that optionally executes _action_ when pressed, and dismisses labnag. Multiple buttons can be defined by providing the flag multiple times. Buttons will appear in the order - they are provided from lef to right. + they are provided from left to right. *-d, --debug* Enable debugging. From 48ba23fc8d0193a73c0e82a2426c8bff730940d1 Mon Sep 17 00:00:00 2001 From: tokyo4j Date: Thu, 21 Aug 2025 17:57:29 +0900 Subject: [PATCH 2/6] Add common/edge.c --- include/common/direction.h | 2 +- include/common/edge.h | 38 +++++++++++++++++++++++ include/config/types.h | 22 -------------- include/view.h | 11 +------ src/action.c | 4 +-- src/common/edge.c | 59 ++++++++++++++++++++++++++++++++++++ src/common/meson.build | 1 + src/config/rcxml.c | 2 +- src/view.c | 62 ++------------------------------------ 9 files changed, 105 insertions(+), 96 deletions(-) create mode 100644 include/common/edge.h create mode 100644 src/common/edge.c diff --git a/include/common/direction.h b/include/common/direction.h index be05d29c..a1e6530e 100644 --- a/include/common/direction.h +++ b/include/common/direction.h @@ -3,7 +3,7 @@ #define LABWC_DIRECTION_H #include -#include "config/types.h" +#include "common/edge.h" bool direction_from_edge(enum lab_edge edge, enum wlr_direction *direction); enum wlr_direction direction_get_opposite(enum wlr_direction direction); diff --git a/include/common/edge.h b/include/common/edge.h new file mode 100644 index 00000000..23b5fdde --- /dev/null +++ b/include/common/edge.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +#ifndef LABWC_EDGE_H +#define LABWC_EDGE_H + +#include + +/** + * Represents an edge or direction (e.g. window tiling, window motion) + */ +enum lab_edge { + LAB_EDGE_INVALID = 0, + + LAB_EDGE_LEFT = (1 << 0), + LAB_EDGE_RIGHT = (1 << 1), + LAB_EDGE_UP = (1 << 2), + LAB_EDGE_DOWN = (1 << 3), + LAB_EDGE_CENTER = (1 << 4), /* for window tiling */ + LAB_EDGE_ANY = (1 << 5), /* for window rules */ + + /* for window tiling */ + LAB_EDGE_UPLEFT = (LAB_EDGE_UP | LAB_EDGE_LEFT), + LAB_EDGE_UPRIGHT = (LAB_EDGE_UP | LAB_EDGE_RIGHT), + LAB_EDGE_DOWNLEFT = (LAB_EDGE_DOWN | LAB_EDGE_LEFT), + LAB_EDGE_DOWNRIGHT = (LAB_EDGE_DOWN | LAB_EDGE_RIGHT), +}; + +enum lab_edge lab_edge_parse(const char *direction, bool tiled, bool any); + +/** + * lab_edge_invert() - select the opposite of a provided edge + * + * Returns LAB_EDGE_INVALID for edges other than UP/DOWN/LEFT/RIGHT. + * + * @edge: edge to be inverted + */ +enum lab_edge lab_edge_invert(enum lab_edge edge); + +#endif /* LABWC_EDGE_H */ diff --git a/include/config/types.h b/include/config/types.h index 246c7527..18d08700 100644 --- a/include/config/types.h +++ b/include/config/types.h @@ -11,28 +11,6 @@ * For the full config struct, see config/rcxml.h. */ -/** - * Edges to which a view can be snapped. "Any" is used as - * a catch-all for every valid edge in order to simplify certain - * types of conditionals, but it is only valid for a selection - * of options in rc.xml. - */ -enum lab_edge { - LAB_EDGE_INVALID = 0, - - LAB_EDGE_LEFT = (1 << 0), - LAB_EDGE_RIGHT = (1 << 1), - LAB_EDGE_UP = (1 << 2), - LAB_EDGE_DOWN = (1 << 3), - LAB_EDGE_CENTER = (1 << 4), - LAB_EDGE_ANY = (1 << 5), - - LAB_EDGE_UPLEFT = (LAB_EDGE_UP | LAB_EDGE_LEFT), - LAB_EDGE_UPRIGHT = (LAB_EDGE_UP | LAB_EDGE_RIGHT), - LAB_EDGE_DOWNLEFT = (LAB_EDGE_DOWN | LAB_EDGE_LEFT), - LAB_EDGE_DOWNRIGHT = (LAB_EDGE_DOWN | LAB_EDGE_RIGHT), -}; - /** * Indicates whether tablet tool motion events should be reported using * absolute or relative coordinates diff --git a/include/view.h b/include/view.h index 2aa7df67..4efb2283 100644 --- a/include/view.h +++ b/include/view.h @@ -7,6 +7,7 @@ #include #include #include +#include "common/edge.h" #include "config.h" #include "config/types.h" @@ -422,15 +423,6 @@ void view_array_append(struct server *server, struct wl_array *views, enum view_wants_focus view_wants_focus(struct view *view); bool view_contains_window_type(struct view *view, enum lab_window_type window_type); -/** - * view_edge_invert() - select the opposite of a provided edge - * - * LAB_EDGE_CENTER and LAB_EDGE_INVALID both map to LAB_EDGE_INVALID. - * - * @edge: edge to be inverted - */ -enum lab_edge view_edge_invert(enum lab_edge edge); - /* If view is NULL, the size of SSD is not considered */ struct wlr_box view_get_edge_snap_box(struct view *view, struct output *output, enum lab_edge edge); @@ -601,7 +593,6 @@ void view_init(struct view *view); void view_destroy(struct view *view); enum view_axis view_axis_parse(const char *direction); -enum lab_edge view_edge_parse(const char *direction, bool tiled, bool any); enum lab_placement_policy view_placement_parse(const char *policy); /* xdg.c */ diff --git a/src/action.c b/src/action.c index 2722998f..a65d7371 100644 --- a/src/action.c +++ b/src/action.c @@ -347,7 +347,7 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char if (!strcmp(argument, "direction")) { bool tiled = (action->type == ACTION_TYPE_TOGGLE_SNAP_TO_EDGE || action->type == ACTION_TYPE_SNAP_TO_EDGE); - enum lab_edge edge = view_edge_parse(content, tiled, /*any*/ false); + enum lab_edge edge = lab_edge_parse(content, tiled, /*any*/ false); if (edge == LAB_EDGE_INVALID) { wlr_log(WLR_ERROR, "Invalid argument for action %s: '%s' (%s)", action_names[action->type], argument, content); @@ -455,7 +455,7 @@ action_arg_from_xml_node(struct action *action, const char *nodename, const char goto cleanup; } if (!strcmp(argument, "direction")) { - enum lab_edge edge = view_edge_parse(content, + enum lab_edge edge = lab_edge_parse(content, /*tiled*/ false, /*any*/ false); if (edge == LAB_EDGE_INVALID) { wlr_log(WLR_ERROR, "Invalid argument for action %s: '%s' (%s)", diff --git a/src/common/edge.c b/src/common/edge.c new file mode 100644 index 00000000..20b8eb9c --- /dev/null +++ b/src/common/edge.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-only +#include "common/edge.h" +#include + +enum lab_edge +lab_edge_parse(const char *direction, bool tiled, bool any) +{ + if (!direction) { + return LAB_EDGE_INVALID; + } + if (!strcasecmp(direction, "left")) { + return LAB_EDGE_LEFT; + } else if (!strcasecmp(direction, "up")) { + return LAB_EDGE_UP; + } else if (!strcasecmp(direction, "right")) { + return LAB_EDGE_RIGHT; + } else if (!strcasecmp(direction, "down")) { + return LAB_EDGE_DOWN; + } + + if (any) { + if (!strcasecmp(direction, "any")) { + return LAB_EDGE_ANY; + } + } + + if (tiled) { + if (!strcasecmp(direction, "center")) { + return LAB_EDGE_CENTER; + } else if (!strcasecmp(direction, "up-left")) { + return LAB_EDGE_UPLEFT; + } else if (!strcasecmp(direction, "up-right")) { + return LAB_EDGE_UPRIGHT; + } else if (!strcasecmp(direction, "down-left")) { + return LAB_EDGE_DOWNLEFT; + } else if (!strcasecmp(direction, "down-right")) { + return LAB_EDGE_DOWNRIGHT; + } + } + + return LAB_EDGE_INVALID; +} + +enum lab_edge +lab_edge_invert(enum lab_edge edge) +{ + switch (edge) { + case LAB_EDGE_LEFT: + return LAB_EDGE_RIGHT; + case LAB_EDGE_RIGHT: + return LAB_EDGE_LEFT; + case LAB_EDGE_UP: + return LAB_EDGE_DOWN; + case LAB_EDGE_DOWN: + return LAB_EDGE_UP; + default: + return LAB_EDGE_INVALID; + } +} diff --git a/src/common/meson.build b/src/common/meson.build index aa0fc413..e0b90336 100644 --- a/src/common/meson.build +++ b/src/common/meson.build @@ -3,6 +3,7 @@ labwc_sources += files( 'box.c', 'buf.c', 'dir.c', + 'edge.c', 'fd-util.c', 'file-helpers.c', 'font.c', diff --git a/src/config/rcxml.c b/src/config/rcxml.c index 17703e68..8746836b 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -444,7 +444,7 @@ fill_action_query(struct action *action, xmlNode *node, struct view_query *query } else if (!strcasecmp(key, "omnipresent")) { query->omnipresent = parse_tristate(content); } else if (!strcasecmp(key, "tiled")) { - query->tiled = view_edge_parse(content, + query->tiled = lab_edge_parse(content, /*tiled*/ true, /*any*/ true); } else if (!strcasecmp(key, "tiled_region")) { xstrdup_replace(query->tiled_region, content); diff --git a/src/view.c b/src/view.c index 4088512a..ff863d32 100644 --- a/src/view.c +++ b/src/view.c @@ -429,25 +429,6 @@ view_offer_focus(struct view *view) * They may be called repeatably during output layout changes. */ -enum lab_edge -view_edge_invert(enum lab_edge edge) -{ - switch (edge) { - case LAB_EDGE_LEFT: - return LAB_EDGE_RIGHT; - case LAB_EDGE_RIGHT: - return LAB_EDGE_LEFT; - case LAB_EDGE_UP: - return LAB_EDGE_DOWN; - case LAB_EDGE_DOWN: - return LAB_EDGE_UP; - case LAB_EDGE_CENTER: - case LAB_EDGE_INVALID: - default: - return LAB_EDGE_INVALID; - } -} - struct wlr_box view_get_edge_snap_box(struct view *view, struct output *output, enum lab_edge edge) @@ -2020,7 +2001,7 @@ view_move_to_edge(struct view *view, enum lab_edge direction, bool snap_to_windo int destination_y = view->pending.y; /* Compute the new position in the direction of motion */ - direction = view_edge_invert(direction); + direction = lab_edge_invert(direction); switch (direction) { case LAB_EDGE_LEFT: destination_x = left; @@ -2120,45 +2101,6 @@ view_axis_parse(const char *direction) } } -enum lab_edge -view_edge_parse(const char *direction, bool tiled, bool any) -{ - if (!direction) { - return LAB_EDGE_INVALID; - } - if (!strcasecmp(direction, "left")) { - return LAB_EDGE_LEFT; - } else if (!strcasecmp(direction, "up")) { - return LAB_EDGE_UP; - } else if (!strcasecmp(direction, "right")) { - return LAB_EDGE_RIGHT; - } else if (!strcasecmp(direction, "down")) { - return LAB_EDGE_DOWN; - } - - if (any) { - if (!strcasecmp(direction, "any")) { - return LAB_EDGE_ANY; - } - } - - if (tiled) { - if (!strcasecmp(direction, "center")) { - return LAB_EDGE_CENTER; - } else if (!strcasecmp(direction, "up-left")) { - return LAB_EDGE_UPLEFT; - } else if (!strcasecmp(direction, "up-right")) { - return LAB_EDGE_UPRIGHT; - } else if (!strcasecmp(direction, "down-left")) { - return LAB_EDGE_DOWNLEFT; - } else if (!strcasecmp(direction, "down-right")) { - return LAB_EDGE_DOWNRIGHT; - } - } - - return LAB_EDGE_INVALID; -} - enum lab_placement_policy view_placement_parse(const char *policy) { @@ -2215,7 +2157,7 @@ view_snap_to_edge(struct view *view, enum lab_edge edge, } /* When switching outputs, jump to the opposite edge */ - edge = view_edge_invert(edge); + edge = lab_edge_invert(edge); } if (view->maximized != VIEW_AXIS_NONE) { From 943f5751ee008faf1ee5e745f10086c95ea5183d Mon Sep 17 00:00:00 2001 From: tokyo4j Date: Thu, 21 Aug 2025 13:45:58 +0900 Subject: [PATCH 3/6] view: unify ssd_enabled and ssd_titlebar_hidden to ssd_mode --- include/config/types.h | 4 ++-- include/view.h | 5 ++--- src/ssd/ssd.c | 12 +++++------ src/view.c | 47 +++++++++++++++++------------------------- 4 files changed, 29 insertions(+), 39 deletions(-) diff --git a/include/config/types.h b/include/config/types.h index 18d08700..7f90b151 100644 --- a/include/config/types.h +++ b/include/config/types.h @@ -36,10 +36,10 @@ enum lab_rotation { }; enum lab_ssd_mode { - LAB_SSD_MODE_INVALID, - LAB_SSD_MODE_NONE, + LAB_SSD_MODE_NONE = 0, LAB_SSD_MODE_BORDER, LAB_SSD_MODE_FULL, + LAB_SSD_MODE_INVALID, }; enum lab_tristate { diff --git a/include/view.h b/include/view.h index 4efb2283..e7dce886 100644 --- a/include/view.h +++ b/include/view.h @@ -170,8 +170,7 @@ struct view { bool mapped; bool been_mapped; - bool ssd_enabled; - bool ssd_titlebar_hidden; + enum lab_ssd_mode ssd_mode; enum ssd_preference ssd_preference; bool shaded; bool minimized; @@ -534,7 +533,7 @@ bool view_is_tiled(struct view *view); bool view_is_tiled_and_notify_tiled(struct view *view); bool view_is_floating(struct view *view); void view_move_to_workspace(struct view *view, struct workspace *workspace); -enum lab_ssd_mode view_get_ssd_mode(struct view *view); +bool view_titlebar_visible(struct view *view); void view_set_ssd_mode(struct view *view, enum lab_ssd_mode mode); void view_set_decorations(struct view *view, enum lab_ssd_mode mode, bool force_ssd); void view_toggle_fullscreen(struct view *view); diff --git a/src/ssd/ssd.c b/src/ssd/ssd.c index 97338c26..db706085 100644 --- a/src/ssd/ssd.c +++ b/src/ssd/ssd.c @@ -32,7 +32,7 @@ ssd_thickness(struct view *view) * in border-only deco mode as view->ssd would only be set * after ssd_create() returns. */ - if (!view->ssd_enabled || view->fullscreen) { + if (!view->ssd_mode || view->fullscreen) { return (struct border){ 0 }; } @@ -40,7 +40,7 @@ ssd_thickness(struct view *view) if (view->maximized == VIEW_AXIS_BOTH) { struct border thickness = { 0 }; - if (!view->ssd_titlebar_hidden) { + if (view_titlebar_visible(view)) { thickness.top += theme->titlebar_height; } return thickness; @@ -53,7 +53,7 @@ ssd_thickness(struct view *view) .left = theme->border_width, }; - if (view->ssd_titlebar_hidden) { + if (!view_titlebar_visible(view)) { thickness.top -= theme->titlebar_height; } return thickness; @@ -89,14 +89,14 @@ static enum ssd_part_type get_resizing_type(const struct ssd *ssd, struct wlr_cursor *cursor) { struct view *view = ssd ? ssd->view : NULL; - if (!view || !cursor || !view->ssd_enabled || view->fullscreen) { + if (!view || !cursor || !view->ssd_mode || view->fullscreen) { return LAB_SSD_NONE; } struct wlr_box view_box = view->current; view_box.height = view_effective_height(view, /* use_pending */ false); - if (!view->ssd_titlebar_hidden) { + if (view_titlebar_visible(view)) { /* If the titlebar is visible, consider it part of the view */ int titlebar_height = view->server->theme->titlebar_height; view_box.y -= titlebar_height; @@ -250,7 +250,7 @@ ssd_create(struct view *view, bool active) */ ssd_titlebar_create(ssd); ssd_border_create(ssd); - if (view->ssd_titlebar_hidden) { + if (!view_titlebar_visible(view)) { /* Ensure we keep the old state on Reconfigure or when exiting fullscreen */ ssd_set_titlebar(ssd, false); } diff --git a/src/view.c b/src/view.c index ff863d32..75f8bad1 100644 --- a/src/view.c +++ b/src/view.c @@ -80,6 +80,7 @@ view_query_create(void) struct view_query *query = znew(*query); query->window_type = -1; query->maximized = VIEW_AXIS_INVALID; + query->decoration = LAB_SSD_MODE_INVALID; return query; } @@ -206,8 +207,8 @@ view_matches_query(struct view *view, struct view_query *query) } } - enum lab_ssd_mode decor = view_get_ssd_mode(view); - if (query->decoration != LAB_SSD_MODE_INVALID && query->decoration != decor) { + if (query->decoration != LAB_SSD_MODE_INVALID + && query->decoration != view->ssd_mode) { return false; } @@ -1316,7 +1317,7 @@ view_apply_maximized_geometry(struct view *view) &natural.x, &natural.y); } - if (view->ssd_enabled) { + if (view->ssd_mode) { struct border border = ssd_thickness(view); box.x += border.left; box.y += border.top; @@ -1557,7 +1558,7 @@ view_set_decorations(struct view *view, enum lab_ssd_mode mode, bool force_ssd) assert(view); if (force_ssd || view_wants_decorations(view) - || mode < view_get_ssd_mode(view)) { + || mode < view->ssd_mode) { view_set_ssd_mode(view, mode); } } @@ -1567,10 +1568,9 @@ view_toggle_decorations(struct view *view) { assert(view); - enum lab_ssd_mode mode = view_get_ssd_mode(view); - if (rc.ssd_keep_border && mode == LAB_SSD_MODE_FULL) { + if (rc.ssd_keep_border && view->ssd_mode == LAB_SSD_MODE_FULL) { view_set_ssd_mode(view, LAB_SSD_MODE_BORDER); - } else if (mode != LAB_SSD_MODE_NONE) { + } else if (view->ssd_mode != LAB_SSD_MODE_NONE) { view_set_ssd_mode(view, LAB_SSD_MODE_NONE); } else { view_set_ssd_mode(view, LAB_SSD_MODE_FULL); @@ -1657,18 +1657,10 @@ undecorate(struct view *view) view->ssd = NULL; } -enum lab_ssd_mode -view_get_ssd_mode(struct view *view) +bool +view_titlebar_visible(struct view *view) { - assert(view); - - if (!view->ssd_enabled) { - return LAB_SSD_MODE_NONE; - } else if (view->ssd_titlebar_hidden) { - return LAB_SSD_MODE_BORDER; - } else { - return LAB_SSD_MODE_FULL; - } + return view->ssd_mode == LAB_SSD_MODE_FULL; } void @@ -1677,7 +1669,7 @@ view_set_ssd_mode(struct view *view, enum lab_ssd_mode mode) assert(view); if (view->shaded || view->fullscreen - || mode == view_get_ssd_mode(view)) { + || mode == view->ssd_mode) { return; } @@ -1685,12 +1677,11 @@ view_set_ssd_mode(struct view *view, enum lab_ssd_mode mode) * Set these first since they are referenced * within the call tree of ssd_create() and ssd_thickness() */ - view->ssd_enabled = mode != LAB_SSD_MODE_NONE; - view->ssd_titlebar_hidden = mode != LAB_SSD_MODE_FULL; + view->ssd_mode = mode; - if (view->ssd_enabled) { + if (mode) { decorate(view); - ssd_set_titlebar(view->ssd, !view->ssd_titlebar_hidden); + ssd_set_titlebar(view->ssd, view_titlebar_visible(view)); } else { undecorate(view); } @@ -1718,7 +1709,7 @@ set_fullscreen(struct view *view, bool fullscreen) } /* Hide decorations when going fullscreen */ - if (fullscreen && view->ssd_enabled) { + if (fullscreen && view->ssd_mode) { undecorate(view); } @@ -1730,7 +1721,7 @@ set_fullscreen(struct view *view, bool fullscreen) wl_signal_emit_mutable(&view->events.fullscreened, NULL); /* Re-show decorations when no longer fullscreen */ - if (!fullscreen && view->ssd_enabled) { + if (!fullscreen && view->ssd_mode) { decorate(view); } @@ -2393,7 +2384,7 @@ void view_reload_ssd(struct view *view) { assert(view); - if (view->ssd_enabled && !view->fullscreen) { + if (view->ssd_mode && !view->fullscreen) { undecorate(view); decorate(view); } @@ -2416,7 +2407,7 @@ view_toggle_keybinds(struct view *view) assert(view); view->inhibits_keybinds = !view->inhibits_keybinds; - if (view->ssd_enabled) { + if (view->ssd_mode) { ssd_enable_keybind_inhibit_indicator(view->ssd, view->inhibits_keybinds); } @@ -2498,7 +2489,7 @@ view_set_shade(struct view *view, bool shaded) } /* Views without a title-bar or SSD cannot be shaded */ - if (shaded && (!view->ssd || view->ssd_titlebar_hidden)) { + if (shaded && (!view->ssd || !view_titlebar_visible(view))) { return; } From 888dbedeed416ee18e73129fc5bb0a23eebc31d8 Mon Sep 17 00:00:00 2001 From: tokyo4j Date: Thu, 21 Aug 2025 13:56:37 +0900 Subject: [PATCH 4/6] ssd: allow hiding titlebar on maximization hides the titlebar when a window is maximized. Co-authored-by: @CosmicFusion --- docs/labwc-config.5.scd | 6 ++++++ docs/rc.xml.all | 1 + include/config/rcxml.h | 1 + src/config/rcxml.c | 7 +++++++ src/ssd/ssd.c | 6 ++++++ src/view.c | 4 ++++ 6 files changed, 25 insertions(+) diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd index 860391c9..e86fb75f 100644 --- a/docs/labwc-config.5.scd +++ b/docs/labwc-config.5.scd @@ -171,6 +171,7 @@ this is for compatibility with Openbox. ``` server + titlebar 0 no no @@ -186,6 +187,11 @@ this is for compatibility with Openbox. that it is not always possible to turn off client side decorations. Default is server. +** [titlebar|none] + Specify how server side decorations are shown for maximized windows. + *titlebar* shows titlebar above a maximized window. *none* shows no server + side decorations around a maximized window. Default is titlebar. + ** The distance in pixels between windows and output edges when using movement actions, for example MoveToEdge. Default is 0. diff --git a/docs/rc.xml.all b/docs/rc.xml.all index 3084aee5..91dc7791 100644 --- a/docs/rc.xml.all +++ b/docs/rc.xml.all @@ -11,6 +11,7 @@ server + titlebar 0 no no diff --git a/include/config/rcxml.h b/include/config/rcxml.h index a7eb22bd..cb3dd1b9 100644 --- a/include/config/rcxml.h +++ b/include/config/rcxml.h @@ -66,6 +66,7 @@ struct rcxml { /* core */ bool xdg_shell_server_side_deco; + bool hide_maximized_window_titlebar; int gap; enum adaptive_sync_mode adaptive_sync; enum tearing_mode allow_tearing; diff --git a/src/config/rcxml.c b/src/config/rcxml.c index 8746836b..52e02c4b 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -1094,6 +1094,12 @@ entry(xmlNode *node, char *nodename, char *content) } else { rc.xdg_shell_server_side_deco = true; } + } else if (!strcasecmp(nodename, "maximizedDecoration.core")) { + if (!strcasecmp(content, "titlebar")) { + rc.hide_maximized_window_titlebar = false; + } else if (!strcasecmp(content, "none")) { + rc.hide_maximized_window_titlebar = true; + } } else if (!strcmp(nodename, "gap.core")) { rc.gap = atoi(content); } else if (!strcasecmp(nodename, "adaptiveSync.core")) { @@ -1370,6 +1376,7 @@ rcxml_init(void) rc.placement_cascade_offset_y = 0; rc.xdg_shell_server_side_deco = true; + rc.hide_maximized_window_titlebar = false; rc.show_title = true; rc.title_layout_loaded = false; rc.ssd_keep_border = true; diff --git a/src/ssd/ssd.c b/src/ssd/ssd.c index db706085..3d0dd7a0 100644 --- a/src/ssd/ssd.c +++ b/src/ssd/ssd.c @@ -312,6 +312,12 @@ ssd_update_geometry(struct ssd *ssd) || ssd->state.was_squared != squared || ssd->state.was_omnipresent != view->visible_on_all_workspaces; + /* + * (Un)maximization updates titlebar visibility with + * maximizedDecoration=none + */ + ssd_set_titlebar(ssd, view_titlebar_visible(view)); + if (update_extents) { ssd_extents_update(ssd); } diff --git a/src/view.c b/src/view.c index 75f8bad1..a81b03ad 100644 --- a/src/view.c +++ b/src/view.c @@ -1660,6 +1660,10 @@ undecorate(struct view *view) bool view_titlebar_visible(struct view *view) { + if (view->maximized == VIEW_AXIS_BOTH + && rc.hide_maximized_window_titlebar) { + return false; + } return view->ssd_mode == LAB_SSD_MODE_FULL; } From ebd39dfe0d1ded5af933075f5400909c9d2a2c99 Mon Sep 17 00:00:00 2001 From: John Lindgren Date: Sat, 23 Aug 2025 10:44:26 -0400 Subject: [PATCH 5/6] view: respect client-initiated resize of non-maximized axis When implementing single-axis maximize some time ago, I made the simplifying assumption that a view couldn't be resized while maximized (even in only one axis). And indeed for compositor-initiated resize, we always unmaximize the view first. However, I didn't account for the client resizing the non-maximized axis, which we can't (and shouldn't) prevent. When this happens, we should also update the natural geometry of that single axis so that we don't undo the resize when un-maximizing. P.S. xdg-shell clients resizing the *maximized* axis is still an unsolved problem, exacerbated by the fact that xdg-shell protocol doesn't allow clients to even know about single-axis maximize. P.P.S. the view_invalidate_last_layout_geometry() logic may need similar updates, I'm not sure. --- src/interactive.c | 4 ++-- src/view.c | 27 +++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/src/interactive.c b/src/interactive.c index b50d27a4..8a8903da 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -90,9 +90,9 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) return; } + /* Store natural geometry at start of move */ + view_store_natural_geometry(view); if (view_is_floating(view)) { - /* Store natural geometry at start of move */ - view_store_natural_geometry(view); view_invalidate_last_layout_geometry(view); } diff --git a/src/view.c b/src/view.c index a81b03ad..8ddef7d4 100644 --- a/src/view.c +++ b/src/view.c @@ -971,8 +971,11 @@ void view_store_natural_geometry(struct view *view) { assert(view); - if (!view_is_floating(view)) { - /* Do not overwrite the stored geometry with special cases */ + /* + * Do not overwrite the stored geometry if fullscreen or tiled. + * Maximized views are handled on a per-axis basis (see below). + */ + if (view->fullscreen || view_is_tiled(view)) { return; } @@ -983,7 +986,14 @@ view_store_natural_geometry(struct view *view) * xdg-toplevel configure event, which means the application should * choose its own size. */ - view->natural_geometry = view->pending; + if (!(view->maximized & VIEW_AXIS_HORIZONTAL)) { + view->natural_geometry.x = view->pending.x; + view->natural_geometry.width = view->pending.width; + } + if (!(view->maximized & VIEW_AXIS_VERTICAL)) { + view->natural_geometry.y = view->pending.y; + view->natural_geometry.height = view->pending.height; + } } int @@ -1472,11 +1482,20 @@ view_maximize(struct view *view, enum view_axis axis, */ interactive_cancel(view); if (store_natural_geometry && view_is_floating(view)) { - view_store_natural_geometry(view); view_invalidate_last_layout_geometry(view); } } + /* + * Update natural geometry for any axis that wasn't already + * maximized. This is needed even when unmaximizing, because in + * single-axis cases the client may have resized the other axis + * while one axis was maximized. + */ + if (store_natural_geometry) { + view_store_natural_geometry(view); + } + /* * When natural geometry is unknown (0x0) for an xdg-shell view, * we normally send a configure event of 0x0 to get the client's From 55ee96761a047de6592f18ecdc9c3e4bff06ea37 Mon Sep 17 00:00:00 2001 From: tokyo4j Date: Mon, 25 Aug 2025 18:54:22 +0900 Subject: [PATCH 6/6] window-rules: fix window rules not being applied In 943f5751, I initialized heap-allocated `view_query` used for `If` actions with `decoration=LAB_SSD_MODE_INVALID`, but I forgot to do that for stack-allocated `view_query` used for window rules. --- src/view.c | 1 + src/window-rules.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/view.c b/src/view.c index 8ddef7d4..8c697daf 100644 --- a/src/view.c +++ b/src/view.c @@ -78,6 +78,7 @@ struct view_query * view_query_create(void) { struct view_query *query = znew(*query); + /* Must be synced with view_matches_criteria() in window-rules.c */ query->window_type = -1; query->maximized = VIEW_AXIS_INVALID; query->decoration = LAB_SSD_MODE_INVALID; diff --git a/src/window-rules.c b/src/window-rules.c index ed980efc..8283e801 100644 --- a/src/window-rules.c +++ b/src/window-rules.c @@ -36,7 +36,9 @@ view_matches_criteria(struct window_rule *rule, struct view *view) .window_type = rule->window_type, .sandbox_engine = rule->sandbox_engine, .sandbox_app_id = rule->sandbox_app_id, + /* Must be synced with view_query_create() */ .maximized = VIEW_AXIS_INVALID, + .decoration = LAB_SSD_MODE_INVALID, }; if (rule->match_once && other_instances_exist(view, &query)) {