From e05bedb14071a8263e306798005b74a29d241b8d Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Tue, 8 Aug 2023 03:39:35 +0200 Subject: [PATCH] feat: add Shade/Unshade/ToggleShade actions This builds on the work of @Consolatis in #1018. Co-authored-by: Consolatis <35009135+Consolatis@users.noreply.github.com> Co-authored-by: Andrew J. Hesford --- docs/labwc-actions.5.scd | 9 +++++ docs/menu.xml | 3 ++ docs/rc.xml.all | 8 +++++ include/ssd.h | 1 + include/view.h | 10 ++++++ po/labwc.pot | 32 +++++++++-------- src/action.c | 22 ++++++++++++ src/config/rcxml.c | 4 +++ src/input/cursor.c | 7 +++- src/interactive.c | 12 ++++--- src/menu/menu.c | 2 ++ src/placement.c | 10 +++--- src/resistance.c | 9 +++-- src/snap.c | 22 +++++++----- src/ssd/resize_indicator.c | 11 +++--- src/ssd/ssd.c | 24 +++++++++++-- src/ssd/ssd_border.c | 4 +-- src/ssd/ssd_extents.c | 2 +- src/view.c | 73 ++++++++++++++++++++++++++++++++++++-- 19 files changed, 218 insertions(+), 47 deletions(-) diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd index 38bad8a2..52beef42 100644 --- a/docs/labwc-actions.5.scd +++ b/docs/labwc-actions.5.scd @@ -229,6 +229,15 @@ Actions are used in menus and keyboard/mouse bindings. Use the automatic placement policy to move the active window to a position on its output that will minimize overlap with other windows. +**++ +**++ +** + Set, unset, or toggle, respectively, the "shaded" state of the active + window. When shaded, window contents are hidden, leaving only the + titlebar visible. Full-screen windows or those without server-side + decorations (including those for which the server-side titlebar has been + hidden) are not eligible for shading. + ** If used as the only action for a binding: clear an earlier defined binding. diff --git a/docs/menu.xml b/docs/menu.xml index d03f8e71..521d80a9 100644 --- a/docs/menu.xml +++ b/docs/menu.xml @@ -12,6 +12,9 @@ + + + diff --git a/docs/rc.xml.all b/docs/rc.xml.all index 012818c2..350a5be1 100644 --- a/docs/rc.xml.all +++ b/docs/rc.xml.all @@ -331,6 +331,14 @@ + + + + + + + + diff --git a/include/ssd.h b/include/ssd.h index f1b27516..5d0a32ee 100644 --- a/include/ssd.h +++ b/include/ssd.h @@ -68,6 +68,7 @@ void ssd_destroy(struct ssd *ssd); void ssd_titlebar_hide(struct ssd *ssd); void ssd_enable_keybind_inhibit_indicator(struct ssd *ssd, bool enable); +void ssd_enable_shade(struct ssd *ssd, bool enable); struct ssd_hover_state *ssd_hover_state_new(void); void ssd_update_button_hover(struct wlr_scene_node *node, diff --git a/include/view.h b/include/view.h index c446df8b..f18904fc 100644 --- a/include/view.h +++ b/include/view.h @@ -148,6 +148,7 @@ struct view { bool ssd_enabled; bool ssd_titlebar_hidden; enum ssd_preference ssd_preference; + bool shaded; bool minimized; enum view_axis maximized; bool fullscreen; @@ -394,6 +395,13 @@ bool view_compute_centered_position(struct view *view, bool view_adjust_floating_geometry(struct view *view, struct wlr_box *geometry); void view_store_natural_geometry(struct view *view); +/** + * view_effective_height - effective height of view, with respect to shaded state + * @view: view for which effective height is desired + * @use_pending: if false, report current height; otherwise, report pending height + */ +int view_effective_height(struct view *view, bool use_pending); + /** * view_center - center view within some region * @view: view to be centered @@ -463,6 +471,8 @@ void view_update_title(struct view *view); void view_update_app_id(struct view *view); void view_reload_ssd(struct view *view); +void view_set_shade(struct view *view, bool shaded); + struct view_size_hints view_get_size_hints(struct view *view); void view_adjust_size(struct view *view, int *w, int *h); diff --git a/po/labwc.pot b/po/labwc.pot index eff1d14e..51508ea5 100644 --- a/po/labwc.pot +++ b/po/labwc.pot @@ -1,5 +1,5 @@ # Labwc pot file -# Copyright (C) 2023 +# Copyright (C) 2024 # This file is distributed under the same license as the labwc package. # FIRST AUTHOR , YEAR. # @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: labwc\n" "Report-Msgid-Bugs-To: https://github.com/labwc/labwc/issues\n" -"POT-Creation-Date: 2023-01-02 11:22+1000\n" +"POT-Creation-Date: 2024-01-15 16:00-0500\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,50 +17,54 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/menu/menu.c:698 +#: src/menu/menu.c:697 msgid "Reconfigure" msgstr "" -#: src/menu/menu.c:700 +#: src/menu/menu.c:699 msgid "Exit" msgstr "" -#: src/menu/menu.c:716 +#: src/menu/menu.c:715 msgid "Minimize" msgstr "" -#: src/menu/menu.c:718 +#: src/menu/menu.c:717 msgid "Maximize" msgstr "" -#: src/menu/menu.c:720 +#: src/menu/menu.c:719 msgid "Fullscreen" msgstr "" -#: src/menu/menu.c:722 +#: src/menu/menu.c:721 +msgid "Roll up/down" +msgstr "" + +#: src/menu/menu.c:723 msgid "Decorations" msgstr "" -#: src/menu/menu.c:724 +#: src/menu/menu.c:725 msgid "Always on Top" msgstr "" -#: src/menu/menu.c:729 +#: src/menu/menu.c:730 msgid "Move left" msgstr "" -#: src/menu/menu.c:736 +#: src/menu/menu.c:737 msgid "Move right" msgstr "" -#: src/menu/menu.c:741 +#: src/menu/menu.c:742 msgid "Always on Visible Workspace" msgstr "" -#: src/menu/menu.c:744 +#: src/menu/menu.c:745 msgid "Workspace" msgstr "" -#: src/menu/menu.c:747 +#: src/menu/menu.c:748 msgid "Close" msgstr "" diff --git a/src/action.c b/src/action.c index 46bc8c9e..d9b46866 100644 --- a/src/action.c +++ b/src/action.c @@ -103,6 +103,9 @@ enum action_type { ACTION_TYPE_VIRTUAL_OUTPUT_REMOVE, ACTION_TYPE_AUTO_PLACE, ACTION_TYPE_TOGGLE_TEARING, + ACTION_TYPE_SHADE, + ACTION_TYPE_UNSHADE, + ACTION_TYPE_TOGGLE_SHADE, }; const char *action_names[] = { @@ -151,6 +154,9 @@ const char *action_names[] = { "VirtualOutputRemove", "AutoPlace", "ToggleTearing", + "Shade", + "Unshade", + "ToggleShade", NULL }; @@ -841,6 +847,7 @@ actions_run(struct view *activator, struct server *server, .width = width ? : view->pending.width, .height = height ? : view->pending.height, }; + view_set_shade(view, false); view_move_resize(view, box); } break; @@ -960,6 +967,21 @@ actions_run(struct view *activator, struct server *server, view->tearing_hint ? "en" : "dis"); } break; + case ACTION_TYPE_TOGGLE_SHADE: + if (view) { + view_set_shade(view, !view->shaded); + } + break; + case ACTION_TYPE_SHADE: + if (view) { + view_set_shade(view, true); + } + break; + case ACTION_TYPE_UNSHADE: + if (view) { + view_set_shade(view, false); + } + break; case ACTION_TYPE_INVALID: wlr_log(WLR_ERROR, "Not executing unknown action"); break; diff --git a/src/config/rcxml.c b/src/config/rcxml.c index 4547422a..bc21a458 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -1166,6 +1166,10 @@ static struct mouse_combos { { "Frame", "A-Right", "Drag", "Resize", NULL, NULL}, { "Titlebar", "Left", "Press", "Focus", NULL, NULL}, { "Titlebar", "Left", "Press", "Raise", NULL, NULL}, + { "Titlebar", "Up", "Scroll", "Unfocus", NULL, NULL}, + { "Titlebar", "Up", "Scroll", "Shade", NULL, NULL}, + { "Titlebar", "Down", "Scroll", "Unshade", NULL, NULL}, + { "Titlebar", "Down", "Scroll", "Focus", NULL, NULL}, { "Title", "Left", "Drag", "Move", NULL, NULL }, { "Title", "Left", "DoubleClick", "ToggleMaximize", NULL, NULL }, { "TitleBar", "Right", "Click", "Focus", NULL, NULL}, diff --git a/src/input/cursor.c b/src/input/cursor.c index 309bb6cd..38bf250c 100644 --- a/src/input/cursor.c +++ b/src/input/cursor.c @@ -471,7 +471,12 @@ cursor_update_common(struct server *server, struct cursor_context *ctx, */ wlr_seat_pointer_notify_clear_focus(wlr_seat); if (!seat->drag.active) { - cursor_set(seat, cursor_get_from_ssd(ctx->type)); + enum lab_cursors cursor = cursor_get_from_ssd(ctx->type); + if (ctx->view && ctx->view->shaded && cursor > LAB_CURSOR_GRAB) { + /* Prevent resize cursor on borders for shaded SSD */ + cursor = LAB_CURSOR_DEFAULT; + } + cursor_set(seat, cursor); } } } diff --git a/src/interactive.c b/src/interactive.c index f92ab8c1..0a4e1818 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -55,7 +55,8 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) } if (!view_is_floating(view)) { /* - * Un-maximize and restore natural width/height. + * Un-maximize, unshade and restore natural + * width/height. * Don't reset tiled state yet since we may want * to keep it (in the snap-to-maximize case). */ @@ -66,6 +67,8 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) geometry.y = max_move_scale(seat->cursor->y, view->current.y, view->current.height, geometry.height); + + view_set_shade(view, false); view_restore_to(view, geometry); } else { /* Store natural geometry at start of move */ @@ -80,10 +83,11 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) cursor_set(seat, LAB_CURSOR_GRAB); break; case LAB_INPUT_STATE_RESIZE: - if (view->fullscreen || view->maximized == VIEW_AXIS_BOTH) { + if (view->shaded || view->fullscreen || + view->maximized == VIEW_AXIS_BOTH) { /* - * We don't allow resizing while fullscreen or - * maximized in both directions. + * We don't allow resizing while shaded, + * fullscreen or maximized in both directions. */ return; } diff --git a/src/menu/menu.c b/src/menu/menu.c index 236ab26d..5790caf5 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -718,6 +718,8 @@ init_windowmenu(struct server *server) fill_item("name.action", "ToggleMaximize"); current_item = item_create(menu, _("Fullscreen"), false); fill_item("name.action", "ToggleFullscreen"); + current_item = item_create(menu, _("Roll up/down"), false); + fill_item("name.action", "ToggleShade"); current_item = item_create(menu, _("Decorations"), false); fill_item("name.action", "ToggleDecorations"); current_item = item_create(menu, _("Always on Top"), false); diff --git a/src/placement.c b/src/placement.c index c2a724af..560b5e54 100644 --- a/src/placement.c +++ b/src/placement.c @@ -168,8 +168,9 @@ build_grid(struct overlap_bitmap *bmp, struct view *view) bmp->rows[nr_rows++] = y; } - x = v->pending.x + v->pending.width + margin.right; - y = v->pending.y + v->pending.height + margin.bottom; + x = v->pending.x + margin.right + v->pending.width; + y = v->pending.y + margin.bottom + + view_effective_height(v, /* use_pending */ true); /* Add a column if the right view edge is in the usable region */ if (x > usable.x && x < usable_right) { @@ -259,8 +260,9 @@ build_overlap(struct overlap_bitmap *bmp, struct view *view) struct border margin = ssd_get_margin(v->ssd); int lx = v->pending.x - margin.left; int ly = v->pending.y - margin.top; - int hx = v->pending.x + v->pending.width + margin.right; - int hy = v->pending.y + v->pending.height + margin.bottom; + int hx = v->pending.x + margin.right + v->pending.width; + int hy = v->pending.y + margin.bottom + + view_effective_height(v, /* use_pending */ true); /* * Find the first and last row and column intervals spanned by diff --git a/src/resistance.c b/src/resistance.c index 26ee84e6..a03080a9 100644 --- a/src/resistance.c +++ b/src/resistance.c @@ -47,15 +47,18 @@ resistance_move_apply(struct view *view, double *x, double *y) struct edges other_edges; /* The edges of the monitor/other view */ struct edges flags = { 0 }; + /* Use the effective height to properly snap shaded views */ + int eff_height = view_effective_height(view, /* use_pending */ false); + view_edges.left = vgeom.x - border.left + 1; view_edges.top = vgeom.y - border.top + 1; view_edges.right = vgeom.x + vgeom.width + border.right; - view_edges.bottom = vgeom.y + vgeom.height + border.bottom; + view_edges.bottom = vgeom.y + eff_height + border.bottom; target_edges.left = *x - border.left; target_edges.top = *y - border.top; target_edges.right = *x + vgeom.width + border.right; - target_edges.bottom = *y + vgeom.height + border.bottom; + target_edges.bottom = *y + eff_height + border.bottom; if (!rc.screen_edge_strength) { return; @@ -91,7 +94,7 @@ resistance_move_apply(struct view *view, double *x, double *y) if (flags.top == 1) { *y = other_edges.top + border.top; } else if (flags.bottom == 1) { - *y = other_edges.bottom - vgeom.height - border.bottom; + *y = other_edges.bottom - eff_height - border.bottom; } /* reset the flags */ diff --git a/src/snap.c b/src/snap.c index 7128f167..fd60cad0 100644 --- a/src/snap.c +++ b/src/snap.c @@ -37,8 +37,9 @@ snap_get_view_edge(struct view *view) struct border edge = { .left = view->pending.x - margin.left, .top = view->pending.y - margin.top, - .right = view->pending.x + view->pending.width + margin.right, - .bottom = view->pending.y + view->pending.height + margin.bottom + .right = view->pending.x + margin.right + view->pending.width, + .bottom = view->pending.y + margin.bottom + + view_effective_height(view, /* use_pending */ true) }; return edge; } @@ -52,9 +53,10 @@ snap_get_max_distance(struct view *view) struct border distance = { .left = usable.x + margin.left + rc.gap - view->pending.x, .top = usable.y + margin.top + rc.gap - view->pending.y, - .right = usable.x + usable.width - view->pending.width + .right = usable.x + usable.width - view->pending.width - margin.right - rc.gap - view->pending.x, - .bottom = usable.y + usable.height - view->pending.height + .bottom = usable.y + usable.height + - view_effective_height(view, /* use_pending */ true) - margin.bottom - rc.gap - view->pending.y }; return distance; @@ -115,7 +117,8 @@ _snap_next_edge(struct view *view, int start_pos, const struct snap_search def, vp += def.add_view_x * v->pending.x; vp += def.add_view_y * v->pending.y; vp += def.add_view_width * v->pending.width; - vp += def.add_view_height * v->pending.height; + vp += def.add_view_height + * view_effective_height(v, /* use_pending */ true); vp += gap; if (def.search_dir * vp > 0 && def.search_dir * (vp - p) < 0) { @@ -131,12 +134,15 @@ _snap_move_resize_to_edge(struct view *view, enum view_edge direction, enum snap { struct border edge = snap_get_view_edge(view); struct border dmax; + if (mode == SNAP_MODE_SHRINK) { /* limit to half of current size */ - int width_max_dx = max(view->pending.width - LAB_MIN_VIEW_WIDTH, 0); - int height_max_dy = max(view->pending.height - LAB_MIN_VIEW_HEIGHT, 0); + int eff_height = + view_effective_height(view, /* use_pending */ true); + int width_max_dx = max(view->pending.width - LAB_MIN_VIEW_WIDTH, 0); + int height_max_dy = max(eff_height - LAB_MIN_VIEW_HEIGHT, 0); dmax.right = min(width_max_dx, view->pending.width / 2); - dmax.bottom = min(height_max_dy, view->pending.height / 2); + dmax.bottom = min(height_max_dy, eff_height / 2); dmax.left = -dmax.right; dmax.top = -dmax.bottom; } else { diff --git a/src/ssd/resize_indicator.c b/src/ssd/resize_indicator.c index 5360f1c0..e140886d 100644 --- a/src/ssd/resize_indicator.c +++ b/src/ssd/resize_indicator.c @@ -159,14 +159,17 @@ resize_indicator_update(struct view *view) char text[32]; /* 12345 x 12345 would be 13 chars + 1 null byte */ + int eff_height = view_effective_height(view, /* use_pending */ false); + int eff_width = view->current.width; + switch (view->server->input_mode) { case LAB_INPUT_STATE_RESIZE: ; /* works around "a label can only be part of a statement" */ struct view_size_hints hints = view_get_size_hints(view); snprintf(text, sizeof(text), "%d x %d", - MAX(0, view->current.width - hints.base_width) + MAX(0, eff_width - hints.base_width) / MAX(1, hints.width_inc), - MAX(0, view->current.height - hints.base_height) + MAX(0, eff_height - hints.base_height) / MAX(1, hints.height_inc)); break; case LAB_INPUT_STATE_MOVE: @@ -192,8 +195,8 @@ resize_indicator_update(struct view *view) /* Center the indicator in the window */ wlr_scene_node_set_position(&indicator->tree->node, - (view->current.width - indicator->width) / 2, - (view->current.height - indicator->height) / 2); + (eff_width - indicator->width) / 2, + (eff_height - indicator->height) / 2); scaled_font_buffer_update(indicator->text, text, width, &rc.font_osd, rc.theme->osd_label_text_color, NULL /* const char *arrow */); diff --git a/src/ssd/ssd.c b/src/ssd/ssd.c index df18f1e5..dd7f1b60 100644 --- a/src/ssd/ssd.c +++ b/src/ssd/ssd.c @@ -61,11 +61,15 @@ ssd_max_extents(struct view *view) { assert(view); struct border border = ssd_thickness(view); + + int eff_width = view->current.width; + int eff_height = view_effective_height(view, /* use_pending */ false); + return (struct wlr_box){ .x = view->current.x - border.left, .y = view->current.y - border.top, - .width = view->current.width + border.left + border.right, - .height = view->current.height + border.top + border.bottom, + .width = eff_width + border.left + border.right, + .height = eff_height + border.top + border.bottom, }; } @@ -220,7 +224,11 @@ ssd_update_geometry(struct ssd *ssd) struct wlr_box cached = ssd->state.geometry; struct wlr_box current = ssd->view->current; - if (current.width == cached.width && current.height == cached.height) { + + int eff_width = current.width; + int eff_height = view_effective_height(ssd->view, /* use_pending */ false); + + if (eff_width == cached.width && eff_height == cached.height) { if (current.x != cached.x || current.y != cached.y) { /* Dynamically resize extents based on position and usable_area */ ssd_extents_update(ssd); @@ -333,6 +341,16 @@ ssd_set_active(struct ssd *ssd, bool active) wlr_scene_node_set_enabled(&ssd->titlebar.inactive.tree->node, !active); } +void +ssd_enable_shade(struct ssd *ssd, bool enable) +{ + if (!ssd) { + return; + } + ssd_border_update(ssd); + wlr_scene_node_set_enabled(&ssd->extents.tree->node, !enable); +} + void ssd_enable_keybind_inhibit_indicator(struct ssd *ssd, bool enable) { diff --git a/src/ssd/ssd_border.c b/src/ssd/ssd_border.c index c12b07b2..74f29ffa 100644 --- a/src/ssd/ssd_border.c +++ b/src/ssd/ssd_border.c @@ -20,7 +20,7 @@ ssd_border_create(struct ssd *ssd) struct view *view = ssd->view; struct theme *theme = view->server->theme; int width = view->current.width; - int height = view->current.height; + int height = view_effective_height(view, /* use_pending */ false); int full_width = width + 2 * theme->border_width; float *color; @@ -83,7 +83,7 @@ ssd_border_update(struct ssd *ssd) struct theme *theme = view->server->theme; int width = view->current.width; - int height = view->current.height; + int height = view_effective_height(view, /* use_pending */ false); int full_width = width + 2 * theme->border_width; struct ssd_part *part; diff --git a/src/ssd/ssd_extents.c b/src/ssd/ssd_extents.c index 22bfa579..9a926a2b 100644 --- a/src/ssd/ssd_extents.c +++ b/src/ssd/ssd_extents.c @@ -109,7 +109,7 @@ ssd_extents_update(struct ssd *ssd) struct theme *theme = view->server->theme; int width = view->current.width; - int height = view->current.height; + int height = view_effective_height(view, /* use_pending */ false); int full_height = height + theme->border_width * 2 + ssd->titlebar.height; int full_width = width + 2 * theme->border_width; int extended_area = SSD_EXTENDED_AREA; diff --git a/src/view.c b/src/view.c index 7ab09e2d..eac7893d 100644 --- a/src/view.c +++ b/src/view.c @@ -384,6 +384,7 @@ view_resize_relative(struct view *view, int left, int right, int top, int bottom if (view->fullscreen || view->maximized != VIEW_AXIS_NONE) { return; } + view_set_shade(view, false); struct wlr_box newgeo = view->pending; newgeo.x -= left; newgeo.width += left + right; @@ -703,6 +704,18 @@ view_store_natural_geometry(struct view *view) } } +int +view_effective_height(struct view *view, bool use_pending) +{ + assert(view); + + if (view->shaded) { + return 0; + } + + return use_pending ? view->pending.height : view->current.height; +} + void view_center(struct view *view, const struct wlr_box *ref) { @@ -1032,12 +1045,17 @@ view_maximize(struct view *view, enum view_axis axis, bool store_natural_geometry) { assert(view); + if (view->maximized == axis) { return; } + if (view->fullscreen) { return; } + + view_set_shade(view, false); + if (axis != VIEW_AXIS_NONE) { /* * Maximize via keybind or client request cancels @@ -1087,6 +1105,12 @@ void view_toggle_decorations(struct view *view) { assert(view); + + /* Reject decoration toggles when shaded */ + if (view->shaded) { + return; + } + if (rc.ssd_keep_border && view->ssd_enabled && view->ssd && !view->ssd_titlebar_hidden) { /* @@ -1209,6 +1233,7 @@ void view_toggle_fullscreen(struct view *view) { assert(view); + view_set_fullscreen(view, !view->fullscreen); } @@ -1216,6 +1241,11 @@ view_toggle_fullscreen(struct view *view) static void set_fullscreen(struct view *view, bool fullscreen) { + /* When going fullscreen, unshade the window */ + if (fullscreen) { + view_set_shade(view, false); + } + /* Hide decorations when going fullscreen */ if (fullscreen && view->ssd_enabled) { undecorate(view); @@ -1561,7 +1591,8 @@ view_move_to_edge(struct view *view, enum view_edge direction, bool snap_to_wind destination_y = top; break; case VIEW_EDGE_DOWN: - destination_y = bottom - view->pending.height; + destination_y = bottom + - view_effective_height(view, /* use_pending */ true); break; default: return; @@ -1578,9 +1609,11 @@ view_move_to_edge(struct view *view, enum view_edge direction, bool snap_to_wind destination_x = MAX(destination_x, left); /* If more than half the view is below usable region, align to bottom */ - midpoint = destination_y + view->pending.height / 2; + midpoint = destination_y + + view_effective_height(view, /* use_pending */ true) / 2; if (destination_y >= top && midpoint > usable.y + usable.height) { - destination_y = bottom - view->pending.height; + destination_y = bottom + - view_effective_height(view, /* use_pending */ true); } /* Never allow the window to start above the usable edge */ @@ -1599,11 +1632,14 @@ view_grow_to_edge(struct view *view, enum view_edge direction) if (view->fullscreen || view->maximized != VIEW_AXIS_NONE) { return; } + if (!output_is_usable(view->output)) { wlr_log(WLR_ERROR, "view has no output, not growing view"); return; } + view_set_shade(view, false); + struct wlr_box geo = view->pending; snap_grow_to_next_edge(view, direction, &geo); view_move_resize(view, geo); @@ -1613,15 +1649,19 @@ void view_shrink_to_edge(struct view *view, enum view_edge direction) { assert(view); + /* TODO: allow shrink to edge if maximized along the other axis */ if (view->fullscreen || view->maximized != VIEW_AXIS_NONE) { return; } + if (!output_is_usable(view->output)) { wlr_log(WLR_ERROR, "view has no output, not shrinking view"); return; } + view_set_shade(view, false); + struct wlr_box geo = view->pending; snap_shrink_to_next_edge(view, direction, &geo); view_move_resize(view, geo); @@ -1670,15 +1710,19 @@ view_snap_to_edge(struct view *view, enum view_edge edge, bool across_outputs, bool store_natural_geometry) { assert(view); + if (view->fullscreen) { return; } + struct output *output = view->output; if (!output_is_usable(output)) { wlr_log(WLR_ERROR, "view has no output, not snapping to edge"); return; } + view_set_shade(view, false); + if (across_outputs && view->tiled == edge && view->maximized == VIEW_AXIS_NONE) { /* We are already tiled for this edge; try to switch outputs */ output = view_get_adjacent_output(view, edge); @@ -1721,15 +1765,19 @@ view_snap_to_region(struct view *view, struct region *region, { assert(view); assert(region); + if (view->fullscreen) { return; } + /* view_apply_region_geometry() needs a usable output */ if (!output_is_usable(view->output)) { wlr_log(WLR_ERROR, "view has no output, not snapping to region"); return; } + view_set_shade(view, false); + if (view->maximized != VIEW_AXIS_NONE) { /* Unmaximize + keep using existing natural_geometry */ view_maximize(view, VIEW_AXIS_NONE, @@ -1974,6 +2022,25 @@ view_connect_map(struct view *view, struct wlr_surface *surface) mappable_connect(&view->mappable, surface, handle_map, handle_unmap); } +void +view_set_shade(struct view *view, bool shaded) +{ + assert(view); + + if (view->shaded == shaded) { + return; + } + + /* Views without a title-bar or SSD cannot be shaded */ + if (shaded && (!view->ssd || view->ssd_titlebar_hidden)) { + return; + } + + view->shaded = shaded; + ssd_enable_shade(view->ssd, view->shaded); + wlr_scene_node_set_enabled(view->scene_node, !view->shaded); +} + void view_destroy(struct view *view) {