uint32_t resize_edges;
/* SSD state */
+ /*
+ * Currently focused view (cached value). This pointer is used
+ * primarily to track which view is being drawn with "active"
+ * SSD coloring. We consider it a bug if this gets out of sync
+ * with the actual keyboard focus (according to wlroots). See
+ * also desktop_focused_view().
+ */
struct view *focused_view;
struct ssd_hover_state *ssd_hover_state;
* cannot assume this means that the window actually has keyboard
* or pointer focus, in this compositor are they called together.
*/
-void desktop_focus_and_activate_view(struct seat *seat, struct view *view);
+void desktop_focus_view(struct view *view);
void desktop_arrange_all_views(struct server *server);
void desktop_focus_output(struct output *output);
struct view *desktop_topmost_mapped_view(struct server *server);
*/
struct view *desktop_cycle_view(struct server *server, struct view *start_view,
enum lab_cycle_dir dir);
+/**
+ * desktop_focused_view - return the view that is currently focused
+ * (determined on-the-fly from the wlroots keyboard focus). The return
+ * value should ideally match server->focused_view (we consider it a
+ * bug otherwise) but is guaranteed to be up-to-date even if
+ * server->focused_view gets out of sync.
+ */
struct view *desktop_focused_view(struct server *server);
void desktop_focus_topmost_mapped_view(struct server *server);
bool view_inhibits_keybinds(struct view *view);
void view_toggle_keybinds(struct view *view);
-void view_set_activated(struct view *view);
+void view_focus(struct view *view);
+void view_defocus(struct view *view);
void view_set_output(struct view *view, struct output *output);
void view_close(struct view *view);
break;
case ACTION_TYPE_FOCUS:
if (view) {
- desktop_focus_and_activate_view(&server->seat, view);
+ desktop_focus_view(view);
}
break;
case ACTION_TYPE_ICONIFY:
}
if (ctx.view && rc.focus_follow_mouse) {
- desktop_focus_and_activate_view(seat, ctx.view);
+ desktop_focus_view(ctx.view);
if (rc.raise_on_focus) {
view_move_to_front(ctx.view);
}
&& !rc.focus_follow_mouse_requires_movement
&& !server->osd_state.cycle_view) {
/* Prevents changing keyboard focus during A-Tab */
- desktop_focus_and_activate_view(&server->seat, ctx.view);
+ desktop_focus_view(ctx.view);
if (rc.raise_on_focus) {
view_move_to_front(ctx.view);
}
}
void
-desktop_focus_and_activate_view(struct seat *seat, struct view *view)
+desktop_focus_view(struct view *view)
{
- if (!view) {
- seat_focus_surface(seat, NULL);
- return;
- }
-
+ assert(view);
/*
* Guard against views with no mapped surfaces when handling
* 'request_activate' and 'request_minimize'.
return;
}
- if (input_inhibit_blocks_surface(seat, view->surface->resource)
- || seat->server->session_lock) {
+ struct server *server = view->server;
+ if (input_inhibit_blocks_surface(&server->seat, view->surface->resource)
+ || server->session_lock) {
return;
}
return;
}
- struct wlr_surface *prev_surface;
- prev_surface = seat->seat->keyboard_state.focused_surface;
-
- /* Do not re-focus an already focused surface. */
- if (prev_surface == view->surface) {
- return;
- }
-
- view_set_activated(view);
- seat_focus_surface(seat, view->surface);
+ view_focus(view);
}
static struct wl_list *
desktop_focused_view(struct server *server)
{
struct seat *seat = &server->seat;
- struct wlr_surface *focused_surface;
- focused_surface = seat->seat->keyboard_state.focused_surface;
- if (!focused_surface) {
- return NULL;
- }
- struct view *view;
- wl_list_for_each(view, &server->views, link) {
- if (view->surface == focused_surface) {
- return view;
+ struct wlr_surface *focused_surface =
+ seat->seat->keyboard_state.focused_surface;
+ struct view *focused_view = NULL;
+
+ if (focused_surface) {
+ struct view *view;
+ wl_list_for_each(view, &server->views, link) {
+ if (view->surface == focused_surface) {
+ focused_view = view;
+ break;
+ }
}
}
- return NULL;
+ /* warn so we can identify cases where this occurs */
+ if (focused_view != server->focused_view) {
+ wlr_log(WLR_ERROR, "server->focused_view is out of sync");
+ }
+
+ return focused_view;
}
void
desktop_focus_topmost_mapped_view(struct server *server)
{
struct view *view = desktop_topmost_mapped_view(server);
- desktop_focus_and_activate_view(&server->seat, view);
if (view) {
+ desktop_focus_view(view);
view_move_to_front(view);
+ } else {
+ /*
+ * Defocus previous focused surface/view if no longer
+ * focusable (e.g. unmapped or on a different workspace).
+ * Note than a non-view surface may have been focused.
+ */
+ seat_focus_surface(&server->seat, NULL);
+ if (server->focused_view) {
+ view_defocus(server->focused_view);
+ }
}
}
}
if (wlr_output_layout_intersects(layout,
output->wlr_output, &view->current)) {
- desktop_focus_and_activate_view(&output->server->seat, view);
+ desktop_focus_view(view);
wlr_cursor_warp(output->server->seat.cursor, NULL,
view->current.x + view->current.width / 2,
view->current.y + view->current.height / 2);
if (view->workspace != view->server->workspace_current) {
workspaces_switch_to(view->workspace);
}
- desktop_focus_and_activate_view(&view->server->seat, view);
+ desktop_focus_view(view);
view_move_to_front(view);
}
static void
end_cycling(struct server *server)
{
- desktop_focus_and_activate_view(&server->seat, server->osd_state.cycle_view);
if (server->osd_state.cycle_view) {
+ desktop_focus_view(server->osd_state.cycle_view);
view_move_to_front(server->osd_state.cycle_view);
}
void
view_impl_map(struct view *view)
{
- desktop_focus_and_activate_view(&view->server->seat, view);
+ desktop_focus_view(view);
view_move_to_front(view);
view_update_title(view);
view_update_app_id(view);
}
}
+/*
+ * Give the view keyboard focus and mark it active. This function should
+ * only be called by desktop_focus_view(), which contains additional
+ * checks to make sure it's okay to give focus.
+ */
void
-view_set_activated(struct view *view)
+view_focus(struct view *view)
{
assert(view);
- struct view *last = view->server->focused_view;
- if (last == view) {
- return;
+ /* Update seat focus */
+ struct seat *seat = &view->server->seat;
+ if (view->surface != seat->seat->keyboard_state.focused_surface) {
+ seat_focus_surface(seat, view->surface);
+ }
+ /* Update active view */
+ if (view != view->server->focused_view) {
+ if (view->server->focused_view) {
+ _view_set_activated(view->server->focused_view, false);
+ }
+ _view_set_activated(view, true);
+ view->server->focused_view = view;
+ }
+}
+
+/*
+ * Take keyboard focus from the view and mark it inactive. It's rarely
+ * necessary to call this function directly; usually it's better to
+ * focus a different view instead by calling something like
+ * desktop_focus_topmost_mapped_view().
+ */
+void
+view_defocus(struct view *view)
+{
+ assert(view);
+ /* Update seat focus */
+ struct seat *seat = &view->server->seat;
+ if (view->surface == seat->seat->keyboard_state.focused_surface) {
+ seat_focus_surface(seat, NULL);
}
- if (last) {
- _view_set_activated(last, false);
+ /* Update active view */
+ if (view == view->server->focused_view) {
+ _view_set_activated(view, false);
+ view->server->focused_view = NULL;
}
- _view_set_activated(view, true);
- view->server->focused_view = view;
}
void
view->minimized = minimized;
if (minimized) {
view->impl->unmap(view, /* client_request */ false);
- _view_set_activated(view, false);
- if (view == view->server->focused_view) {
- /*
- * Prevents clearing the active view when
- * we don't actually have keyboard focus.
- *
- * This may happen when using a custom mouse
- * focus configuration or by using the foreign
- * toplevel protocol via some panel.
- */
- view->server->focused_view = NULL;
- }
+ view_defocus(view);
} else {
view->impl->map(view);
}
if (view->workspace != view->server->workspace_current) {
workspaces_switch_to(view->workspace);
}
- desktop_focus_and_activate_view(&view->server->seat, view);
+ desktop_focus_view(view);
view_move_to_front(view);
}
return;
}
- desktop_focus_and_activate_view(&view->server->seat, view);
+ desktop_focus_view(view);
view_move_to_front(view);
}