From afaf78aa72c728bc862059e6f24983c7ce7f6472 Mon Sep 17 00:00:00 2001 From: Johan Malm Date: Mon, 7 Sep 2020 19:47:11 +0100 Subject: [PATCH] view: refactor view_next() --- include/labwc.h | 4 +- src/action.c | 2 +- src/dbg.c | 4 ++ src/keyboard.c | 2 +- src/view.c | 97 ++++++++++++++++++++----------------------------- src/xdg.c | 2 +- src/xwayland.c | 4 +- 7 files changed, 50 insertions(+), 65 deletions(-) diff --git a/include/labwc.h b/include/labwc.h index 0ace4d23..fbffc846 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -128,6 +128,7 @@ struct view { bool mapped; bool been_mapped; + bool minimized; int x, y, w, h; bool show_server_side_deco; @@ -178,8 +179,7 @@ struct wlr_box view_get_surface_geometry(struct view *view); struct wlr_box view_geometry(struct view *view); void view_resize(struct view *view, struct wlr_box geo); void view_focus(struct view *view); -struct view *view_front_toplevel(struct server *server); -struct view *next_toplevel(struct view *current); +struct view *view_next(struct view *current); bool view_hasfocus(struct view *view); struct view *view_at(struct server *server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy, diff --git a/src/action.c b/src/action.c index ab4a91c9..9787cb45 100644 --- a/src/action.c +++ b/src/action.c @@ -11,7 +11,7 @@ void action(struct server *server, struct keybind *keybind) if (!strcasecmp(keybind->action, "Exit")) { wl_display_terminate(server->wl_display); } else if (!strcasecmp(keybind->action, "NextWindow")) { - server->cycle_view = next_toplevel(view_front_toplevel(server)); + server->cycle_view = view_next(server->cycle_view); } else if (!strcasecmp(keybind->action, "Execute")) { spawn_async_no_shell(keybind->command); } else if (!strcasecmp(keybind->action, "debug-views")) { diff --git a/src/dbg.c b/src/dbg.c index 9e26e602..ff845fae 100644 --- a/src/dbg.c +++ b/src/dbg.c @@ -71,6 +71,10 @@ static void show_one_xwl_view(struct view *view) void dbg_show_one_view(struct view *view) { + if (!view->surface) + return; + if (!view->mapped && !view->minimized) + return; if (view->type == LAB_XDG_SHELL_VIEW) show_one_xdg_view(view); else if (view->type == LAB_XWAYLAND_VIEW) diff --git a/src/keyboard.c b/src/keyboard.c index 2ca9009e..02a2e821 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -65,7 +65,7 @@ static void keyboard_handle_key(struct wl_listener *listener, void *data) server->cycle_view = NULL; } else if (event->state == WLR_KEY_PRESSED) { /* cycle to next */ - server->cycle_view = next_toplevel(server->cycle_view); + server->cycle_view = view_next(server->cycle_view); return; } } diff --git a/src/view.c b/src/view.c index d4034f47..74e26d28 100644 --- a/src/view.c +++ b/src/view.c @@ -1,19 +1,6 @@ #include "labwc.h" #include "common/bug-on.h" -static bool is_toplevel(struct view *view) -{ - if (!view) - return false; - switch (view->type) { - case LAB_XDG_SHELL_VIEW: - return view->xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL; - case LAB_XWAYLAND_VIEW: - return view->xwayland_surface->parent == NULL; - } - return false; -} - void view_init_position(struct view *view) { /* If surface already has a 'desired' position, don't touch it */ @@ -112,39 +99,6 @@ bool view_hasfocus(struct view *view) return (view->surface == seat->keyboard_state.focused_surface); } -static struct wlr_xwayland_surface *top_parent(struct view *view) -{ - struct wlr_xwayland_surface *s = view->xwayland_surface; - while (s->parent) - s = s->parent; - return s; -} - -static void move_xwayland_decendants_to_front(struct view *parent) -{ - if (!parent || parent->type != LAB_XWAYLAND_VIEW) - return; - struct view *view, *next; - wl_list_for_each_reverse_safe(view, next, &parent->server->views, link) - { - /* need to stop here, otherwise loops keeps going forever */ - if (view == parent) - break; - if (view->type != LAB_XWAYLAND_VIEW) - continue; - if (!view->mapped) - continue; - if (top_parent(view) != parent->xwayland_surface) - continue; - move_to_front(view); - } -} - -/** - * Note that if 'view' is not a toplevel view, the 'front' toplevel view - * will be focussed on; but if 'view' is a toplevel view, the 'next' - * will be focussed on. - */ void view_focus(struct view *view) { /* Note: this function only deals with keyboard focus. */ @@ -183,27 +137,56 @@ void view_focus(struct view *view) keyboard->num_keycodes, &keyboard->modifiers); - move_xwayland_decendants_to_front(view); + /* TODO: move xwayland decendants to front */ } -struct view *view_front_toplevel(struct server *server) +static struct view *first_view(void) { struct view *view; - wl_list_for_each (view, &server->views, link) { - if (is_toplevel(view)) - return view; - } - return NULL; + view = wl_container_of(server.views.next, view, link); + return view; } -struct view *next_toplevel(struct view *current) +/* + * Some xwayland apps produce unmapped surfaces on startup and also leave + * some unmapped surfaces kicking around on 'close' (for example * leafpad's + * "about" dialogue). Whilst this is not normally a problem, we have to be + * careful when cycling between views. The only view's we should focus are + * those that are already mapped and those that have been minimized. + */ +static bool isfocusable(struct view *view) { - if (!current) + /* filter out those xwayland surfaces that have never been mapped */ + if (!view->surface) + return false; + return (view->mapped || view->minimized); +} + +static int has_focusable_view(struct wl_list *wl_list) +{ + struct view *view; + wl_list_for_each (view, wl_list, link) { + if (isfocusable(view)) + return true; + } + return false; +} + +/* + * Return next view. If NULL provided, return second view from front. + */ +/* TODO: rename function */ +struct view *view_next(struct view *current) +{ + if (!has_focusable_view(&server.views)) return NULL; - struct view *view = current; + + struct view *view = current ? current : first_view(); + + /* Replacement for wl_list_for_each_from() */ do { view = wl_container_of(view->link.next, view, link); - } while (!is_toplevel(view)); + } while (&view->link == &server.views || !isfocusable(view)); return view; } diff --git a/src/xdg.c b/src/xdg.c index 2dd88809..63d81862 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -148,7 +148,7 @@ static void xdg_toplevel_view_unmap(struct view *view) { view->mapped = false; wl_list_remove(&view->commit.link); - view_focus(next_toplevel(view)); + view_focus(view_next(view)); } static const struct view_impl xdg_toplevel_view_impl = { diff --git a/src/xwayland.c b/src/xwayland.c index 2498ef1c..8400d573 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -57,8 +57,6 @@ static void _close(struct view *view) static bool want_ssd(struct view *view) { - if (view->xwayland_surface->override_redirect) - return false; if (view->xwayland_surface->decorations != WLR_XWAYLAND_SURFACE_DECORATIONS_ALL) return false; @@ -89,7 +87,7 @@ static void unmap(struct view *view) { view->mapped = false; wl_list_remove(&view->commit.link); - view_focus(next_toplevel(view)); + view_focus(view_next(view)); } static const struct view_impl xwl_view_impl = {