From 8c5157a0980b2ceb3b6f6d96268c72d90743c8b7 Mon Sep 17 00:00:00 2001 From: Consolatis <35009135+Consolatis@users.noreply.github.com> Date: Wed, 15 Jun 2022 02:02:50 +0200 Subject: [PATCH] workspaces: Wire up workspaces --- src/desktop.c | 98 +++++++++++++++++++++++++++----------------------- src/keyboard.c | 21 +++++++---- src/osd.c | 61 +++++++++++++++++++++++++------ src/server.c | 9 ++++- src/view.c | 5 +-- src/xdg.c | 4 ++- src/xwayland.c | 4 ++- 7 files changed, 134 insertions(+), 68 deletions(-) diff --git a/src/desktop.c b/src/desktop.c index 9e16465e..b19cd4be 100644 --- a/src/desktop.c +++ b/src/desktop.c @@ -6,6 +6,7 @@ #include "node.h" #include "ssd.h" #include "common/scene-helpers.h" +#include "workspaces.h" static void move_to_front(struct view *view) @@ -162,73 +163,80 @@ isfocusable(struct view *view) return (view->mapped || view->minimized); } -static bool -has_focusable_view(struct wl_list *wl_list) +static struct wl_list * +get_prev_item(struct wl_list *item) { - struct view *view; - wl_list_for_each (view, wl_list, link) { - if (isfocusable(view)) { - return true; - } - } - return false; + return item->prev; +} + +static struct wl_list * +get_next_item(struct wl_list *item) +{ + return item->next; } static struct view * first_view(struct server *server) { - struct view *view; - view = wl_container_of(server->views.next, view, link); - return view; + struct wlr_scene_node *node; + struct wl_list *list_head = + &server->workspace_current->tree->children; + wl_list_for_each_reverse(node, list_head, link) { + return node_view_from_node(node); + } + return NULL; } struct view * -desktop_cycle_view(struct server *server, struct view *current, +desktop_cycle_view(struct server *server, struct view *start_view, enum lab_cycle_dir dir) { - if (!has_focusable_view(&server->views)) { + struct view *view = start_view ? start_view : first_view(server); + if (!view) { return NULL; } + start_view = view; + struct wlr_scene_node *node = &view->scene_tree->node; - struct view *view = current ? current : first_view(server); - if (dir == LAB_CYCLE_DIR_FORWARD) { - /* Replacement for wl_list_for_each_from() */ - do { - view = wl_container_of(view->link.next, view, link); - } while (&view->link == &server->views || !isfocusable(view)); - } else if (dir == LAB_CYCLE_DIR_BACKWARD) { - do { - view = wl_container_of(view->link.prev, view, link); - } while (&view->link == &server->views || !isfocusable(view)); - } - return view; -} + assert(node->parent); + struct wl_list *list_head = &node->parent->children; + struct wl_list *list_item = &node->link; + struct wl_list *(*iter)(struct wl_list *); -static bool -has_mapped_view(struct wl_list *wl_list) -{ - struct view *view; - wl_list_for_each (view, wl_list, link) { - if (view->mapped) { - return true; + /* Scene nodes are ordered like last node == displayed topmost */ + iter = dir == LAB_CYCLE_DIR_FORWARD ? get_prev_item : get_next_item; + + do { + list_item = iter(list_item); + if (list_item == list_head) { + /* Start / End of list reached. Roll over */ + list_item = iter(list_item); } - } - return false; + node = wl_container_of(list_item, node, link); + view = node_view_from_node(node); + if (isfocusable(view)) { + return view; + } + } while (view != start_view); + + /* No focusable views found, including the one we started with */ + return NULL; } static struct view * topmost_mapped_view(struct server *server) { - if (!has_mapped_view(&server->views)) { - return NULL; + struct view *view; + struct wl_list *node_list; + struct wlr_scene_node *node; + node_list = &server->workspace_current->tree->children; + wl_list_for_each_reverse(node, node_list, link) { + view = node_view_from_node(node); + if (view->mapped) { + return view; + } } - - /* start from tail of server->views */ - struct view *view = wl_container_of(server->views.prev, view, link); - do { - view = wl_container_of(view->link.next, view, link); - } while (&view->link == &server->views || !view->mapped); - return view; + return NULL; } struct view * diff --git a/src/keyboard.c b/src/keyboard.c index d6049f88..e754d5f6 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -5,6 +5,7 @@ #include "buffer.h" #include "key-state.h" #include "labwc.h" +#include "workspaces.h" static void change_vt(struct server *server, unsigned int vt) @@ -38,17 +39,23 @@ keyboard_modifiers_notify(struct wl_listener *listener, void *data) struct seat *seat = wl_container_of(listener, seat, keyboard_modifiers); struct server *server = seat->server; - if (server->cycle_view) { + if (server->cycle_view || seat->workspace_osd_shown_by_modifier) { struct wlr_keyboard_key_event *event = data; struct wlr_keyboard *keyboard = &seat->keyboard_group->keyboard; + if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED && !keyboard_any_modifiers_pressed(keyboard)) { - /* end cycle */ - desktop_focus_and_activate_view(&server->seat, - server->cycle_view); - desktop_move_to_front(server->cycle_view); - server->cycle_view = NULL; - osd_finish(server); + if (server->cycle_view) { + /* end cycle */ + desktop_focus_and_activate_view(&server->seat, + server->cycle_view); + desktop_move_to_front(server->cycle_view); + server->cycle_view = NULL; + osd_finish(server); + } + if (seat->workspace_osd_shown_by_modifier) { + workspaces_osd_hide(seat); + } } } diff --git a/src/osd.c b/src/osd.c index 38803a16..646feb92 100644 --- a/src/osd.c +++ b/src/osd.c @@ -10,6 +10,8 @@ #include "config/rcxml.h" #include "labwc.h" #include "theme.h" +#include "node.h" +#include "workspaces.h" #define OSD_ITEM_HEIGHT (20) #define OSD_ITEM_WIDTH (600) @@ -78,11 +80,13 @@ get_formatted_app_id(struct view *view) } static int -get_osd_height(struct wl_list *views) +get_osd_height(struct wl_list *node_list) { int height = 0; struct view *view; - wl_list_for_each(view, views, link) { + struct wlr_scene_node *node; + wl_list_for_each(node, node_list, link) { + view = node_view_from_node(node); if (!isfocusable(view)) { continue; } @@ -115,21 +119,32 @@ osd_finish(struct server *server) void osd_update(struct server *server) { - if (wl_list_empty(&server->views)) { + struct wl_list *node_list = + &server->workspace_current->tree->children; + + if (wl_list_empty(node_list)) { osd_finish(server); return; } struct theme *theme = server->theme; + bool show_workspace = wl_list_length(&rc.workspace_config.workspaces) > 1; struct buf buf; buf_init(&buf); + + struct view *view; struct output *output; + struct wlr_scene_node *node; wl_list_for_each(output, &server->outputs, link) { destroy_osd_nodes(output); float scale = output->wlr_output->scale; - int w = (OSD_ITEM_WIDTH + (2 * OSD_BORDER_WIDTH)); - int h = get_osd_height(&server->views); + int w = OSD_ITEM_WIDTH + (2 * OSD_BORDER_WIDTH); + int h = get_osd_height(node_list); + if (show_workspace) { + /* workspace indicator */ + h += OSD_ITEM_HEIGHT; + } if (output->osd_buffer) { wlr_buffer_drop(&output->osd_buffer->base); @@ -148,10 +163,16 @@ osd_update(struct server *server) set_source(cairo, theme->osd_border_color); draw_border(cairo, w, h, theme->osd_border_width); - /* highlight current window */ int y = OSD_BORDER_WIDTH; - struct view *view; - wl_list_for_each(view, &server->views, link) { + + if (show_workspace) { + /* workspace indicator */ + y += OSD_ITEM_HEIGHT; + } + + /* highlight current window */ + wl_list_for_each_reverse(node, node_list, link) { + view = node_view_from_node(node); if (!isfocusable(view)) { continue; } @@ -179,7 +200,6 @@ osd_update(struct server *server) pango_font_description_set_family(desc, font.name); pango_font_description_set_size(desc, font.size * PANGO_SCALE); pango_layout_set_font_description(layout, desc); - pango_font_description_free(desc); PangoTabArray *tabs = pango_tab_array_new_with_positions(2, TRUE, PANGO_TAB_LEFT, OSD_TAB1, PANGO_TAB_LEFT, OSD_TAB2); @@ -189,9 +209,28 @@ osd_update(struct server *server) pango_cairo_update_layout(cairo, layout); y = OSD_BORDER_WIDTH; - y += (OSD_ITEM_HEIGHT - font_height(&font)) / 2; - wl_list_for_each(view, &server->views, link) { + /* Center text entries on the y axis */ + int y_offset = (OSD_ITEM_HEIGHT - font_height(&font)) / 2; + y += y_offset; + + if (show_workspace) { + /* Center workspace indicator on the x axis */ + int x = font_width(&font, server->workspace_current->name); + x = (OSD_ITEM_WIDTH - x) / 2; + cairo_move_to(cairo, x, y); + pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); + pango_layout_set_font_description(layout, desc); + pango_layout_set_text(layout, server->workspace_current->name, -1); + pango_cairo_show_layout(cairo, layout); + pango_font_description_set_weight(desc, PANGO_WEIGHT_NORMAL); + pango_layout_set_font_description(layout, desc); + y += OSD_ITEM_HEIGHT; + } + pango_font_description_free(desc); + + wl_list_for_each_reverse(node, node_list, link) { + view = node_view_from_node(node); if (!isfocusable(view)) { continue; } diff --git a/src/server.c b/src/server.c index 7ad7c427..9f6ad078 100644 --- a/src/server.c +++ b/src/server.c @@ -18,6 +18,7 @@ #include "menu/menu.h" #include "ssd.h" #include "theme.h" +#include "workspaces.h" #define LAB_XDG_SHELL_VERSION (2) @@ -181,6 +182,7 @@ server_init(struct server *server) event_loop, SIGINT, handle_sigterm, server->wl_display); sigterm_source = wl_event_loop_add_signal( event_loop, SIGTERM, handle_sigterm, server->wl_display); + server->wl_event_loop = event_loop; /* * The backend is a feature which abstracts the underlying input and @@ -245,6 +247,8 @@ server_init(struct server *server) #endif server->menu_tree = wlr_scene_tree_create(&server->scene->tree); + workspaces_init(server); + output_init(server); /* @@ -452,7 +456,7 @@ server_start(struct server *server) void server_finish(struct server *server) { -/* TODO: clean up various scene_tree nodes */ + #if HAVE_XWAYLAND wlr_xwayland_destroy(server->xwayland); #endif @@ -465,4 +469,7 @@ server_finish(struct server *server) wlr_output_layout_destroy(server->output_layout); wl_display_destroy(server->wl_display); + + /* TODO: clean up various scene_tree nodes */ + workspaces_destroy(server); } diff --git a/src/view.c b/src/view.c index e11610bc..e82dd6d3 100644 --- a/src/view.c +++ b/src/view.c @@ -6,6 +6,7 @@ #include "labwc.h" #include "ssd.h" #include "menu/menu.h" +#include "workspaces.h" #define MAX(a, b) (((a) > (b)) ? (a) : (b)) @@ -336,8 +337,8 @@ void view_toggle_always_on_top(struct view *view) { if (is_always_on_top(view)) { - wlr_scene_node_reparent(&view->scene_tree->node, - view->server->view_tree); + view->workspace = view->server->workspace_current; + wlr_scene_node_reparent(&view->scene_tree->node, view->workspace->tree); } else { wlr_scene_node_reparent(&view->scene_tree->node, view->server->view_tree_always_on_top); diff --git a/src/xdg.c b/src/xdg.c index 162a6d41..611691c6 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -3,6 +3,7 @@ #include "labwc.h" #include "node.h" #include "ssd.h" +#include "workspaces.h" static void handle_new_xdg_popup(struct wl_listener *listener, void *data) @@ -374,7 +375,8 @@ xdg_surface_new(struct wl_listener *listener, void *data) view->impl = &xdg_toplevel_view_impl; view->xdg_surface = xdg_surface; - view->scene_tree = wlr_scene_tree_create(view->server->view_tree); + view->workspace = server->workspace_current; + view->scene_tree = wlr_scene_tree_create(view->workspace->tree); wlr_scene_node_set_enabled(&view->scene_tree->node, false); struct wlr_scene_tree *tree = wlr_scene_xdg_surface_create( diff --git a/src/xwayland.c b/src/xwayland.c index 2790852d..334dd3b2 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -3,6 +3,7 @@ #include "labwc.h" #include "node.h" #include "ssd.h" +#include "workspaces.h" static void handle_commit(struct wl_listener *listener, void *data) @@ -434,7 +435,8 @@ xwayland_surface_new(struct wl_listener *listener, void *data) view->impl = &xwl_view_impl; view->xwayland_surface = xsurface; - view->scene_tree = wlr_scene_tree_create(view->server->view_tree); + view->workspace = server->workspace_current; + view->scene_tree = wlr_scene_tree_create(view->workspace->tree); node_descriptor_create(&view->scene_tree->node, LAB_NODE_DESC_VIEW, view); xsurface->data = view;