/* if set, views cannot receive focus */
struct wlr_layer_surface_v1 *focused_layer;
+ /**
+ * active_view will usually be NULL and is only set on button press
+ * while the mouse is over a view surface and reset to NULL on button
+ * release.
+ * It is used to send cursor motion events to a surface even though
+ * the cursor has left the surface in the meantime.
+ *
+ * This allows to keep dragging a scrollbar or selecting text even
+ * when moving outside of the window.
+ */
+ struct view *active_view;
+
struct wl_client *active_client_while_inhibited;
struct wl_list inputs;
struct wl_listener new_input;
} else if (server->input_mode == LAB_INPUT_STATE_RESIZE) {
process_cursor_resize(server, time);
return;
+ } else if (server->seat.active_view && !server->seat.drag_icon) {
+ /* Button has been pressed while over a view surface */
+ struct view *view = server->seat.active_view;
+ double sx = server->seat.cursor->x - view->x;
+ double sy = server->seat.cursor->y - view->y;
+ sx = sx < 0 ? 0 : (sx > view->w ? view->w : sx);
+ sy = sy < 0 ? 0 : (sy > view->h ? view->h : sy);
+ wlr_seat_pointer_notify_motion(server->seat.seat, time, sx, sy);
+ return;
}
/* Otherwise, find view under the pointer and send the event along */
{
struct seat *seat = wl_container_of(listener, seat, start_drag);
struct wlr_drag *wlr_drag = data;
+ seat->active_view = NULL;
seat->drag_icon = wlr_drag->icon;
wl_signal_add(&seat->drag_icon->events.destroy, &seat->destroy_drag);
}
/* handle _release_ */
if (event->state == WLR_BUTTON_RELEASED) {
+ server->seat.active_view = NULL;
+
if (server->input_mode == LAB_INPUT_STATE_MENU) {
if (close_menu) {
if (server->menu_current) {
}
/* Handle _press */
+ if (view_area == LAB_SSD_CLIENT) {
+ server->seat.active_view = view;
+ }
+
if (server->input_mode == LAB_INPUT_STATE_MENU) {
if (view_area != LAB_SSD_MENU) {
/* We close the menu on release so we don't leak a stray release */
wlr_foreign_toplevel_handle_v1_destroy(view->toplevel_handle);
}
interactive_end(view);
+ if (view->server->seat.active_view == view) {
+ view->server->seat.active_view = NULL;
+ }
wl_list_remove(&view->link);
wl_list_remove(&view->destroy.link);
if (view->scene_tree) {
wlr_foreign_toplevel_handle_v1_destroy(view->toplevel_handle);
}
interactive_end(view);
+ if (view->server->seat.active_view == view) {
+ view->server->seat.active_view = NULL;
+ }
view->xwayland_surface = NULL;
wl_list_remove(&view->link);
wl_list_remove(&view->map.link);