mirror of
https://github.com/labwc/labwc.git
synced 2026-04-09 08:21:18 -04:00
desktop: enforce followMouse focus policy more strictly
When followMouse=yes, prevent stealing focus from another view under the cursor. The requested view *is* allowed to take focus if it ends up under the cursor after raising, or if there is no view under the cursor at all. (Non-view surfaces aren't currently considered.) v2: allow focusing a new/raised view appearing under the cursor v3: allow focusing a sub-view/sibling of the requested view v4: fix new xdg-shell views under mouse not being focused v5: allow focus if no other view is focused; rebase
This commit is contained in:
parent
145de91932
commit
4025d009de
6 changed files with 54 additions and 15 deletions
|
|
@ -476,10 +476,12 @@ void xdg_shell_finish(struct server *server);
|
|||
void desktop_focus_view(struct view *view, bool raise);
|
||||
|
||||
/**
|
||||
* desktop_focus_view_or_surface() - like desktop_focus_view() but can
|
||||
* also focus other (e.g. xwayland-unmanaged) surfaces
|
||||
* desktop_focus_for_cursor_update() - like desktop_focus_view() but can
|
||||
* also focus other (e.g. xwayland-unmanaged) surfaces.
|
||||
*
|
||||
* Used only for cursor-driven focus updates.
|
||||
*/
|
||||
void desktop_focus_view_or_surface(struct seat *seat, struct view *view,
|
||||
void desktop_focus_for_cursor_update(struct seat *seat, struct view *view,
|
||||
struct wlr_surface *surface, bool raise);
|
||||
|
||||
void desktop_arrange_all_views(struct server *server);
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ set_or_offer_focus(struct view *view)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
desktop_focus_view(struct view *view, bool raise)
|
||||
static void
|
||||
_desktop_focus_view(struct view *view, bool raise, bool for_cursor_update)
|
||||
{
|
||||
assert(view);
|
||||
/*
|
||||
|
|
@ -100,6 +100,28 @@ desktop_focus_view(struct view *view, bool raise)
|
|||
view_move_to_front(view);
|
||||
}
|
||||
|
||||
/*
|
||||
* When followMouse=yes, prevent stealing focus from another
|
||||
* view under the cursor. The requested view *is* allowed to
|
||||
* take focus if it ends up under the cursor after raising, or
|
||||
* if there is no view under the cursor at all.
|
||||
*
|
||||
* If view_move_to_front() also raised child/sibling views,
|
||||
* then focus the sibling that's under the cursor.
|
||||
*/
|
||||
if (rc.focus_follow_mouse && !for_cursor_update) {
|
||||
struct cursor_context ctx = get_cursor_context(view->server);
|
||||
if (ctx.view && view_get_root(ctx.view) == view_get_root(view)) {
|
||||
view = ctx.view;
|
||||
} else if (ctx.view) {
|
||||
/*
|
||||
* Do not steal focus from an unrelated view.
|
||||
* TODO: consider non-view surfaces also?
|
||||
*/
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If any child/sibling of the view is a modal dialog, focus
|
||||
* the dialog instead. It does not need to be raised separately
|
||||
|
|
@ -109,14 +131,20 @@ desktop_focus_view(struct view *view, bool raise)
|
|||
set_or_offer_focus(dialog ? dialog : view);
|
||||
}
|
||||
|
||||
void
|
||||
desktop_focus_view(struct view *view, bool raise)
|
||||
{
|
||||
_desktop_focus_view(view, raise, /*for_cursor_update*/ false);
|
||||
}
|
||||
|
||||
/* TODO: focus layer-shell surfaces also? */
|
||||
void
|
||||
desktop_focus_view_or_surface(struct seat *seat, struct view *view,
|
||||
desktop_focus_for_cursor_update(struct seat *seat, struct view *view,
|
||||
struct wlr_surface *surface, bool raise)
|
||||
{
|
||||
assert(view || surface);
|
||||
if (view) {
|
||||
desktop_focus_view(view, raise);
|
||||
_desktop_focus_view(view, raise, /*for_cursor_update*/ true);
|
||||
#if HAVE_XWAYLAND
|
||||
} else {
|
||||
struct wlr_xwayland_surface *xsurface =
|
||||
|
|
|
|||
|
|
@ -639,7 +639,7 @@ cursor_process_motion(struct server *server, uint32_t time, double *sx, double *
|
|||
* If followMouse=yes, update the keyboard focus when the
|
||||
* cursor enters a surface
|
||||
*/
|
||||
desktop_focus_view_or_surface(seat,
|
||||
desktop_focus_for_cursor_update(seat,
|
||||
view_from_wlr_surface(new_focused_surface),
|
||||
new_focused_surface, rc.raise_on_focus);
|
||||
}
|
||||
|
|
@ -659,7 +659,7 @@ _cursor_update_focus(struct server *server)
|
|||
* Always focus the surface below the cursor when
|
||||
* followMouse=yes and followMouseRequiresMovement=no.
|
||||
*/
|
||||
desktop_focus_view_or_surface(&server->seat, ctx.view,
|
||||
desktop_focus_for_cursor_update(&server->seat, ctx.view,
|
||||
ctx.surface, rc.raise_on_focus);
|
||||
}
|
||||
|
||||
|
|
@ -1102,7 +1102,7 @@ cursor_process_button_press(struct seat *seat, uint32_t button, uint32_t time_ms
|
|||
}
|
||||
#ifdef HAVE_XWAYLAND
|
||||
} else if (ctx.type == LAB_SSD_UNMANAGED) {
|
||||
desktop_focus_view_or_surface(seat, NULL, ctx.surface,
|
||||
desktop_focus_for_cursor_update(seat, NULL, ctx.surface,
|
||||
/*raise*/ false);
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@
|
|||
void
|
||||
view_impl_map(struct view *view)
|
||||
{
|
||||
desktop_focus_view(view, /*raise*/ true);
|
||||
view_update_title(view);
|
||||
view_update_app_id(view);
|
||||
if (!view->been_mapped) {
|
||||
|
|
|
|||
10
src/xdg.c
10
src/xdg.c
|
|
@ -217,8 +217,18 @@ handle_commit(struct wl_listener *listener, void *data)
|
|||
}
|
||||
|
||||
if (update_required) {
|
||||
bool was_empty = wlr_box_empty(current);
|
||||
view_impl_apply_geometry(view, size.width, size.height);
|
||||
|
||||
/*
|
||||
* Try to focus the view once it has a valid surface
|
||||
* size. Before this point, the under-mouse checks in
|
||||
* desktop_focus_view() may fail.
|
||||
*/
|
||||
if (was_empty && !wlr_box_empty(&size)) {
|
||||
desktop_focus_view(view, /*raise*/ true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Some views (e.g., terminals that scale as multiples of rows
|
||||
* and columns, or windows that impose a fixed aspect ratio),
|
||||
|
|
|
|||
|
|
@ -826,14 +826,14 @@ xwayland_view_map(struct view *view)
|
|||
|
||||
/*
|
||||
* If the view was focused (on the xwayland server side) before
|
||||
* being mapped, update the seat focus now. Note that this only
|
||||
* really matters in the case of Globally Active input windows.
|
||||
* In all other cases, it's redundant since view_impl_map()
|
||||
* results in the view being focused anyway.
|
||||
* being mapped, just update the seat focus. Otherwise, try to
|
||||
* focus the view now.
|
||||
*/
|
||||
if (xwayland_view->focused_before_map) {
|
||||
xwayland_view->focused_before_map = false;
|
||||
seat_focus_surface(&view->server->seat, view->surface);
|
||||
} else {
|
||||
desktop_focus_view(view, /*raise*/ true);
|
||||
}
|
||||
|
||||
view_impl_map(view);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue