mirror of
https://github.com/labwc/labwc.git
synced 2026-04-13 08:21:15 -04:00
Window switch, add custom field, with printf style config
based on work by Consolatis. I added documentation, examples and repackaged.
This commit is contained in:
parent
11b6836a38
commit
6311b3ac6a
5 changed files with 202 additions and 45 deletions
|
|
@ -224,6 +224,9 @@ this is for compatibility with Openbox.
|
||||||
|
|
||||||
- *output* Show output id, if more than one output detected
|
- *output* Show output id, if more than one output detected
|
||||||
|
|
||||||
|
- *custom* This field will replace any/all of the above.
|
||||||
|
It uses a printf style for it's formatting.
|
||||||
|
|
||||||
*width* defines the width of the field expressed as a percentage of
|
*width* defines the width of the field expressed as a percentage of
|
||||||
the overall window switcher width. The "%" character is required.
|
the overall window switcher width. The "%" character is required.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,30 @@
|
||||||
<field content="output" width="9%" />
|
<field content="output" width="9%" />
|
||||||
<field content="identifier" width="30%" />
|
<field content="identifier" width="30%" />
|
||||||
<field content="title" width="50%" />
|
<field content="title" width="50%" />
|
||||||
</fields>
|
</fields>
|
||||||
</windowSwitcher>
|
</windowSwitcher>
|
||||||
|
|
||||||
|
A new custom field has been added that will effectively replace the above.
|
||||||
|
It's used like this.
|
||||||
|
|
||||||
|
<windowSwitcher show="yes" preview="no" outlines="no" allWorkspaces="yes">
|
||||||
|
<fields>
|
||||||
|
<field content="custom" format="%b %3s %-10o %-20W %-10i %t" width="100%" />
|
||||||
|
</fields>
|
||||||
|
</windowSwitcher>
|
||||||
|
|
||||||
|
Note: you can embed text into the string, or rearrange the order of elements
|
||||||
|
or leave them out completely. Recommend using a monospace font for the osd
|
||||||
|
Printf style formatting, including spacing and justification.
|
||||||
|
Fields are:
|
||||||
|
%B -> type (backend)
|
||||||
|
%b -> type_short (backend)
|
||||||
|
%I -> identifier
|
||||||
|
%i -> trimmed_identifier
|
||||||
|
%s -> state
|
||||||
|
%o -> output
|
||||||
|
%W -> workspace
|
||||||
|
%t -> title
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!-- edge strength is in pixels -->
|
<!-- edge strength is in pixels -->
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,9 @@ enum window_switcher_field_content {
|
||||||
LAB_FIELD_WIN_STATE,
|
LAB_FIELD_WIN_STATE,
|
||||||
LAB_FIELD_TYPE_SHORT,
|
LAB_FIELD_TYPE_SHORT,
|
||||||
LAB_FIELD_OUTPUT,
|
LAB_FIELD_OUTPUT,
|
||||||
|
LAB_FIELD_CUSTOM,
|
||||||
|
|
||||||
|
LAB_FIELD_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
enum view_placement_policy {
|
enum view_placement_policy {
|
||||||
|
|
@ -56,6 +59,7 @@ struct usable_area_override {
|
||||||
struct window_switcher_field {
|
struct window_switcher_field {
|
||||||
enum window_switcher_field_content content;
|
enum window_switcher_field_content content;
|
||||||
int width;
|
int width;
|
||||||
|
char *format;
|
||||||
struct wl_list link; /* struct rcxml.window_switcher.fields */
|
struct wl_list link; /* struct rcxml.window_switcher.fields */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -216,9 +216,13 @@ fill_window_switcher_field(char *nodename, char *content)
|
||||||
current_field->content = LAB_FIELD_TYPE_SHORT;
|
current_field->content = LAB_FIELD_TYPE_SHORT;
|
||||||
} else if (!strcmp(content, "output")) {
|
} else if (!strcmp(content, "output")) {
|
||||||
current_field->content = LAB_FIELD_OUTPUT;
|
current_field->content = LAB_FIELD_OUTPUT;
|
||||||
|
} else if (!strcmp(content, "custom")) {
|
||||||
|
current_field->content = LAB_FIELD_CUSTOM;
|
||||||
} else {
|
} else {
|
||||||
wlr_log(WLR_ERROR, "bad windowSwitcher field '%s'", content);
|
wlr_log(WLR_ERROR, "bad windowSwitcher field '%s'", content);
|
||||||
}
|
}
|
||||||
|
} else if (!strcmp(nodename, "format")) {
|
||||||
|
current_field->format = xstrdup(content);
|
||||||
} else if (!strcmp(nodename, "width") && !strchr(content, '%')) {
|
} else if (!strcmp(nodename, "width") && !strchr(content, '%')) {
|
||||||
wlr_log(WLR_ERROR, "Removing invalid field, %s='%s' misses"
|
wlr_log(WLR_ERROR, "Removing invalid field, %s='%s' misses"
|
||||||
" trailing %%", nodename, content);
|
" trailing %%", nodename, content);
|
||||||
|
|
@ -1635,6 +1639,7 @@ rcxml_finish(void)
|
||||||
struct window_switcher_field *field, *field_tmp;
|
struct window_switcher_field *field, *field_tmp;
|
||||||
wl_list_for_each_safe(field, field_tmp, &rc.window_switcher.fields, link) {
|
wl_list_for_each_safe(field, field_tmp, &rc.window_switcher.fields, link) {
|
||||||
wl_list_remove(&field->link);
|
wl_list_remove(&field->link);
|
||||||
|
zfree(field->format);
|
||||||
zfree(field);
|
zfree(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
211
src/osd.c
211
src/osd.c
|
|
@ -11,6 +11,7 @@
|
||||||
#include "common/buf.h"
|
#include "common/buf.h"
|
||||||
#include "common/font.h"
|
#include "common/font.h"
|
||||||
#include "common/graphic-helpers.h"
|
#include "common/graphic-helpers.h"
|
||||||
|
#include "common/mem.h"
|
||||||
#include "common/scene-helpers.h"
|
#include "common/scene-helpers.h"
|
||||||
#include "config/rcxml.h"
|
#include "config/rcxml.h"
|
||||||
#include "labwc.h"
|
#include "labwc.h"
|
||||||
|
|
@ -282,6 +283,169 @@ get_title_if_different(struct view *view)
|
||||||
return (!title || !strcmp(identifier, title)) ? NULL : title;
|
return (!title || !strcmp(identifier, title)) ? NULL : title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef void field_set_fn_t(struct buf *buf, struct view *view, const char *format);
|
||||||
|
|
||||||
|
static void
|
||||||
|
field_set_type(struct buf *buf, struct view *view, const char *format)
|
||||||
|
{
|
||||||
|
buf_add(buf, get_type(view));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
field_set_type_short(struct buf *buf, struct view *view, const char *format)
|
||||||
|
{
|
||||||
|
buf_add(buf, get_type_short(view));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
field_set_workspace(struct buf *buf, struct view *view, const char *format)
|
||||||
|
{
|
||||||
|
buf_add(buf, view->workspace->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
field_set_win_state(struct buf *buf, struct view *view, const char *format)
|
||||||
|
{
|
||||||
|
if (view->maximized) {
|
||||||
|
buf_add(buf, "M");
|
||||||
|
} else if (view->minimized) {
|
||||||
|
buf_add(buf, "m");
|
||||||
|
} else if (view->fullscreen) {
|
||||||
|
buf_add(buf, "F");
|
||||||
|
} else {
|
||||||
|
buf_add(buf, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
field_set_output(struct buf *buf, struct view *view, const char *format)
|
||||||
|
{
|
||||||
|
if (wl_list_length(&view->server->outputs) > 1 &&
|
||||||
|
output_is_usable(view->output)) {
|
||||||
|
buf_add(buf, view->output->wlr_output->name);
|
||||||
|
} else {
|
||||||
|
buf_add(buf, " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
field_set_identifier(struct buf *buf, struct view *view, const char *format)
|
||||||
|
{
|
||||||
|
buf_add(buf, get_app_id(view));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
field_set_identifier_trimmed(struct buf *buf, struct view *view, const char *format)
|
||||||
|
{
|
||||||
|
char *s = (char *)get_app_id(view);
|
||||||
|
buf_add(buf, get_trimmed_app_id(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
field_set_title(struct buf *buf, struct view *view, const char *format)
|
||||||
|
{
|
||||||
|
buf_add(buf, get_title_if_different(view));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* forward declare */
|
||||||
|
static field_set_fn_t * const field_handlers[];
|
||||||
|
|
||||||
|
static void
|
||||||
|
field_set_custom(struct buf *buf, struct view *view, const char *format)
|
||||||
|
{
|
||||||
|
if (!format) {
|
||||||
|
wlr_log(WLR_ERROR, "Missing format for custom window switcher field");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME: completely random, add check in the string formatting branch */
|
||||||
|
char fmt[20];
|
||||||
|
unsigned char fmt_len = 0;
|
||||||
|
|
||||||
|
struct buf field_result;
|
||||||
|
buf_init(&field_result);
|
||||||
|
|
||||||
|
/* FIXME: similarly random */
|
||||||
|
char field_formatted[4096];
|
||||||
|
|
||||||
|
for (const char *p = format; *p; p++) {
|
||||||
|
if (!fmt_len) {
|
||||||
|
if (*p == '%') {
|
||||||
|
fmt[fmt_len++] = *p;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Just relay anything not part of a
|
||||||
|
* format string to the output buffer.
|
||||||
|
*/
|
||||||
|
buf_add_char(buf, *p);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
enum window_switcher_field_content field = LAB_FIELD_NONE;
|
||||||
|
|
||||||
|
/* Allow string formatting */
|
||||||
|
/* TODO: add . for manual truncating? */
|
||||||
|
if (*p == '-' || *p == '#' || (*p >= '0' && *p <= '9')) {
|
||||||
|
fmt[fmt_len++] = *p;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handlers */
|
||||||
|
if (*p == 'B') {
|
||||||
|
field = LAB_FIELD_TYPE;
|
||||||
|
} else if (*p == 'b') {
|
||||||
|
field = LAB_FIELD_TYPE_SHORT;
|
||||||
|
} else if (*p == 'W') {
|
||||||
|
field = LAB_FIELD_WORKSPACE;
|
||||||
|
} else if (*p == 's') {
|
||||||
|
field = LAB_FIELD_WIN_STATE;
|
||||||
|
} else if (*p == 'o') {
|
||||||
|
field = LAB_FIELD_OUTPUT;
|
||||||
|
} else if (*p == 'I') {
|
||||||
|
field = LAB_FIELD_IDENTIFIER;
|
||||||
|
} else if (*p == 'i') {
|
||||||
|
field = LAB_FIELD_TRIMMED_IDENTIFIER;
|
||||||
|
} else if (*p == 't') {
|
||||||
|
field = LAB_FIELD_TITLE;
|
||||||
|
} else {
|
||||||
|
wlr_log(WLR_ERROR,
|
||||||
|
"invalid format character found for osd %s: '%c'",
|
||||||
|
format, *p);
|
||||||
|
goto reset_format;
|
||||||
|
}
|
||||||
|
fmt[fmt_len++] = 's';
|
||||||
|
fmt[fmt_len++] = '\0';
|
||||||
|
|
||||||
|
/* Generate the actual content*/
|
||||||
|
assert(field < LAB_FIELD_COUNT && field_handlers[field]);
|
||||||
|
field_handlers[field](&field_result, view, NULL);
|
||||||
|
|
||||||
|
/* Throw it at snprintf to allow formatting / padding */
|
||||||
|
snprintf(field_formatted, sizeof(field_formatted), fmt, field_result.buf);
|
||||||
|
|
||||||
|
/* And finally write it to the output buffer */
|
||||||
|
buf_add(buf, field_formatted);
|
||||||
|
|
||||||
|
reset_format:
|
||||||
|
/* Reset format string and tmp field result buffer */
|
||||||
|
fmt_len = 0;
|
||||||
|
field_result.len = 0;
|
||||||
|
}
|
||||||
|
free(field_result.buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static field_set_fn_t * const field_handlers[] = {
|
||||||
|
[LAB_FIELD_TYPE] = field_set_type,
|
||||||
|
[LAB_FIELD_TYPE_SHORT] = field_set_type_short,
|
||||||
|
[LAB_FIELD_WORKSPACE] = field_set_workspace,
|
||||||
|
[LAB_FIELD_WIN_STATE] = field_set_win_state,
|
||||||
|
[LAB_FIELD_OUTPUT] = field_set_output,
|
||||||
|
[LAB_FIELD_IDENTIFIER] = field_set_identifier,
|
||||||
|
[LAB_FIELD_TRIMMED_IDENTIFIER] = field_set_identifier_trimmed,
|
||||||
|
[LAB_FIELD_TITLE] = field_set_title,
|
||||||
|
[LAB_FIELD_CUSTOM] = field_set_custom,
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
render_osd(struct server *server, cairo_t *cairo, int w, int h,
|
render_osd(struct server *server, cairo_t *cairo, int w, int h,
|
||||||
bool show_workspace, const char *workspace_name,
|
bool show_workspace, const char *workspace_name,
|
||||||
|
|
@ -374,50 +538,9 @@ render_osd(struct server *server, cairo_t *cairo, int w, int h,
|
||||||
+ theme->osd_window_switcher_item_padding_y
|
+ theme->osd_window_switcher_item_padding_y
|
||||||
+ theme->osd_window_switcher_item_active_border_width);
|
+ theme->osd_window_switcher_item_active_border_width);
|
||||||
|
|
||||||
switch (field->content) {
|
assert(field->content < LAB_FIELD_COUNT && field_handlers[field->content]);
|
||||||
case LAB_FIELD_TYPE:
|
field_handlers[field->content](&buf, *view, field->format);
|
||||||
buf_add(&buf, get_type(*view));
|
|
||||||
break;
|
|
||||||
case LAB_FIELD_TYPE_SHORT:
|
|
||||||
buf_add(&buf, get_type_short(*view));
|
|
||||||
break;
|
|
||||||
case LAB_FIELD_WORKSPACE:
|
|
||||||
buf_add(&buf, (*view)->workspace->name);
|
|
||||||
break;
|
|
||||||
case LAB_FIELD_WIN_STATE:
|
|
||||||
if ((*view)->maximized) {
|
|
||||||
buf_add(&buf, "M");
|
|
||||||
} else if ((*view)->minimized) {
|
|
||||||
buf_add(&buf, "m");
|
|
||||||
} else if ((*view)->fullscreen) {
|
|
||||||
buf_add(&buf, "F");
|
|
||||||
} else {
|
|
||||||
buf_add(&buf, " ");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LAB_FIELD_OUTPUT:
|
|
||||||
if (wl_list_length(&server->outputs) > 1 &&
|
|
||||||
output_is_usable((*view)->output)) {
|
|
||||||
buf_add(&buf, (*view)->output->wlr_output->name);
|
|
||||||
} else {
|
|
||||||
buf_add(&buf, " ");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case LAB_FIELD_IDENTIFIER:
|
|
||||||
buf_add(&buf, get_app_id(*view));
|
|
||||||
break;
|
|
||||||
case LAB_FIELD_TRIMMED_IDENTIFIER:
|
|
||||||
{
|
|
||||||
char *s = (char *)get_app_id(*view);
|
|
||||||
buf_add(&buf, get_trimmed_app_id(s));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LAB_FIELD_TITLE:
|
|
||||||
buf_add(&buf, get_title_if_different(*view));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
int field_width = (available_width - (nr_fields + 1)
|
int field_width = (available_width - (nr_fields + 1)
|
||||||
* theme->osd_window_switcher_item_padding_x)
|
* theme->osd_window_switcher_item_padding_x)
|
||||||
* field->width / 100.0;
|
* field->width / 100.0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue