Merge branch 'labwc:master' into menu_state

This commit is contained in:
David Barr 2025-08-26 19:11:13 +01:00 committed by GitHub
commit 06e3e712af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 188 additions and 142 deletions

View file

@ -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)",

59
src/common/edge.c Normal file
View file

@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-2.0-only
#include "common/edge.h"
#include <strings.h>
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;
}
}

View file

@ -3,6 +3,7 @@ labwc_sources += files(
'box.c',
'buf.c',
'dir.c',
'edge.c',
'fd-util.c',
'file-helpers.c',
'font.c',

View file

@ -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);
@ -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;

View file

@ -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);
}

View file

@ -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);
}
@ -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);
}

View file

@ -78,8 +78,10 @@ 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;
return query;
}
@ -206,8 +208,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;
}
@ -429,25 +431,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)
@ -989,8 +972,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;
}
@ -1001,7 +987,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
@ -1335,7 +1328,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;
@ -1490,11 +1483,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
@ -1576,7 +1578,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);
}
}
@ -1586,10 +1588,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);
@ -1676,18 +1677,14 @@ 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;
if (view->maximized == VIEW_AXIS_BOTH
&& rc.hide_maximized_window_titlebar) {
return false;
}
return view->ssd_mode == LAB_SSD_MODE_FULL;
}
void
@ -1696,7 +1693,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;
}
@ -1704,12 +1701,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);
}
@ -1737,7 +1733,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);
}
@ -1749,7 +1745,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);
}
@ -2020,7 +2016,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 +2116,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 +2172,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) {
@ -2451,7 +2408,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);
}
@ -2474,7 +2431,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);
}
@ -2556,7 +2513,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;
}

View file

@ -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)) {