- 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.
struct wl_client *active_client_while_inhibited;
struct wl_list inputs;
struct wl_listener new_input;
+ struct wl_listener focus_change;
struct wl_listener cursor_motion;
struct wl_listener cursor_motion_absolute;
/* 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().
+ * Currently focused view. Updated with each "focus change"
+ * event. This view is drawn with "active" SSD coloring.
*/
struct view *focused_view;
struct ssd_hover_state *ssd_hover_state;
*/
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);
void keyboard_cancel_keybind_repeat(struct keyboard *keyboard);
LAB_VIEW_CRITERIA_NO_SKIP_WINDOW_SWITCHER = 1 << 2,
};
+/**
+ * view_from_wlr_surface() - returns the view associated with a
+ * wlr_surface, or NULL if the surface has no associated view.
+ */
+struct view *view_from_wlr_surface(struct wlr_surface *surface);
+
/**
* for_each_view() - iterate over all views which match criteria
* @view: Iterator.
bool view_inhibits_keybinds(struct view *view);
void view_toggle_keybinds(struct view *view);
-void view_focus(struct view *view);
-void view_defocus(struct view *view);
+void view_set_activated(struct view *view, bool activated);
void view_set_output(struct view *view, struct output *output);
void view_close(struct view *view);
return ctx.view;
}
default:
- return desktop_focused_view(server);
+ return server->focused_view;
}
}
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);
}
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);
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 */
}
}
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)
{
/*
* 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);
- }
}
}
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;
}
#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)
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)
{
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,
{
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) {
#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"
#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)
{
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);
}
}
-/*
- * 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)
{
view->minimized = minimized;
if (minimized) {
view->impl->unmap(view, /* client_request */ false);
- view_defocus(view);
} else {
view->impl->map(view);
}
* 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);
}