view: add view_array_append()

...to reduce code duplication.

The function populates an array with views which meet any set of critera
from:

  - current-workspace
  - no-always-on-top
  - no-skipWindowSwitcher (window-rule)

Make src/osd.c use this new interface. Note that always-on-top views are
still filtered out from the window-switcher and that desktop_cycle_view()
needs to be re-worked before always-on-top views can be opted in.
This commit is contained in:
Johan Malm 2023-08-10 15:46:00 +01:00 committed by Johan Malm
parent 58b33fb0c9
commit 57b9efeb45
4 changed files with 103 additions and 35 deletions

View file

@ -168,6 +168,36 @@ struct xdg_toplevel_view {
struct wl_listener new_popup; struct wl_listener new_popup;
}; };
enum lab_view_criteria {
LAB_VIEW_CRITERIA_ALL = 0,
LAB_VIEW_CRITERIA_CURRENT_WORKSPACE = 1 << 0,
LAB_VIEW_CRITERIA_NO_ALWAYS_ON_TOP = 1 << 1,
LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER = 1 << 2,
};
/**
* view_array_append - append views that match criteria to array
* @server: server context
* @views: arrays to append to
* @criteria: criteria to match against
*
* Note: This array has a very short shelf-life so it is intended to be used
* with a single-use-throw-away approach.
*
* Example usage:
*
* struct view **view;
* struct wl_array views;
* wl_array_init(&views);
* view_array_append(server, &views, LAB_VIEW_CRITERIA_CURRENT_WORKSPACE);
* wl_array_for_each(view, &views) {
* // Do something with *view
* }
* wl_array_release(&views);
*/
void view_array_append(struct server *server, struct wl_array *views,
enum lab_view_criteria criteria);
bool view_inhibits_keybinds(struct view *view); bool view_inhibits_keybinds(struct view *view);
void view_toggle_keybinds(struct view *view); void view_toggle_keybinds(struct view *view);

View file

@ -435,3 +435,4 @@ get_cursor_context(struct server *server)
wlr_log(WLR_ERROR, "Unknown node detected"); wlr_log(WLR_ERROR, "Unknown node detected");
return ret; return ret;
} }

View file

@ -258,12 +258,11 @@ get_title(struct view *view)
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,
struct wl_list *node_list, bool show_workspace, struct wl_list *node_list, bool show_workspace,
const char *workspace_name) const char *workspace_name, enum lab_view_criteria criteria)
{ {
struct view *cycle_view = server->osd_state.cycle_view; struct view *cycle_view = server->osd_state.cycle_view;
struct theme *theme = server->theme; struct theme *theme = server->theme;
struct wlr_scene_node *node;
cairo_surface_t *surf = cairo_get_target(cairo); cairo_surface_t *surf = cairo_get_target(cairo);
/* Draw background */ /* Draw background */
@ -317,17 +316,11 @@ render_osd(struct server *server, cairo_t *cairo, int w, int h,
- 2 * theme->osd_window_switcher_item_active_border_width; - 2 * theme->osd_window_switcher_item_active_border_width;
/* Draw text for each node */ /* Draw text for each node */
wl_list_for_each_reverse(node, node_list, link) { struct view **view;
if (!node->data) { struct wl_array views;
/* We found some non-view, most likely the region overlay */ wl_array_init(&views);
continue; desktop_views_append(server, &views, criteria);
} wl_array_for_each(view, &views) {
struct view *view = node_view_from_node(node);
enum property skip = window_rules_get_property(view, "skipWindowSwitcher");
if (!isfocusable(view) || skip == LAB_PROP_TRUE) {
continue;
}
/* /*
* OSD border * OSD border
* +---------------------------------+ * +---------------------------------+
@ -359,13 +352,13 @@ render_osd(struct server *server, cairo_t *cairo, int w, int h,
switch (field->content) { switch (field->content) {
case LAB_FIELD_TYPE: case LAB_FIELD_TYPE:
buf_add(&buf, get_type(view)); buf_add(&buf, get_type(*view));
break; break;
case LAB_FIELD_APP_ID: case LAB_FIELD_APP_ID:
buf_add(&buf, get_app_id(view)); buf_add(&buf, get_app_id(*view));
break; break;
case LAB_FIELD_TITLE: case LAB_FIELD_TITLE:
buf_add(&buf, get_title(view)); buf_add(&buf, get_title(*view));
break; break;
default: default:
break; break;
@ -379,7 +372,7 @@ render_osd(struct server *server, cairo_t *cairo, int w, int h,
x += field_width + theme->osd_window_switcher_item_padding_x; x += field_width + theme->osd_window_switcher_item_padding_x;
} }
if (view == cycle_view) { if (*view == cycle_view) {
/* Highlight current window */ /* Highlight current window */
struct wlr_fbox fbox = { struct wlr_fbox fbox = {
.x = theme->osd_border_width + theme->osd_window_switcher_padding, .x = theme->osd_border_width + theme->osd_window_switcher_padding,
@ -398,30 +391,23 @@ render_osd(struct server *server, cairo_t *cairo, int w, int h,
} }
free(buf.buf); free(buf.buf);
g_object_unref(layout); g_object_unref(layout);
wl_array_release(&views);
cairo_surface_flush(surf); cairo_surface_flush(surf);
} }
static int static int
get_osd_height(struct wl_list *node_list) get_osd_height(struct server *server, enum lab_view_criteria criteria)
{ {
int height = 0; int height = 0;
struct view *view; struct wl_array views;
struct wlr_scene_node *node; wl_array_init(&views);
wl_list_for_each(node, node_list, link) { desktop_views_append(server, &views, criteria);
if (!node->data) {
/* We found some non-view, most likely the region overlay */
continue;
}
view = node_view_from_node(node);
enum property skip = window_rules_get_property(view, "skipWindowSwitcher");
if (!isfocusable(view) || skip == LAB_PROP_TRUE) {
continue;
}
/* Include item border width */ /* Includes item border width */
height += rc.theme->osd_window_switcher_item_height; size_t len = views.size / sizeof(struct view *);
} height += len * rc.theme->osd_window_switcher_item_height;
wl_array_release(&views);
/* Add OSD border width */ /* Add OSD border width */
height += 2 * rc.theme->osd_border_width; height += 2 * rc.theme->osd_border_width;
@ -439,9 +425,16 @@ display_osd(struct output *output)
bool show_workspace = wl_list_length(&rc.workspace_config.workspaces) > 1; bool show_workspace = wl_list_length(&rc.workspace_config.workspaces) > 1;
const char *workspace_name = server->workspace_current->name; const char *workspace_name = server->workspace_current->name;
struct wl_array views;
wl_array_init(&views);
view_array_append(server, &views,
LAB_VIEW_CRITERIA_CURRENT_WORKSPACE
| LAB_VIEW_CRITERIA_NO_ALWAYS_ON_TOP
| LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER);
float scale = output->wlr_output->scale; float scale = output->wlr_output->scale;
int w = theme->osd_window_switcher_width; int w = theme->osd_window_switcher_width;
int h = get_osd_height(node_list); int h = get_osd_height(server, criteria);
if (show_workspace) { if (show_workspace) {
/* workspace indicator */ /* workspace indicator */
h += theme->osd_window_switcher_item_height; h += theme->osd_window_switcher_item_height;
@ -455,7 +448,8 @@ display_osd(struct output *output)
/* Render OSD image */ /* Render OSD image */
cairo_t *cairo = output->osd_buffer->cairo; cairo_t *cairo = output->osd_buffer->cairo;
render_osd(server, cairo, w, h, node_list, show_workspace, workspace_name); render_osd(server, cairo, w, h, node_list, show_workspace,
workspace_name, criteria);
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_create( struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_create(
output->osd_tree, &output->osd_buffer->base); output->osd_tree, &output->osd_buffer->base);

View file

@ -19,6 +19,48 @@
#define LAB_FALLBACK_WIDTH 640 #define LAB_FALLBACK_WIDTH 640
#define LAB_FALLBACK_HEIGHT 480 #define LAB_FALLBACK_HEIGHT 480
void
view_array_append(struct server *server, struct wl_array *views,
enum lab_view_criteria criteria)
{
struct view *view;
wl_list_for_each(view, &server->views, link)
{
if (!isfocusable(view)) {
continue;
}
if (criteria & LAB_VIEW_CRITERIA_CURRENT_WORKSPACE) {
/*
* Always-on-top views are always on the current
* desktop and are special in that they live in a
* different tree.
*/
if (view_is_always_on_top(view)) {
goto next;
}
if (view->scene_tree->node.parent != server->workspace_current->tree) {
continue;
}
}
next:
if (criteria & LAB_VIEW_CRITERIA_NO_ALWAYS_ON_TOP) {
if (view_is_always_on_top(view)) {
continue;
}
}
if (criteria & LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER) {
if (window_rules_get_property(view, "skipWindowSwitcher")
== LAB_PROP_TRUE) {
continue;
}
}
struct view **entry = wl_array_add(views, sizeof(*entry));
*entry = view;
}
}
/** /**
* All view_apply_xxx_geometry() functions must *not* modify * All view_apply_xxx_geometry() functions must *not* modify
* any state besides repositioning or resizing the view. * any state besides repositioning or resizing the view.
@ -1264,3 +1306,4 @@ view_destroy(struct view *view)
cursor_update_focus(server); cursor_update_focus(server);
} }
} }