diff --git a/include/labwc.h b/include/labwc.h index b343fbba..93f1e01c 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -522,14 +522,6 @@ struct view *desktop_node_and_view_at(struct server *server, double lx, struct view *desktop_view_at_cursor(struct server *server); -/** - * cursor_rebase - set cursor icon for and send motion-event to surface below it - * @seat - current seat - * @time_msec - time now - * @force - disable check for skipping already focused surface - */ -void cursor_rebase(struct seat *seat, uint32_t time_msec, bool force); - /** * cursor_set - set cursor icon * @seat - current seat @@ -538,7 +530,7 @@ void cursor_rebase(struct seat *seat, uint32_t time_msec, bool force); void cursor_set(struct seat *seat, const char *cursor_name); /** - * cursor_update_focus - update cursor focus + * cursor_update_focus - update cursor focus, may update the cursor icon * @server - server * Use it to force an update of the cursor icon and to send an enter event * to the surface below the cursor. diff --git a/src/cursor.c b/src/cursor.c index 89ea6996..fc5a3204 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -24,24 +24,24 @@ is_surface(enum ssd_part_type view_area) ; } -void -cursor_rebase(struct seat *seat, uint32_t time_msec, bool force) +/* + * cursor_rebase() for internal use: reuses node, surface, sx and sy + * For a public variant use cursor_update_focus() + */ +static void +cursor_rebase(struct seat *seat, struct wlr_scene_node *node, + struct wlr_surface *surface, double sx, double sy, uint32_t time_msec, + bool force) { - double sx, sy; - struct wlr_scene_node *node; - enum ssd_part_type view_area = LAB_SSD_NONE; - struct wlr_surface *surface = NULL; - - desktop_node_and_view_at(seat->server, seat->cursor->x, - seat->cursor->y, &node, &sx, &sy, &view_area); - if (is_surface(view_area)) { - surface = lab_wlr_surface_from_node(node); + if (seat->pressed.surface && surface != seat->pressed.surface) { + /* Don't leave surface when a button was pressed over another surface */ + return; } if (surface) { if (!force && surface == seat->seat->pointer_state.focused_surface) { /* - * Usually we prevent re-entering an already focued surface + * Usually we prevent re-entering an already focused surface * because it sends useless leave and enter events. * * They may also seriously confuse clients if sent between @@ -367,10 +367,26 @@ msec(const struct timespec *t) void cursor_update_focus(struct server *server) { + double sx, sy; + struct wlr_scene_node *node = NULL; + struct wlr_surface *surface = NULL; + enum ssd_part_type view_area = LAB_SSD_NONE; + struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); + + struct seat *seat = &server->seat; + desktop_node_and_view_at(seat->server, seat->cursor->x, + seat->cursor->y, &node, &sx, &sy, &view_area); + + if (is_surface(view_area)) { + surface = lab_wlr_surface_from_node(node); + } + + ssd_update_button_hover(node, &seat->server->ssd_hover_state); + /* Focus surface under cursor if it isn't already focused */ - cursor_rebase(&server->seat, msec(&now), false); + cursor_rebase(seat, node, surface, sx, sy, msec(&now), false); } void @@ -695,7 +711,7 @@ cursor_button(struct wl_listener *listener, void *data) wlr_idle_notify_activity(seat->wlr_idle, seat->seat); double sx, sy; - struct wlr_scene_node *node; + struct wlr_scene_node *node = NULL; enum ssd_part_type view_area = LAB_SSD_NONE; uint32_t resize_edges = 0; @@ -739,7 +755,8 @@ cursor_button(struct wl_listener *listener, void *data) if (server->input_mode == LAB_INPUT_STATE_MENU) { if (close_menu) { menu_close_root(server); - cursor_rebase(&server->seat, event->time_msec, false); + cursor_rebase(&server->seat, node, surface, sx, sy, + event->time_msec, false); close_menu = false; } return; @@ -757,7 +774,8 @@ cursor_button(struct wl_listener *listener, void *data) * Focus surface under cursor and force updating the * cursor icon */ - cursor_rebase(&server->seat, event->time_msec, true); + cursor_rebase(&server->seat, node, surface, sx, sy, + event->time_msec, true); return; } goto mousebindings; @@ -829,6 +847,9 @@ cursor_axis(struct wl_listener *listener, void *data) struct wlr_pointer_axis_event *event = data; wlr_idle_notify_activity(seat->wlr_idle, seat->seat); + /* Make sure we are sending the events to the surface under the cursor */ + cursor_update_focus(seat->server); + /* Notify the client with pointer focus of the axis event. */ wlr_seat_pointer_notify_axis(seat->seat, event->time_msec, event->orientation, event->delta, event->delta_discrete, diff --git a/src/view.c b/src/view.c index f1766a91..0f5a8351 100644 --- a/src/view.c +++ b/src/view.c @@ -149,6 +149,7 @@ view_moved(struct view *view) wlr_scene_node_set_position(&view->scene_tree->node, view->x, view->y); view_discover_output(view); ssd_update_geometry(view); + cursor_update_focus(view->server); } /* N.B. Use view_move() if not resizing. */ diff --git a/src/xdg.c b/src/xdg.c index e75ac138..2456f7f8 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -40,16 +40,23 @@ handle_commit(struct wl_listener *listener, void *data) struct wlr_box size; wlr_xdg_surface_get_geometry(view->xdg_surface, &size); - view->w = size.width; - view->h = size.height; + bool update_required = false; + + if (view->w != size.width || view->h != size.height) { + update_required = true; + view->w = size.width; + view->h = size.height; + } uint32_t serial = view->pending_move_resize.configure_serial; if (serial > 0 && serial >= view->xdg_surface->current.configure_serial) { if (view->pending_move_resize.update_x) { + update_required = true; view->x = view->pending_move_resize.x + view->pending_move_resize.width - size.width; } if (view->pending_move_resize.update_y) { + update_required = true; view->y = view->pending_move_resize.y + view->pending_move_resize.height - size.height; } @@ -57,7 +64,9 @@ handle_commit(struct wl_listener *listener, void *data) view->pending_move_resize.configure_serial = 0; } } - view_moved(view); + if (update_required) { + view_moved(view); + } } static void diff --git a/src/xwayland-unmanaged.c b/src/xwayland-unmanaged.c index b14760c2..b09b6196 100644 --- a/src/xwayland-unmanaged.c +++ b/src/xwayland-unmanaged.c @@ -11,6 +11,7 @@ unmanaged_handle_request_configure(struct wl_listener *listener, void *data) wlr_xwayland_surface_configure(xsurface, ev->x, ev->y, ev->width, ev->height); if (unmanaged->node) { wlr_scene_node_set_position(unmanaged->node, ev->x, ev->y); + cursor_update_focus(unmanaged->server); } } @@ -22,6 +23,7 @@ unmanaged_handle_set_geometry(struct wl_listener *listener, void *data) struct wlr_xwayland_surface *xsurface = unmanaged->xwayland_surface; if (unmanaged->node) { wlr_scene_node_set_position(unmanaged->node, xsurface->x, xsurface->y); + cursor_update_focus(unmanaged->server); } } @@ -49,6 +51,7 @@ unmanaged_handle_map(struct wl_listener *listener, void *data) unmanaged->server->unmanaged_tree, xsurface->surface)->buffer->node; wlr_scene_node_set_position(unmanaged->node, xsurface->x, xsurface->y); + cursor_update_focus(unmanaged->server); } static void @@ -102,6 +105,7 @@ unmanaged_handle_unmap(struct wl_listener *listener, void *data) seat_reset_pressed(seat); } unmanaged->node = NULL; + cursor_update_focus(unmanaged->server); if (seat->seat->keyboard_state.focused_surface == xsurface->surface) { focus_next_surface(unmanaged->server, xsurface);