]> git.mdlowis.com Git - proto/labwc.git/commitdiff
config: support window switcher field definitions
authorJohan Malm <jgm323@gmail.com>
Wed, 19 Apr 2023 13:44:41 +0000 (14:44 +0100)
committerJohan Malm <johanmalm@users.noreply.github.com>
Fri, 21 Apr 2023 15:05:48 +0000 (16:05 +0100)
<windowSwitcher>
  <fields>
    <field content="type" width="25%" />
    <field content="app_id" width="25%" />
    <field content="title" width="50%" />
  </fields>
</windowSwitcher>

Relates to issues #852 #855 #879

docs/labwc-config.5.scd
docs/rc.xml.all
include/config/rcxml.h
src/config/rcxml.c
src/osd.c

index a3b4b30cbf44bfe7d4a5202194958f069da6fd2a..14f680387c19cef43e5bd382a3196c8fd6f85468 100644 (file)
@@ -89,6 +89,20 @@ The rest of this man page describes configuration options.
        *outlines* [yes|no] Draw an outline around the selected window when
        switching between windows. Default is yes.
 
+*<windowSwitcher><fields><field content="" width="%">*
+       Define window switcher fields.
+
+       *content* defines what the field shows and can be any of:
+
+               - *type* Show view type ("xdg-shell" or "xwayland")
+
+               - *app_id* Show app_id (class for XWayland)
+
+               - *title* Show window title if different to app_id
+
+       *width* defines the width of the field expressed as a percentage of
+       the overall window switcher width. The "%" character is required.
+
 ## RESISTANCE
 
 *<resistance><screenEdgeStrength>*
index 9a04ede9686d118235bf8228ac845b27b2cb31c7..648bb5f34a1c508c0c726db95a803e32bb7e3bfb 100644 (file)
     </font>
   </theme>
 
-  <windowSwitcher show="yes" preview="yes" outlines="yes" />
+  <windowSwitcher show="yes" preview="yes" outlines="yes">
+    <fields>
+      <field content="type" width="25%" />
+      <field content="app_id" width="25%" />
+      <field content="title" width="50%" />
+    </fields>
+  </windowSwitcher>
 
   <!-- edge strength is in pixels -->
   <resistance>
index 18f79ea247c5377dde4d660c7aab86c8e22fedf9..cdc01df835e95dadce12b0c6ea629520ac3b7219 100644 (file)
 #include "config/libinput.h"
 #include "theme.h"
 
+enum window_switcher_field_content {
+       LAB_FIELD_NONE = 0,
+       LAB_FIELD_TYPE,
+       LAB_FIELD_APP_ID,
+       LAB_FIELD_TITLE,
+};
+
+struct window_switcher_field {
+       enum window_switcher_field_content content;
+       int width;
+       struct wl_list link; /* struct rcxml.window_switcher.fields */
+};
+
 struct rcxml {
        char *config_dir;
 
@@ -65,6 +78,10 @@ struct rcxml {
 
        /* Regions */
        struct wl_list regions;  /* struct region.link */
+
+       struct {
+               struct wl_list fields;  /* struct window_switcher_field.link */
+       } window_switcher;
 };
 
 extern struct rcxml rc;
index 82f7f1e2c864123a3dfd1e3f73be0f5090532cdd..564943283029009760ad39dd9c54d3c1b6d2309b 100644 (file)
@@ -31,6 +31,8 @@ static bool in_regions;
 static bool in_keybind;
 static bool in_mousebind;
 static bool in_libinput_category;
+static bool in_window_switcher_field;
+
 static struct keybind *current_keybind;
 static struct mousebind *current_mousebind;
 static struct libinput_category *current_libinput_category;
@@ -38,6 +40,7 @@ static const char *current_mouse_context;
 static struct action *current_keybind_action;
 static struct action *current_mousebind_action;
 static struct region *current_region;
+static struct window_switcher_field *current_field;
 
 enum font_place {
        FONT_PLACE_NONE = 0,
@@ -51,6 +54,43 @@ enum font_place {
 static void load_default_key_bindings(void);
 static void load_default_mouse_bindings(void);
 
+static void
+fill_window_switcher_field(char *nodename, char *content)
+{
+       if (!strcasecmp(nodename, "field.fields.windowswitcher")) {
+               current_field = znew(*current_field);
+               wl_list_append(&rc.window_switcher.fields, &current_field->link);
+               return;
+       }
+
+       string_truncate_at_pattern(nodename, ".field.fields.windowswitcher");
+       if (!content) {
+               /* intentionally left empty */
+       } else if (!current_field) {
+               wlr_log(WLR_ERROR, "no <field>");
+       } else if (!strcmp(nodename, "content")) {
+               if (!strcmp(content, "type")) {
+                       current_field->content = LAB_FIELD_TYPE;
+               } else if (!strcmp(content, "app_id")) {
+                       current_field->content = LAB_FIELD_APP_ID;
+               } else if (!strcmp(content, "title")) {
+                       current_field->content = LAB_FIELD_TITLE;
+               } else {
+                       wlr_log(WLR_ERROR, "bad windowSwitcher field '%s'", content);
+               }
+       } else if (!strcmp(nodename, "width") && !strchr(content, '%')) {
+               wlr_log(WLR_ERROR, "Removing invalid field, %s='%s' misses"
+                       " trailing %%", nodename, content);
+               wl_list_remove(&current_field->link);
+               zfree(current_field);
+       } else if (!strcmp(nodename, "width")) {
+               current_field->width = atoi(content);
+       } else {
+               wlr_log(WLR_ERROR, "Unexpected data in field parser: %s=\"%s\"",
+                       nodename, content);
+       }
+}
+
 static void
 fill_region(char *nodename, char *content)
 {
@@ -362,6 +402,10 @@ entry(xmlNode *node, char *nodename, char *content)
                fill_region(nodename, content);
                return;
        }
+       if (in_window_switcher_field) {
+               fill_window_switcher_field(nodename, content);
+               return;
+       }
 
        /* handle nodes without content, e.g. <keyboard><default /> */
        if (!strcmp(nodename, "default.keyboard")) {
@@ -448,6 +492,14 @@ entry(xmlNode *node, char *nodename, char *content)
        } else if (strstr(nodename, "windowswitcher.core")) {
                wlr_log(WLR_ERROR, "<windowSwitcher> should not be child of <core>");
 
+       /* The following three are for backward compatibility only */
+       } else if (!strcasecmp(nodename, "show.windowSwitcher.core")) {
+               rc.cycle_view_osd = get_bool(content);
+       } else if (!strcasecmp(nodename, "preview.windowSwitcher.core")) {
+               rc.cycle_preview_contents = get_bool(content);
+       } else if (!strcasecmp(nodename, "outlines.windowSwitcher.core")) {
+               rc.cycle_preview_outlines = get_bool(content);
+
        /* The following three are for backward compatibility only */
        } else if (!strcasecmp(nodename, "cycleViewOSD.core")) {
                rc.cycle_view_osd = get_bool(content);
@@ -531,6 +583,12 @@ xml_tree_walk(xmlNode *node)
                        in_regions = false;
                        continue;
                }
+               if (!strcasecmp((char *)n->name, "fields")) {
+                       in_window_switcher_field = true;
+                       traverse(n);
+                       in_window_switcher_field = false;
+                       continue;
+               }
                traverse(n);
        }
 }
@@ -568,6 +626,7 @@ rcxml_init(void)
                wl_list_init(&rc.libinput_categories);
                wl_list_init(&rc.workspace_config.workspaces);
                wl_list_init(&rc.regions);
+               wl_list_init(&rc.window_switcher.fields);
        }
        has_run = true;
 
@@ -784,6 +843,29 @@ deduplicate_key_bindings(void)
        }
 }
 
+static struct {
+       enum window_switcher_field_content content;
+       int width;
+} fields[] = {
+       { LAB_FIELD_TYPE, 25 },
+       { LAB_FIELD_APP_ID, 25 },
+       { LAB_FIELD_TITLE, 50 },
+       { LAB_FIELD_NONE, 0 },
+};
+
+static void
+load_default_window_switcher_fields(void)
+{
+       struct window_switcher_field *field;
+
+       for (int i = 0; fields[i].content != LAB_FIELD_NONE; i++) {
+               field = znew(*field);
+               field->content = fields[i].content;
+               field->width = fields[i].width;
+               wl_list_append(&rc.window_switcher.fields, &field->link);
+       }
+}
+
 static void
 post_processing(void)
 {
@@ -846,6 +928,11 @@ post_processing(void)
                        free(region);
                }
        }
+
+       if (!wl_list_length(&rc.window_switcher.fields)) {
+               wlr_log(WLR_INFO, "load default window switcher fields");
+               load_default_window_switcher_fields();
+       }
 }
 
 static void
@@ -953,6 +1040,12 @@ rcxml_finish(void)
 
        regions_destroy(NULL, &rc.regions);
 
+       struct window_switcher_field *field, *field_tmp;
+       wl_list_for_each_safe(field, field_tmp, &rc.window_switcher.fields, link) {
+               wl_list_remove(&field->link);
+               zfree(field);
+       }
+
        /* Reset state vars for starting fresh when Reload is triggered */
        current_keybind = NULL;
        current_mousebind = NULL;
@@ -961,4 +1054,5 @@ rcxml_finish(void)
        current_keybind_action = NULL;
        current_mousebind_action = NULL;
        current_region = NULL;
+       current_field = NULL;
 }
index 8c2ee64ebf30dce3e389203d58397f61c4fc528b..d2f5a56774b25e97200aa8911577201018173722 100644 (file)
--- a/src/osd.c
+++ b/src/osd.c
@@ -21,8 +21,6 @@
 #define OSD_ITEM_WIDTH (600)
 #define OSD_ITEM_PADDING (10)
 #define OSD_BORDER_WIDTH (6)
-#define OSD_TAB1 (120)
-#define OSD_TAB2 (300)
 
 /* is title different from app_id/class? */
 static int
@@ -243,11 +241,52 @@ preview_cycled_view(struct view *view)
        wlr_scene_node_raise_to_top(osd_state->preview_node);
 }
 
+static const char *
+get_type(struct view *view)
+{
+       switch (view->type) {
+       case LAB_XDG_SHELL_VIEW:
+               return "[xdg-shell]";
+#if HAVE_XWAYLAND
+       case LAB_XWAYLAND_VIEW:
+               return "[xwayland]";
+#endif
+       }
+       return "";
+}
+
+static const char *
+get_app_id(struct view *view)
+{
+       switch (view->type) {
+       case LAB_XDG_SHELL_VIEW:
+               return get_formatted_app_id(view);
+#if HAVE_XWAYLAND
+       case LAB_XWAYLAND_VIEW:
+               return view_get_string_prop(view, "class");
+#endif
+       }
+       return "";
+}
+
+static const char *
+get_title(struct view *view)
+{
+       if (is_title_different(view)) {
+               return view_get_string_prop(view, "title");
+       } else {
+               return "";
+       }
+}
+
 static void
-render_osd(cairo_t *cairo, int w, int h, struct wl_list *node_list,
-               struct view *cycle_view, struct theme *theme, bool show_workspace,
+render_osd(struct server *server, cairo_t *cairo, int w, int h,
+               struct wl_list *node_list, bool show_workspace,
                const char *workspace_name)
 {
+       struct view *cycle_view = server->osd_state.cycle_view;
+       struct theme *theme = server->theme;
+
        struct wlr_scene_node *node;
        cairo_surface_t *surf = cairo_get_target(cairo);
 
@@ -270,11 +309,6 @@ render_osd(cairo_t *cairo, int w, int h, struct wl_list *node_list,
        PangoFontDescription *desc = font_to_pango_desc(&rc.font_osd);
        pango_layout_set_font_description(layout, desc);
 
-       PangoTabArray *tabs = pango_tab_array_new_with_positions(2, TRUE,
-               PANGO_TAB_LEFT, OSD_TAB1, PANGO_TAB_LEFT, OSD_TAB2);
-       pango_layout_set_tabs(layout, tabs);
-       pango_tab_array_free(tabs);
-
        pango_cairo_update_layout(cairo, layout);
 
        int y = OSD_BORDER_WIDTH;
@@ -313,31 +347,31 @@ render_osd(cairo_t *cairo, int w, int h, struct wl_list *node_list,
                if (!isfocusable(view)) {
                        continue;
                }
-               buf.len = 0;
-               cairo_move_to(cairo, OSD_BORDER_WIDTH + OSD_ITEM_PADDING, y);
-
-               switch (view->type) {
-               case LAB_XDG_SHELL_VIEW:
-                       buf_add(&buf, "[xdg-shell]\t");
-                       buf_add(&buf, get_formatted_app_id(view));
-                       buf_add(&buf, "\t");
-                       break;
-#if HAVE_XWAYLAND
-               case LAB_XWAYLAND_VIEW:
-                       buf_add(&buf, "[xwayland]\t");
-                       buf_add(&buf, view_get_string_prop(view, "class"));
-                       buf_add(&buf, "\t");
-                       break;
-#endif
-               }
 
-               if (is_title_different(view)) {
-                       buf_add(&buf, view_get_string_prop(view, "title"));
+               int x = OSD_BORDER_WIDTH + OSD_ITEM_PADDING;
+               struct window_switcher_field *field;
+               wl_list_for_each(field, &rc.window_switcher.fields, link) {
+                       buf.len = 0;
+                       cairo_move_to(cairo, x, y);
+
+                       switch (field->content) {
+                       case LAB_FIELD_TYPE:
+                               buf_add(&buf, get_type(view));
+                               break;
+                       case LAB_FIELD_APP_ID:
+                               buf_add(&buf, get_app_id(view));
+                               break;
+                       case LAB_FIELD_TITLE:
+                               buf_add(&buf, get_title(view));
+                               break;
+                       default:
+                               break;
+                       }
+                       pango_layout_set_text(layout, buf.buf, -1);
+                       pango_cairo_show_layout(cairo, layout);
+                       x += field->width / 100.0 * OSD_ITEM_WIDTH;
                }
 
-               pango_layout_set_text(layout, buf.buf, -1);
-               pango_cairo_show_layout(cairo, layout);
-
                if (view == cycle_view) {
                        /* Highlight current window */
                        cairo_rectangle(cairo, OSD_BORDER_WIDTH, y - y_offset,
@@ -378,8 +412,7 @@ display_osd(struct output *output)
 
        /* Render OSD image */
        cairo_t *cairo = output->osd_buffer->cairo;
-       render_osd(cairo, w, h, node_list, server->osd_state.cycle_view,
-               server->theme, show_workspace, workspace_name);
+       render_osd(server, cairo, w, h, node_list, show_workspace, workspace_name);
 
        struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_create(
                output->osd_tree, &output->osd_buffer->base);