seat: use focus_change event to update focused/active view

- Connect to wlr_seat_keyboard_state's focus_change event.
- Add view_from_wlr_surface(), which does what the name says.
- Use focus_change event along with view_from_wlr_surface() to update
  server->focused_view and set SSD states via view_set_activated().
- Eliminate desktop_focused_view() since server->focused_view should be
  reliably up-to-date now.
- Eliminate view_focus/defocus() since we can now just call
  seat_focus_surface() directly.
This commit is contained in:
John Lindgren 2023-09-27 18:24:35 -04:00 committed by Johan Malm
parent bb5d272dc9
commit 4028a9482f
9 changed files with 77 additions and 100 deletions

View file

@ -503,7 +503,7 @@ view_for_action(struct view *activator, struct server *server,
return ctx.view;
}
default:
return desktop_focused_view(server);
return server->focused_view;
}
}

View file

@ -602,7 +602,7 @@ create_constraint(struct wl_listener *listener, void *data)
constraint->destroy.notify = destroy_constraint;
wl_signal_add(&wlr_constraint->events.destroy, &constraint->destroy);
struct view *view = desktop_focused_view(server);
struct view *view = server->focused_view;
if (view && view->surface == wlr_constraint->surface) {
constrain_cursor(server, wlr_constraint);
}

View file

@ -74,7 +74,10 @@ desktop_focus_view(struct view *view, bool raise)
workspaces_switch_to(view->workspace, /*update_focus*/ false);
}
view_focus(view);
struct seat *seat = &server->seat;
if (view->surface != seat->seat->keyboard_state.focused_surface) {
seat_focus_surface(seat, view->surface);
}
if (raise) {
view_move_to_front(view);
@ -147,7 +150,7 @@ desktop_cycle_view(struct server *server, struct view *start_view,
if (!start_view) {
start_view = first_view(server);
if (!start_view || start_view != desktop_focused_view(server)) {
if (!start_view || start_view != server->focused_view) {
return start_view; /* may be NULL */
}
}
@ -206,32 +209,6 @@ desktop_topmost_mapped_view(struct server *server)
return NULL;
}
struct view *
desktop_focused_view(struct server *server)
{
struct seat *seat = &server->seat;
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;
}
}
}
/* 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)
{
@ -242,12 +219,8 @@ desktop_focus_topmost_mapped_view(struct server *server)
/*
* 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);
}
}
}

View file

@ -94,7 +94,7 @@ handle_keybinding(struct server *server, uint32_t modifiers, xkb_keysym_t sym, x
continue;
}
if (server->seat.nr_inhibited_keybind_views
&& view_inhibits_keybinds(desktop_focused_view(server))
&& view_inhibits_keybinds(server->focused_view)
&& !actions_contain_toggle_keybinds(&keybind->actions)) {
continue;
}

View file

@ -11,6 +11,7 @@
#include "common/mem.h"
#include "key-state.h"
#include "labwc.h"
#include "view.h"
static void
input_device_destroy(struct wl_listener *listener, void *data)
@ -335,6 +336,26 @@ new_virtual_keyboard(struct wl_listener *listener, void *data)
seat_add_device(seat, input);
}
static void
focus_change_notify(struct wl_listener *listener, void *data)
{
struct seat *seat = wl_container_of(listener, seat, focus_change);
struct wlr_seat_keyboard_focus_change_event *event = data;
struct server *server = seat->server;
struct view *view = event->new_surface ?
view_from_wlr_surface(event->new_surface) : NULL;
if (view != server->focused_view) {
if (server->focused_view) {
view_set_activated(server->focused_view, false);
}
if (view) {
view_set_activated(view, true);
}
server->focused_view = view;
}
}
void
seat_init(struct server *server)
{
@ -353,6 +374,10 @@ seat_init(struct server *server)
seat->new_input.notify = new_input_notify;
wl_signal_add(&server->backend->events.new_input, &seat->new_input);
seat->focus_change.notify = focus_change_notify;
wl_signal_add(&seat->seat->keyboard_state.events.focus_change,
&seat->focus_change);
seat->virtual_pointer = wlr_virtual_pointer_manager_v1_create(
server->wl_display);
wl_signal_add(&seat->virtual_pointer->events.new_virtual_pointer,
@ -382,6 +407,7 @@ seat_finish(struct server *server)
{
struct seat *seat = &server->seat;
wl_list_remove(&seat->new_input.link);
wl_list_remove(&seat->focus_change.link);
struct input *input, *next;
wl_list_for_each_safe(input, next, &seat->inputs, link) {

View file

@ -2,6 +2,7 @@
#include <assert.h>
#include <stdio.h>
#include <strings.h>
#include <wlr/xwayland.h>
#include "common/mem.h"
#include "common/scene-helpers.h"
#include "labwc.h"
@ -19,6 +20,34 @@
#define LAB_FALLBACK_WIDTH 640
#define LAB_FALLBACK_HEIGHT 480
struct view *
view_from_wlr_surface(struct wlr_surface *surface)
{
assert(surface);
/*
* TODO:
* - find a way to get rid of xdg/xwayland-specific stuff
* - look up root/toplevel surface if passed a subsurface?
*/
if (wlr_surface_is_xdg_surface(surface)) {
struct wlr_xdg_surface *xdg_surface =
wlr_xdg_surface_from_wlr_surface(surface);
if (xdg_surface) {
return xdg_surface->data;
}
}
#if HAVE_XWAYLAND
if (wlr_surface_is_xwayland_surface(surface)) {
struct wlr_xwayland_surface *xsurface =
wlr_xwayland_surface_from_wlr_surface(surface);
if (xsurface) {
return xsurface->data;
}
}
#endif
return NULL;
}
static bool
matches_criteria(struct view *view, enum lab_view_criteria criteria)
{
@ -174,9 +203,10 @@ view_discover_output(struct view *view)
view->current.y + view->current.height / 2);
}
static void
_view_set_activated(struct view *view, bool activated)
void
view_set_activated(struct view *view, bool activated)
{
assert(view);
ssd_set_active(view->ssd, activated);
if (view->impl->set_activated) {
view->impl->set_activated(view, activated);
@ -187,52 +217,6 @@ _view_set_activated(struct view *view, bool activated)
}
}
/*
* 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_focus(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, 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);
}
/* Update active view */
if (view == view->server->focused_view) {
_view_set_activated(view, false);
view->server->focused_view = NULL;
}
}
void
view_set_output(struct view *view, struct output *output)
{
@ -408,7 +392,6 @@ _minimize(struct view *view, bool minimized)
view->minimized = minimized;
if (minimized) {
view->impl->unmap(view, /* client_request */ false);
view_defocus(view);
} else {
view->impl->map(view);
}

View file

@ -287,7 +287,7 @@ workspaces_switch_to(struct workspace *target, bool update_focus)
* Only refocus if the focus is not already on an always-on-top view.
*/
if (update_focus) {
struct view *view = desktop_focused_view(server);
struct view *view = server->focused_view;
if (!view || !view_is_always_on_top(view)) {
desktop_focus_topmost_mapped_view(server);
}