diff --git a/docs/labwc-actions.5.scd b/docs/labwc-actions.5.scd
index 418cff55..b5daf093 100644
--- a/docs/labwc-actions.5.scd
+++ b/docs/labwc-actions.5.scd
@@ -80,6 +80,14 @@ Actions are used in menus and keyboard/mouse bindings.
**
Toggle decorations of focused window.
+ This is a 3-state action which can be executed multiple times:
+ - Only the titlebar will be hidden, borders and resize area are kept
+ - Remaining decorations will be disabled
+ - Decorations will be shown normally
+
+ By disabling the theme configuration 'keepBorder' the first step
+ will be removed and the action only toggles between on and off.
+
**
Toggle fullscreen state of focused window.
diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd
index 7a9e5181..10b22842 100644
--- a/docs/labwc-config.5.scd
+++ b/docs/labwc-config.5.scd
@@ -218,6 +218,10 @@ Therefore, where multiple objects of the same kind are required (for example
**
The radius of server side decoration top corners. Default is 8.
+** [yes|no]
+ Even when disabling server side decorations via ToggleDecorations,
+ keep a small border (and resize area) around the window. Default is yes.
+
**
The font to use for a specific element of a window, menu or OSD.
Places can be any of:
diff --git a/docs/rc.xml.all b/docs/rc.xml.all
index 23457f35..445b61dc 100644
--- a/docs/rc.xml.all
+++ b/docs/rc.xml.all
@@ -18,6 +18,7 @@
8
+ yes
sans
10
diff --git a/include/config/rcxml.h b/include/config/rcxml.h
index 88a2ee0f..62a06ab6 100644
--- a/include/config/rcxml.h
+++ b/include/config/rcxml.h
@@ -48,6 +48,7 @@ struct rcxml {
/* theme */
char *theme_name;
int corner_radius;
+ bool ssd_keep_border;
struct font font_activewindow;
struct font font_menuitem;
struct font font_osd;
diff --git a/include/ssd-internal.h b/include/ssd-internal.h
index d6459122..755e5db4 100644
--- a/include/ssd-internal.h
+++ b/include/ssd-internal.h
@@ -54,7 +54,8 @@ struct ssd {
/* The top of the view, containing buttons, title, .. */
struct {
- /* struct wlr_scene_tree *tree; unused for now */
+ int height;
+ struct wlr_scene_tree *tree;
struct ssd_sub_tree active;
struct ssd_sub_tree inactive;
} titlebar;
diff --git a/include/ssd.h b/include/ssd.h
index 5e82be2c..814c6ca2 100644
--- a/include/ssd.h
+++ b/include/ssd.h
@@ -63,6 +63,8 @@ void ssd_set_active(struct ssd *ssd, bool active);
void ssd_update_title(struct ssd *ssd);
void ssd_update_geometry(struct ssd *ssd);
void ssd_destroy(struct ssd *ssd);
+bool ssd_titlebar_is_hidden(struct ssd *ssd);
+void ssd_titlebar_hide(struct ssd *ssd);
void ssd_enable_keybind_inhibit_indicator(struct ssd *ssd, bool enable);
diff --git a/include/view.h b/include/view.h
index 79963b4b..5ba62a5b 100644
--- a/include/view.h
+++ b/include/view.h
@@ -89,6 +89,7 @@ struct view {
bool mapped;
bool been_mapped;
bool ssd_enabled;
+ bool ssd_titlebar_hidden;
enum ssd_preference ssd_preference;
bool minimized;
bool maximized;
diff --git a/src/config/rcxml.c b/src/config/rcxml.c
index 42f89442..735afeb3 100644
--- a/src/config/rcxml.c
+++ b/src/config/rcxml.c
@@ -575,6 +575,8 @@ entry(xmlNode *node, char *nodename, char *content)
rc.theme_name = xstrdup(content);
} else if (!strcmp(nodename, "cornerradius.theme")) {
rc.corner_radius = atoi(content);
+ } else if (!strcasecmp(nodename, "keepBorder.theme")) {
+ set_bool(content, &rc.ssd_keep_border);
} else if (!strcmp(nodename, "name.font.theme")) {
fill_font(nodename, content, font_place);
} else if (!strcmp(nodename, "size.font.theme")) {
@@ -780,6 +782,7 @@ rcxml_init(void)
has_run = true;
rc.xdg_shell_server_side_deco = true;
+ rc.ssd_keep_border = true;
rc.corner_radius = 8;
init_font_defaults(&rc.font_activewindow);
diff --git a/src/ssd/ssd.c b/src/ssd/ssd.c
index 3cd9b875..f2d3f267 100644
--- a/src/ssd/ssd.c
+++ b/src/ssd/ssd.c
@@ -25,13 +25,19 @@ ssd_thickness(struct view *view)
if (!view->ssd_enabled || view->fullscreen) {
return (struct border){ 0 };
}
+
struct theme *theme = view->server->theme;
- return (struct border){
+ struct border thickness = {
.top = theme->title_height + theme->border_width,
.bottom = theme->border_width,
.left = theme->border_width,
.right = theme->border_width,
};
+
+ if (ssd_titlebar_is_hidden(view->ssd)) {
+ thickness.top -= theme->title_height;
+ }
+ return thickness;
}
struct wlr_box
@@ -158,9 +164,14 @@ ssd_create(struct view *view, bool active)
ssd->view = view;
ssd->tree = wlr_scene_tree_create(view->scene_tree);
wlr_scene_node_lower_to_bottom(&ssd->tree->node);
+ ssd->titlebar.height = view->server->theme->title_height;
ssd_extents_create(ssd);
ssd_border_create(ssd);
ssd_titlebar_create(ssd);
+ if (rc.ssd_keep_border && view->ssd_titlebar_hidden) {
+ /* Ensure we keep the old state when exiting fullscreen */
+ ssd_titlebar_hide(ssd);
+ }
ssd->margin = ssd_thickness(view);
ssd_set_active(ssd, active);
ssd_enable_keybind_inhibit_indicator(ssd, view->inhibits_keybinds);
@@ -198,6 +209,25 @@ ssd_update_geometry(struct ssd *ssd)
ssd->state.geometry = current;
}
+bool
+ssd_titlebar_is_hidden(struct ssd *ssd)
+{
+ return ssd && !ssd->titlebar.tree->node.enabled;
+}
+
+void
+ssd_titlebar_hide(struct ssd *ssd)
+{
+ if (!ssd || !ssd->titlebar.tree->node.enabled) {
+ return;
+ }
+ wlr_scene_node_set_enabled(&ssd->titlebar.tree->node, false);
+ ssd->titlebar.height = 0;
+ ssd_border_update(ssd);
+ ssd_extents_update(ssd);
+ ssd->margin = ssd_thickness(ssd->view);
+}
+
void
ssd_destroy(struct ssd *ssd)
{
diff --git a/src/ssd/ssd_border.c b/src/ssd/ssd_border.c
index 1c9eb538..d7cc0e34 100644
--- a/src/ssd/ssd_border.c
+++ b/src/ssd/ssd_border.c
@@ -44,7 +44,7 @@ ssd_border_create(struct ssd *ssd)
add_scene_rect(&subtree->parts, LAB_SSD_PART_TOP, parent,
width - 2 * SSD_BUTTON_WIDTH, theme->border_width,
theme->border_width + SSD_BUTTON_WIDTH,
- -(theme->title_height + theme->border_width), color);
+ -(ssd->titlebar.height + theme->border_width), color);
} FOR_EACH_END
}
@@ -82,9 +82,19 @@ ssd_border_update(struct ssd *ssd)
0, height);
continue;
case LAB_SSD_PART_TOP:
- wlr_scene_rect_set_size(rect,
- width - 2 * SSD_BUTTON_WIDTH,
- theme->border_width);
+ if (ssd->titlebar.height > 0) {
+ wlr_scene_rect_set_size(rect,
+ width - 2 * SSD_BUTTON_WIDTH,
+ theme->border_width);
+ wlr_scene_node_set_position(part->node,
+ theme->border_width + SSD_BUTTON_WIDTH,
+ -(ssd->titlebar.height + theme->border_width));
+ } else {
+ wlr_scene_rect_set_size(rect,
+ full_width, theme->border_width);
+ wlr_scene_node_set_position(part->node,
+ 0, -theme->border_width);
+ }
continue;
default:
continue;
diff --git a/src/ssd/ssd_extents.c b/src/ssd/ssd_extents.c
index aa3e2710..1b6f465d 100644
--- a/src/ssd/ssd_extents.c
+++ b/src/ssd/ssd_extents.c
@@ -41,7 +41,7 @@ ssd_extents_create(struct ssd *ssd)
wl_list_init(&ssd->extents.parts);
wlr_scene_node_set_position(&parent->node,
-(theme->border_width + extended_area),
- -(theme->title_height + theme->border_width + extended_area));
+ -(ssd->titlebar.height + theme->border_width + extended_area));
/* Initialize parts and set constant values for targeted geometry */
struct ssd_part *p;
@@ -110,7 +110,7 @@ ssd_extents_update(struct ssd *ssd)
int width = view->current.width;
int height = view->current.height;
- int full_height = height + theme->border_width * 2 + theme->title_height;
+ 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;
int corner_size = extended_area + theme->border_width + SSD_BUTTON_WIDTH / 2;
@@ -122,6 +122,11 @@ ssd_extents_update(struct ssd *ssd)
struct ssd_part *part;
struct wlr_scene_rect *rect;
+ /* Make sure we update the y offset based on titlebar shown / hidden */
+ wlr_scene_node_set_position(&ssd->extents.tree->node,
+ -(theme->border_width + extended_area),
+ -(ssd->titlebar.height + theme->border_width + extended_area));
+
/* Convert usable area into layout coordinates */
struct wlr_box usable_area = view->output->usable_area;
usable_area.x += l_output->x;
diff --git a/src/ssd/ssd_titlebar.c b/src/ssd/ssd_titlebar.c
index 11db0500..cadb7de6 100644
--- a/src/ssd/ssd_titlebar.c
+++ b/src/ssd/ssd_titlebar.c
@@ -34,9 +34,11 @@ ssd_titlebar_create(struct ssd *ssd)
struct wlr_buffer *maximize_button_unpressed;
struct wlr_buffer *close_button_unpressed;
+ ssd->titlebar.tree = wlr_scene_tree_create(ssd->tree);
+
struct ssd_sub_tree *subtree;
FOR_EACH_STATE(ssd, subtree) {
- subtree->tree = wlr_scene_tree_create(ssd->tree);
+ subtree->tree = wlr_scene_tree_create(ssd->titlebar.tree);
parent = subtree->tree;
wlr_scene_node_set_position(&parent->node, 0, -theme->title_height);
if (subtree == &ssd->titlebar.active) {
@@ -138,7 +140,7 @@ ssd_titlebar_update(struct ssd *ssd)
void
ssd_titlebar_destroy(struct ssd *ssd)
{
- if (!ssd->titlebar.active.tree) {
+ if (!ssd->titlebar.tree) {
return;
}
@@ -153,6 +155,9 @@ ssd_titlebar_destroy(struct ssd *ssd)
free(ssd->state.title.text);
ssd->state.title.text = NULL;
}
+
+ wlr_scene_node_destroy(&ssd->titlebar.tree->node);
+ ssd->titlebar.tree = NULL;
}
/*
diff --git a/src/view.c b/src/view.c
index 4c72e13f..729cedb2 100644
--- a/src/view.c
+++ b/src/view.c
@@ -658,6 +658,15 @@ void
view_toggle_decorations(struct view *view)
{
assert(view);
+ if (rc.ssd_keep_border && view->ssd_enabled && view->ssd
+ && !ssd_titlebar_is_hidden(view->ssd)) {
+ ssd_titlebar_hide(view->ssd);
+ view->ssd_titlebar_hidden = true;
+ if (!view_is_floating(view)) {
+ view_apply_special_geometry(view);
+ }
+ return;
+ }
view_set_decorations(view, !view->ssd_enabled);
}
@@ -748,6 +757,7 @@ view_set_decorations(struct view *view, bool decorations)
decorate(view);
} else {
undecorate(view);
+ view->ssd_titlebar_hidden = false;
}
if (!view_is_floating(view)) {
view_apply_special_geometry(view);