From 579a2d20849ad98918b517ea4d1871d617ab79ff Mon Sep 17 00:00:00 2001 From: Keith Bowes Date: Tue, 1 Mar 2022 11:01:09 -0500 Subject: [PATCH] Some bug fixes 1. The "crash when exiting an application while moving it" bug. See https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3372 2. The crash when there's no previous view to focus. This wasn't a problem before the migration to the scene graph API due to a logic error on my part. 3. The crash if is missing from rc.xml. 4. I'm now reusing code from focus_view() in seat_focus_surface(). 5. I'm now using the dimensions of the output layout box instead of the current view (which was clearly wrong) for unconstraining layer-shell popups. 6. I fixed setting the background color, so that it won't interfere with the layer_shell helper. --- include/waybox/output.h | 5 ++--- include/waybox/seat.h | 1 + waybox/config.c | 14 ++++++++++---- waybox/cursor.c | 6 ++++-- waybox/layer_shell.c | 9 ++++----- waybox/output.c | 24 ++++++++++++++++-------- waybox/seat.c | 4 +++- waybox/xdg_shell.c | 35 ++++++++++++----------------------- 8 files changed, 52 insertions(+), 46 deletions(-) diff --git a/include/waybox/output.h b/include/waybox/output.h index 1ce66b2..a126f0e 100644 --- a/include/waybox/output.h +++ b/include/waybox/output.h @@ -23,9 +23,8 @@ struct wb_output { struct wlr_scene_node *shell_top; } layers; -#if !WLR_CHECK_VERSION(0, 16, 0) - struct wlr_scene_rect *scene_rect; -#endif + struct wlr_scene_rect *background; + struct wlr_box geometry; struct wl_listener destroy; struct wl_listener frame; diff --git a/include/waybox/seat.h b/include/waybox/seat.h index 18ef020..c3a60c2 100644 --- a/include/waybox/seat.h +++ b/include/waybox/seat.h @@ -30,6 +30,7 @@ struct wb_keyboard { struct wb_server; struct wb_seat *wb_seat_create(struct wb_server *server); +void seat_focus_surface(struct wb_seat *seat, struct wlr_surface *surface); void seat_set_focus_layer(struct wb_seat *seat, struct wlr_layer_surface_v1 *layer); void wb_seat_destroy(struct wb_seat *seat); #endif diff --git a/waybox/config.c b/waybox/config.c index 68973d2..861faa7 100644 --- a/waybox/config.c +++ b/waybox/config.c @@ -3,6 +3,12 @@ #include "config.h" +static unsigned long strtoulong(char *s) { + if (s) + return strtoul(s, (char **) NULL, 10); + else return 0; +} + static char *parse_xpath_expr(char *expr, xmlXPathContextPtr ctxt) { xmlXPathObjectPtr object = xmlXPathEvalExpression((xmlChar *) expr, ctxt); if (object == NULL) { @@ -175,10 +181,10 @@ bool init_config(struct wb_server *server) { return false; } - config->margins.bottom = strtoul(parse_xpath_expr("//ob:margins/ob:bottom", ctxt), NULL, 10); - config->margins.left = strtoul(parse_xpath_expr("//ob:margins/ob:left", ctxt), NULL, 10); - config->margins.right = strtoul(parse_xpath_expr("//ob:margins/ob:right", ctxt), NULL, 10); - config->margins.top = strtoul(parse_xpath_expr("//ob:margins/ob:top", ctxt), NULL, 10); + config->margins.bottom = strtoulong(parse_xpath_expr("//ob:margins/ob:bottom", ctxt)); + config->margins.left = strtoulong(parse_xpath_expr("//ob:margins/ob:left", ctxt)); + config->margins.right = strtoulong(parse_xpath_expr("//ob:margins/ob:right", ctxt)); + config->margins.top = strtoulong(parse_xpath_expr("//ob:margins/ob:top", ctxt)); server->config = config; diff --git a/waybox/cursor.c b/waybox/cursor.c index e37968b..d93d893 100644 --- a/waybox/cursor.c +++ b/waybox/cursor.c @@ -7,8 +7,10 @@ static void process_cursor_move(struct wb_server *server) { struct wb_view *view = server->grabbed_view; view->current_position.x = server->cursor->cursor->x - server->grab_x; view->current_position.y = server->cursor->cursor->y - server->grab_y; - wlr_scene_node_set_position(view->scene_node, - view->current_position.x, view->current_position.y); + if (view->scene_node->parent->type == WLR_SCENE_NODE_ROOT) { + wlr_scene_node_set_position(view->scene_node, + view->current_position.x, view->current_position.y); + } } static void process_cursor_resize(struct wb_server *server) { diff --git a/waybox/layer_shell.c b/waybox/layer_shell.c index 0269b49..fb2449b 100644 --- a/waybox/layer_shell.c +++ b/waybox/layer_shell.c @@ -237,12 +237,11 @@ static void popup_unconstrain(struct wb_layer_popup *popup) { /* the output box expressed in the coordinate system of the toplevel parent * of the popup */ - struct wb_view *view = wl_container_of(output->server->views.next, view, link); struct wlr_box output_toplevel_sx_box = { - .x = view->current_position.x - lx, - .y = view->current_position.y - ly, - .width = output->wlr_output->width, - .height = output->wlr_output->height, + .x = output->geometry.x - lx, + .y = output->geometry.y - ly, + .width = output->geometry.width, + .height = output->geometry.height, }; wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box); diff --git a/waybox/output.c b/waybox/output.c index 32e25dc..a1bb7ac 100644 --- a/waybox/output.c +++ b/waybox/output.c @@ -1,20 +1,30 @@ #include "waybox/output.h" void output_frame_notify(struct wl_listener *listener, void *data) { + /* This function is called every time an output is ready to display a frame, + * generally at the output's refresh rate (e.g. 60Hz). */ struct wb_output *output = wl_container_of(listener, output, frame); struct wlr_scene *scene = output->server->scene; struct wlr_scene_output *scene_output = wlr_scene_get_scene_output( scene, output->wlr_output); -#if !WLR_CHECK_VERSION(0, 16, 0) - wlr_scene_rect_set_size(output->scene_rect, - output->wlr_output->width, output->wlr_output->height); +#if WLR_CHECK_VERSION(0, 16, 0) + wlr_output_layout_get_box(output->server->output_layout, + output->wlr_output, &output->geometry); +#else + output->geometry = *wlr_output_layout_get_box( + output->server->output_layout, output->wlr_output); #endif + /* Update the background for the current output size. */ + wlr_scene_rect_set_size(output->background, + output->geometry.width, output->geometry.height); /* Render the scene if needed and commit the output */ wlr_scene_output_commit(scene_output); + /* This lets the client know that we've displayed that frame and it can + * prepare another one now if it likes. */ struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); wlr_scene_output_send_frame_done(scene_output, &now); @@ -65,12 +75,10 @@ void new_output_notify(struct wl_listener *listener, void *data) { output->wlr_output = wlr_output; wlr_output->data = output; -#if !WLR_CHECK_VERSION(0, 16, 0) - /* Allows setting the traditional background color. However, it - * interferes with the wlr_scene layer shell helper in 0.16.0+. */ + /* Set the background color */ float color[4] = {0.1875, 0.1875, 0.1875, 1.0}; - output->scene_rect = wlr_scene_rect_create(&server->scene->node, 0, 0, color); -#endif + output->background = wlr_scene_rect_create(&server->scene->node, 0, 0, color); + wlr_scene_node_lower_to_bottom(&output->background->node); /* Initializes the layers */ size_t num_layers = sizeof(output->layers) / sizeof(struct wlr_scene_node *); diff --git a/waybox/seat.c b/waybox/seat.c index d9151ef..e5cf54f 100644 --- a/waybox/seat.c +++ b/waybox/seat.c @@ -274,7 +274,8 @@ void seat_focus_surface(struct wb_seat *seat, struct wlr_surface *surface) { wlr_seat_keyboard_notify_clear_focus(seat->seat); return; } - struct wlr_keyboard *kb = (struct wlr_keyboard *) seat->keyboards.next; + + struct wlr_keyboard *kb = wlr_seat_get_keyboard(seat->seat); wlr_seat_keyboard_notify_enter(seat->seat, surface, kb->keycodes, kb->num_keycodes, &kb->modifiers); } @@ -327,6 +328,7 @@ struct wb_seat *wb_seat_create(struct wb_server *server) { } void wb_seat_destroy(struct wb_seat *seat) { + wl_list_remove(&seat->keyboards); wl_list_remove(&seat->request_set_primary_selection.link); wl_list_remove(&seat->request_set_selection.link); wlr_seat_destroy(seat->seat); diff --git a/waybox/xdg_shell.c b/waybox/xdg_shell.c index dae34f7..13b9463 100644 --- a/waybox/xdg_shell.c +++ b/waybox/xdg_shell.c @@ -52,7 +52,6 @@ void focus_view(struct wb_view *view, struct wlr_surface *surface) { wlr_xdg_toplevel_set_activated(previous, false); #endif } - struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat); /* Move the view to the front */ wlr_scene_node_raise_to_top(view->scene_node); wl_list_remove(&view->link); @@ -68,8 +67,7 @@ void focus_view(struct wb_view *view, struct wlr_surface *surface) { * track of this and automatically send key events to the appropriate * clients without additional work on your part. */ - wlr_seat_keyboard_notify_enter(seat, view->xdg_toplevel->base->surface, - keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers); + seat_focus_surface(server->seat, view->xdg_toplevel->base->surface); } static struct wlr_box get_usable_area(struct wb_view *view) { @@ -126,15 +124,9 @@ static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) { if (view->xdg_toplevel->base->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) return; + /* Focus the next view, if any. */ struct wb_view *next_view = wl_container_of(view->link.next, next_view, link); - /* If the current view is mapped, focus it. */ - if (view->scene_node->state.enabled) { - wlr_log(WLR_INFO, "%s: %s", _("Focusing current view"), - view->xdg_toplevel->app_id); - focus_view(view, view->xdg_toplevel->base->surface); - } - /* Otherwise, focus the next view, if any. */ - else if (next_view && next_view->scene_node && next_view->scene_node->state.enabled) { + if (next_view && next_view->scene_node && next_view->scene_node->state.enabled) { wlr_log(WLR_INFO, "%s: %s", _("Focusing next view"), next_view->xdg_toplevel->app_id); focus_view(next_view, next_view->xdg_toplevel->base->surface); @@ -148,6 +140,7 @@ static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) { wl_list_remove(&view->map.link); wl_list_remove(&view->unmap.link); wl_list_remove(&view->destroy.link); + wl_list_remove(&view->new_popup.link); if (view->xdg_toplevel->base->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { wl_list_remove(&view->request_minimize.link); @@ -269,22 +262,18 @@ static void xdg_toplevel_request_resize( static void handle_new_popup(struct wl_listener *listener, void *data) { struct wlr_xdg_popup *popup = data; struct wb_view *view = wl_container_of(listener, view, new_popup); - struct wlr_output_layout *output_layout = view->server->output_layout; - struct wlr_output *wlr_output = wlr_output_layout_output_at(output_layout, + struct wlr_output *wlr_output = wlr_output_layout_output_at( + view->server->output_layout, view->current_position.x + popup->geometry.x, view->current_position.y + popup->geometry.y); - struct wlr_box output_box; -#if WLR_CHECK_VERSION(0, 16, 0) - wlr_output_layout_get_box(output_layout, wlr_output, &output_box); -#else - output_box = (*wlr_output_layout_get_box(output_layout, wlr_output)); -#endif + struct wb_output *output = wlr_output->data; + struct wlr_box output_toplevel_box = { - .x = output_box.x - view->current_position.x, - .y = output_box.y - view->current_position.y, - .width = output_box.width, - .height = output_box.height, + .x = output->geometry.x - view->current_position.x, + .y = output->geometry.y - view->current_position.y, + .width = output->geometry.width, + .height = output->geometry.height, }; wlr_xdg_popup_unconstrain_from_box(popup, &output_toplevel_box); }