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 <margins> 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.
This commit is contained in:
Keith Bowes 2022-03-01 11:01:09 -05:00
parent 5a3ac6055d
commit 579a2d2084
8 changed files with 52 additions and 46 deletions

View file

@ -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;

View file

@ -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

View file

@ -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;

View file

@ -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) {

View file

@ -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);

View file

@ -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 *);

View file

@ -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);

View file

@ -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);
}