diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd index 56097bca..c9e0c881 100644 --- a/docs/labwc-config.5.scd +++ b/docs/labwc-config.5.scd @@ -621,6 +621,7 @@ extending outward from the snapped edge. - 'close': close - 'shade': shade toggle - 'desk': all-desktops toggle + - 'ontop': always-on-top toggle A colon deliminator is used to separate buttons on the left and right, whereas commas are used to separate items within a section. It is @@ -900,6 +901,8 @@ input-devices by the Wayland protocol. - Shade: A button that, by default, toggles window shading. - AllDesktops: A button that, by default, toggles omnipresence of a window. + - OnTop: A button that, by default, toggles always-on-top state of a + window. - Close: A button that, by default, closses a window. - Border: The window's border including Top...BRCorner below. - Top: The top edge of the window's border. diff --git a/docs/labwc-theme.5.scd b/docs/labwc-theme.5.scd index 5f99cae7..b665761e 100644 --- a/docs/labwc-theme.5.scd +++ b/docs/labwc-theme.5.scd @@ -494,6 +494,8 @@ file within a particular theme. The following xbm buttons are supported: - max_toggled.xbm - desk.xbm - desk_toggled.xbm +- ontop.xbm +- ontop_toggled.xbm - shade.xbm - shade_toggled.xbm @@ -506,9 +508,11 @@ over the button in question: - menu_hover.xbm - max_toggled_hover.xbm - desk_hover.xbm -- desk_toggle_hover.xbm +- desk_toggled_hover.xbm +- ontop_hover.xbm +- ontop_toggled_hover.xbm - shade_hover.xbm -- shade_toggle_hover.xbm +- shade_toggled_hover.xbm One advantage of xbm buttons over other formats is that they change color based on the theme. Other formats use the suffices "-active" and "-inactive" to align @@ -558,7 +562,14 @@ following icons should be added: - desk_toggled-inactive.[png|svg] - desk_toggled_hover-active.[png|svg] - desk_toggled_hover-inactive.[png|svg] - +- ontop-active.[png|svg] +- ontop_hover-active.[png|svg] +- ontop_hover-inactive.[png|svg] +- ontop-inactive.[png|svg] +- ontop_toggled-active.[png|svg] +- ontop_toggled-inactive.[png|svg] +- ontop_toggled_hover-active.[png|svg] +- ontop_toggled_hover-inactive.[png|svg] # DEFINITIONS The handle is the window edge decoration at the bottom of the window. diff --git a/include/common/node-type.h b/include/common/node-type.h index 52fff3b0..ddda2100 100644 --- a/include/common/node-type.h +++ b/include/common/node-type.h @@ -26,8 +26,9 @@ enum lab_node_type { LAB_NODE_BUTTON_WINDOW_MENU, LAB_NODE_BUTTON_SHADE, LAB_NODE_BUTTON_OMNIPRESENT, + LAB_NODE_BUTTON_ONTOP, LAB_NODE_BUTTON_FIRST = LAB_NODE_BUTTON_CLOSE, - LAB_NODE_BUTTON_LAST = LAB_NODE_BUTTON_OMNIPRESENT, + LAB_NODE_BUTTON_LAST = LAB_NODE_BUTTON_ONTOP, LAB_NODE_BUTTON, LAB_NODE_TITLEBAR, diff --git a/include/config/default-bindings.h b/include/config/default-bindings.h index a49f60f4..f2b49cb8 100644 --- a/include/config/default-bindings.h +++ b/include/config/default-bindings.h @@ -291,6 +291,11 @@ static struct mouse_combos { .button = "Left", .event = "Click", .action = "ToggleOmnipresent", + }, { + .context = "OnTop", + .button = "Left", + .event = "Click", + .action = "ToggleAlwaysOnTop", }, { .context = "Maximize", .button = "Right", diff --git a/include/ssd-internal.h b/include/ssd-internal.h index 600b9076..106fdf76 100644 --- a/include/ssd-internal.h +++ b/include/ssd-internal.h @@ -79,6 +79,7 @@ struct ssd { * such a small titlebar. */ bool was_squared; + bool was_ontop; struct wlr_box geometry; struct ssd_state_title { diff --git a/src/common/node-type.c b/src/common/node-type.c index 67958dd4..b3b66f8c 100644 --- a/src/common/node-type.c +++ b/src/common/node-type.c @@ -20,6 +20,8 @@ node_type_parse(const char *context) return LAB_NODE_BUTTON_SHADE; } else if (!strcasecmp(context, "AllDesktops")) { return LAB_NODE_BUTTON_OMNIPRESENT; + } else if (!strcasecmp(context, "OnTop")) { + return LAB_NODE_BUTTON_ONTOP; } else if (!strcasecmp(context, "Titlebar")) { return LAB_NODE_TITLEBAR; } else if (!strcasecmp(context, "Title")) { diff --git a/src/config/rcxml.c b/src/config/rcxml.c index 0514b6c7..714507c7 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -184,6 +184,8 @@ fill_section(const char *content, enum lab_node_type *buttons, int *count, type = LAB_NODE_BUTTON_SHADE; } else if (!strcmp(identifier, "desk")) { type = LAB_NODE_BUTTON_OMNIPRESENT; + } else if (!strcmp(identifier, "ontop")) { + type = LAB_NODE_BUTTON_ONTOP; } else { wlr_log(WLR_ERROR, "invalid titleLayout identifier '%s'", identifier); diff --git a/src/ssd/ssd-titlebar.c b/src/ssd/ssd-titlebar.c index d1a08810..8d6f5f23 100644 --- a/src/ssd/ssd-titlebar.c +++ b/src/ssd/ssd-titlebar.c @@ -299,6 +299,12 @@ ssd_titlebar_update(struct ssd *ssd) ssd->state.was_omnipresent = view->visible_on_all_workspaces; } + if (ssd->state.was_ontop != view->layer) { + set_alt_button_icon(ssd, LAB_NODE_BUTTON_ONTOP, + view->layer); + ssd->state.was_ontop = view->layer; + } + if (width == ssd->state.geometry.width) { return; } diff --git a/src/ssd/ssd.c b/src/ssd/ssd.c index e2ab6375..731bc3d0 100644 --- a/src/ssd/ssd.c +++ b/src/ssd/ssd.c @@ -227,7 +227,8 @@ ssd_update_geometry(struct ssd *ssd) bool state_changed = ssd->state.was_maximized != maximized || ssd->state.was_shaded != view->shaded || ssd->state.was_squared != squared - || ssd->state.was_omnipresent != view->visible_on_all_workspaces; + || ssd->state.was_omnipresent != view->visible_on_all_workspaces + || ssd->state.was_ontop != (view->layer == VIEW_LAYER_ALWAYS_ON_TOP); /* * (Un)maximization updates titlebar visibility with diff --git a/src/theme.c b/src/theme.c index 93ac1c5e..50b80a54 100644 --- a/src/theme.c +++ b/src/theme.c @@ -315,6 +315,16 @@ load_buttons(struct theme *theme) .fallback_button = (const char[]){ 0x00, 0x1e, 0x1a, 0x16, 0x1e, 0x00 }, .type = LAB_NODE_BUTTON_OMNIPRESENT, .state_set = LAB_BS_TOGGLED, + }, { + .name = "ontop", + .fallback_button = (const char[]){ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c }, + .type = LAB_NODE_BUTTON_ONTOP, + .state_set = 0, + }, { + .name = "ontop_toggled", + .fallback_button = (const char[]){ 0x00, 0x0c, 0x1e, 0x33, 0x21, 0x00 }, + .type = LAB_NODE_BUTTON_ONTOP, + .state_set = LAB_BS_TOGGLED, }, { .name = "close", .fallback_button = (const char[]){ 0x33, 0x3f, 0x1e, 0x1e, 0x3f, 0x33 }, @@ -363,6 +373,17 @@ load_buttons(struct theme *theme) .type = LAB_NODE_BUTTON_OMNIPRESENT, .state_set = LAB_BS_TOGGLED | LAB_BS_HOVERED, /* no fallback (non-hover variant is used instead) */ + }, { + .name = "ontop_hover", + /* no fallback (non-hover variant is used instead) */ + .type = LAB_NODE_BUTTON_ONTOP, + .state_set = LAB_BS_HOVERED, + }, { + .name = "ontop_toggled_hover", + .alt_name = "ontop_hover_toggled", + .type = LAB_NODE_BUTTON_ONTOP, + .state_set = LAB_BS_TOGGLED | LAB_BS_HOVERED, + /* no fallback (non-hover variant is used instead) */ }, { .name = "close_hover", .type = LAB_NODE_BUTTON_CLOSE, @@ -836,6 +857,10 @@ entry(struct theme *theme, const char *key, const char *value) parse_color(value, theme->window[SSD_ACTIVE] .button_colors[LAB_NODE_BUTTON_OMNIPRESENT]); } + if (match_glob(key, "window.active.button.ontop.unpressed.image.color")) { + parse_color(value, theme->window[SSD_ACTIVE] + .button_colors[LAB_NODE_BUTTON_ONTOP]); + } if (match_glob(key, "window.active.button.close.unpressed.image.color")) { parse_color(value, theme->window[SSD_ACTIVE] .button_colors[LAB_NODE_BUTTON_CLOSE]); @@ -862,6 +887,10 @@ entry(struct theme *theme, const char *key, const char *value) parse_color(value, theme->window[SSD_INACTIVE] .button_colors[LAB_NODE_BUTTON_OMNIPRESENT]); } + if (match_glob(key, "window.inactive.button.ontop.unpressed.image.color")) { + parse_color(value, theme->window[SSD_INACTIVE] + .button_colors[LAB_NODE_BUTTON_ONTOP]); + } if (match_glob(key, "window.inactive.button.close.unpressed.image.color")) { parse_color(value, theme->window[SSD_INACTIVE] .button_colors[LAB_NODE_BUTTON_CLOSE]); diff --git a/src/view.c b/src/view.c index bcbd366e..7a946664 100644 --- a/src/view.c +++ b/src/view.c @@ -1562,6 +1562,8 @@ view_toggle_always_on_top(struct view *view) } else { view_set_layer(view, VIEW_LAYER_ALWAYS_ON_TOP); } + // Hack to update always-on-top ssd button state. May be wasteful, idk. + ssd_update_geometry(view->ssd); } void