mirror of
https://github.com/labwc/labwc.git
synced 2026-03-05 01:40:24 -05:00
theme: finish titleLayout implementation (#2150)
Change Openbox style WLIMC syntax to `menu:iconify,max,close` as was agreed when PR #2088 was merged. <titlebar> <layout>menu:iconify,max,close</layout> <showTitle>yes|on</showTitle> </titlebar> Ref: - https://github.com/labwc/labwc/pull/2088#issuecomment-2295730704
This commit is contained in:
parent
04a145f89a
commit
cc26ac29b9
3 changed files with 140 additions and 52 deletions
|
|
@ -437,19 +437,24 @@ extending outward from the snapped edge.
|
||||||
*<theme><name>*
|
*<theme><name>*
|
||||||
The name of the Openbox theme to use. It is not set by default.
|
The name of the Openbox theme to use. It is not set by default.
|
||||||
|
|
||||||
*<theme><titleLayout>*
|
*<theme><titlebar><layout>*
|
||||||
Selection and order of buttons in a window's titlebar.
|
Selection and order of buttons in a window's titlebar.
|
||||||
The following letters can be used, each only once:
|
The following identifiers can be used, each only once:
|
||||||
- L: window label (aka. title)
|
- 'menu': window menu
|
||||||
- |: empty space (can be used instead of a title)
|
- 'iconify': iconify
|
||||||
- W: window menu
|
- 'max': maximize toggle
|
||||||
- I: iconify
|
- 'close': close
|
||||||
- M: maximize toggle
|
- 'shade': shade toggle
|
||||||
- C: close
|
- 'desk': all-desktops toggle
|
||||||
- S: shade toggle
|
|
||||||
- D: all-desktops toggle
|
|
||||||
|
|
||||||
Example: WLIMC
|
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
|
||||||
|
mandatory to use one colon.
|
||||||
|
|
||||||
|
Default: menu:iconify,max,close
|
||||||
|
|
||||||
|
*<theme><titlebar><showTitle>* [yes|no]
|
||||||
|
Show the window title in the titlebar. Default is yes.
|
||||||
|
|
||||||
*<theme><cornerRadius>*
|
*<theme><cornerRadius>*
|
||||||
The radius of server side decoration top corners. Default is 8.
|
The radius of server side decoration top corners. Default is 8.
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,10 @@
|
||||||
<!-- <font><theme> can be defined without an attribute to set all places -->
|
<!-- <font><theme> can be defined without an attribute to set all places -->
|
||||||
<theme>
|
<theme>
|
||||||
<name></name>
|
<name></name>
|
||||||
<titleLayout>WLIMC</titleLayout>
|
<titlebar>
|
||||||
|
<layout>menu:iconify,max,close</layout>
|
||||||
|
<showTitle>yes</showTitle>
|
||||||
|
</titlebar>
|
||||||
<cornerRadius>8</cornerRadius>
|
<cornerRadius>8</cornerRadius>
|
||||||
<keepBorder>yes</keepBorder>
|
<keepBorder>yes</keepBorder>
|
||||||
<dropShadows>no</dropShadows>
|
<dropShadows>no</dropShadows>
|
||||||
|
|
|
||||||
|
|
@ -119,61 +119,139 @@ parse_window_type(const char *type)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Openbox/labwc comparison
|
||||||
|
*
|
||||||
|
* Instead of openbox's <titleLayout>WLIMC</title> we use
|
||||||
|
*
|
||||||
|
* <titlebar>
|
||||||
|
* <layout>menu:iconfiy,max,close</layout>
|
||||||
|
* <showTitle>yes|no</showTitle>
|
||||||
|
* </titlebar>
|
||||||
|
*
|
||||||
|
* ...using the icon names (like iconify.xbm) without the file extension for the
|
||||||
|
* identifier.
|
||||||
|
*
|
||||||
|
* labwc openbox description
|
||||||
|
* ----- ------- -----------
|
||||||
|
* menu W Open window menu (client-menu)
|
||||||
|
* iconfiy I Iconify (aka minimize)
|
||||||
|
* max M Maximize toggle
|
||||||
|
* close C Close
|
||||||
|
* shade S Shade toggle
|
||||||
|
* desk D All-desktops toggle (aka omnipresent)
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
fill_title_layout(char *nodename, char *content)
|
fill_section(const char *content, struct wl_list *list)
|
||||||
{
|
{
|
||||||
char *c, *c2;
|
gchar **identifiers = g_strsplit(content, ",", -1);
|
||||||
enum ssd_part_type type;
|
for (size_t i = 0; identifiers[i]; ++i) {
|
||||||
struct title_button *item;
|
char *identifier = identifiers[i];
|
||||||
struct wl_list *list = &rc.title_buttons_left;
|
if (string_null_or_empty(identifier)) {
|
||||||
|
|
||||||
for (c = content; *c != '\0'; c++) {
|
|
||||||
for (c2 = content; c2 < c; c2++) {
|
|
||||||
if (*c2 == *c) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (c2 != c) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
enum ssd_part_type type = LAB_SSD_NONE;
|
||||||
switch (*c) {
|
if (!strcmp(identifier, "menu")) {
|
||||||
/* case 'N': icon */
|
|
||||||
case 'L':
|
|
||||||
list = &rc.title_buttons_right;
|
|
||||||
rc.show_title = true;
|
|
||||||
continue;
|
|
||||||
case '|':
|
|
||||||
list = &rc.title_buttons_right;
|
|
||||||
continue;
|
|
||||||
case 'W':
|
|
||||||
type = LAB_SSD_BUTTON_WINDOW_MENU;
|
type = LAB_SSD_BUTTON_WINDOW_MENU;
|
||||||
break;
|
} else if (!strcmp(identifier, "iconify")) {
|
||||||
case 'I':
|
|
||||||
type = LAB_SSD_BUTTON_ICONIFY;
|
type = LAB_SSD_BUTTON_ICONIFY;
|
||||||
break;
|
} else if (!strcmp(identifier, "max")) {
|
||||||
case 'M':
|
|
||||||
type = LAB_SSD_BUTTON_MAXIMIZE;
|
type = LAB_SSD_BUTTON_MAXIMIZE;
|
||||||
break;
|
} else if (!strcmp(identifier, "close")) {
|
||||||
case 'C':
|
|
||||||
type = LAB_SSD_BUTTON_CLOSE;
|
type = LAB_SSD_BUTTON_CLOSE;
|
||||||
break;
|
} else if (!strcmp(identifier, "shade")) {
|
||||||
case 'S':
|
|
||||||
type = LAB_SSD_BUTTON_SHADE;
|
type = LAB_SSD_BUTTON_SHADE;
|
||||||
break;
|
} else if (!strcmp(identifier, "desk")) {
|
||||||
case 'D':
|
|
||||||
type = LAB_SSD_BUTTON_OMNIPRESENT;
|
type = LAB_SSD_BUTTON_OMNIPRESENT;
|
||||||
break;
|
} else {
|
||||||
default:
|
wlr_log(WLR_ERROR, "invalid titleLayout identifier '%s'",
|
||||||
|
identifier);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
item = znew(*item);
|
assert(type != LAB_SSD_NONE);
|
||||||
|
|
||||||
|
struct title_button *item = znew(*item);
|
||||||
item->type = type;
|
item->type = type;
|
||||||
wl_list_append(list, &item->link);
|
wl_list_append(list, &item->link);
|
||||||
}
|
}
|
||||||
|
g_strfreev(identifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
compare_strings(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
char * const *str1 = a;
|
||||||
|
char * const *str2 = b;
|
||||||
|
return strcmp(*str1, *str2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
contains_duplicates(char *content)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The string typically looks like: 'menu:iconfiy,max,close' so we have
|
||||||
|
* to split on both ':' and ','.
|
||||||
|
*/
|
||||||
|
gchar **idents = g_strsplit_set(content, ",:", -1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We've got to have at least two for duplicates to exist. Bailing out
|
||||||
|
* early here also enables the below algorithm which just iterates and
|
||||||
|
* checks if previous item is the same.
|
||||||
|
*/
|
||||||
|
if (g_strv_length(idents) <= 1) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(idents, g_strv_length(idents), sizeof(gchar *), compare_strings);
|
||||||
|
for (size_t i = 1; idents[i]; ++i) {
|
||||||
|
if (string_null_or_empty(idents[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!strcmp(idents[i], idents[i-1])) {
|
||||||
|
ret = true;
|
||||||
|
wlr_log(WLR_ERROR,
|
||||||
|
"titleLayout identifier '%s' is a duplicate",
|
||||||
|
idents[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
g_strfreev(idents);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fill_title_layout(char *content)
|
||||||
|
{
|
||||||
|
if (contains_duplicates(content)) {
|
||||||
|
wlr_log(WLR_ERROR, "titleLayout contains duplicates");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wl_list *sections[] = {
|
||||||
|
&rc.title_buttons_left,
|
||||||
|
&rc.title_buttons_right,
|
||||||
|
};
|
||||||
|
|
||||||
|
gchar **parts = g_strsplit(content, ":", -1);
|
||||||
|
|
||||||
|
if (g_strv_length(parts) != 2) {
|
||||||
|
wlr_log(WLR_ERROR, "<titlebar><layout> must contain one colon");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; parts[i]; ++i) {
|
||||||
|
fill_section(parts[i], sections[i]);
|
||||||
|
}
|
||||||
|
|
||||||
rc.title_layout_loaded = true;
|
rc.title_layout_loaded = true;
|
||||||
|
err:
|
||||||
|
g_strfreev(parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -989,8 +1067,10 @@ entry(xmlNode *node, char *nodename, char *content)
|
||||||
rc.placement_cascade_offset_y = atoi(content);
|
rc.placement_cascade_offset_y = atoi(content);
|
||||||
} else if (!strcmp(nodename, "name.theme")) {
|
} else if (!strcmp(nodename, "name.theme")) {
|
||||||
rc.theme_name = xstrdup(content);
|
rc.theme_name = xstrdup(content);
|
||||||
} else if (!strcmp(nodename, "titlelayout.theme")) {
|
} else if (!strcasecmp(nodename, "layout.titlebar.theme")) {
|
||||||
fill_title_layout(nodename, content);
|
fill_title_layout(content);
|
||||||
|
} else if (!strcasecmp(nodename, "showTitle.titlebar.theme")) {
|
||||||
|
rc.show_title = parse_bool(content, true);
|
||||||
} else if (!strcmp(nodename, "cornerradius.theme")) {
|
} else if (!strcmp(nodename, "cornerradius.theme")) {
|
||||||
rc.corner_radius = atoi(content);
|
rc.corner_radius = atoi(content);
|
||||||
} else if (!strcasecmp(nodename, "keepBorder.theme")) {
|
} else if (!strcasecmp(nodename, "keepBorder.theme")) {
|
||||||
|
|
@ -1578,7 +1658,7 @@ post_processing(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rc.title_layout_loaded) {
|
if (!rc.title_layout_loaded) {
|
||||||
fill_title_layout("titlelayout.theme", "WLIMC");
|
fill_title_layout("menu:iconify,max,close");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue