mirror of
https://gitlab.freedesktop.org/wlroots/wlroots.git
synced 2026-04-17 06:46:39 -04:00
Merge branch 'input-router' into 'master'
Add input router See merge request wlroots/wlroots!4950
This commit is contained in:
commit
5d3fd61b9c
27 changed files with 4048 additions and 0 deletions
|
|
@ -4,6 +4,7 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
|
||||||
struct libseat;
|
struct libseat;
|
||||||
|
|
||||||
|
|
@ -88,6 +89,27 @@ struct wlr_device_change_event {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A session input router layer which handles key presses for keysyms from
|
||||||
|
* XKB_KEY_XF86Switch_VT_1 to XKB_KEY_XF86Switch_VT_12 inclusive and calls
|
||||||
|
* wlr_session_change_vt() accordingly.
|
||||||
|
*/
|
||||||
|
struct wlr_session_input_router_layer {
|
||||||
|
struct wlr_input_router *router;
|
||||||
|
struct wlr_session *session;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wlr_input_router_keyboard keyboard;
|
||||||
|
|
||||||
|
struct wl_listener router_destroy;
|
||||||
|
struct wl_listener session_destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Opens a session, taking control of the current virtual terminal.
|
* Opens a session, taking control of the current virtual terminal.
|
||||||
* This should not be called if another program is already in control
|
* This should not be called if another program is already in control
|
||||||
|
|
@ -143,4 +165,12 @@ bool wlr_session_change_vt(struct wlr_session *session, unsigned vt);
|
||||||
ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
ssize_t wlr_session_find_gpus(struct wlr_session *session,
|
||||||
size_t ret_len, struct wlr_device **ret);
|
size_t ret_len, struct wlr_device **ret);
|
||||||
|
|
||||||
|
bool wlr_session_input_router_layer_register(int32_t priority);
|
||||||
|
|
||||||
|
struct wlr_session_input_router_layer *wlr_session_input_router_layer_create(
|
||||||
|
struct wlr_input_router *router, struct wlr_session *session);
|
||||||
|
|
||||||
|
void wlr_session_input_router_layer_destroy(
|
||||||
|
struct wlr_session_input_router_layer *layer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#define WLR_TYPES_WLR_DATA_DEVICE_H
|
#define WLR_TYPES_WLR_DATA_DEVICE_H
|
||||||
|
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
#include <wlr/types/wlr_seat.h>
|
#include <wlr/types/wlr_seat.h>
|
||||||
|
|
||||||
struct wlr_data_device_manager {
|
struct wlr_data_device_manager {
|
||||||
|
|
@ -151,6 +152,50 @@ struct wlr_drag_drop_event {
|
||||||
uint32_t time;
|
uint32_t time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum wlr_drag_input_router_layer_type {
|
||||||
|
WLR_DRAG_INPUT_ROUTER_LAYER_POINTER,
|
||||||
|
WLR_DRAG_INPUT_ROUTER_LAYER_TOUCH,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A data device drag input router layer which sends wl_data_device events based
|
||||||
|
* on the pointer or a touch point position and focus. It is automatically
|
||||||
|
* destroyed when the originating action (e.g. a button press) is reverted.
|
||||||
|
*/
|
||||||
|
struct wlr_drag_input_router_layer {
|
||||||
|
struct wlr_input_router *router;
|
||||||
|
struct wlr_input_router_implicit_grab *implicit_grab;
|
||||||
|
struct wlr_drag *drag;
|
||||||
|
|
||||||
|
enum wlr_drag_input_router_layer_type type;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
// Global position, hotspot is not included
|
||||||
|
double x, y;
|
||||||
|
} icon_position;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
struct wl_signal set_icon_position;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
struct wlr_input_router_pointer pointer;
|
||||||
|
uint32_t pointer_button;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
struct wlr_input_router_touch touch;
|
||||||
|
int32_t touch_id;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wl_listener router_destroy;
|
||||||
|
struct wl_listener drag_destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a wl_data_device_manager global for this display.
|
* Create a wl_data_device_manager global for this display.
|
||||||
*/
|
*/
|
||||||
|
|
@ -210,6 +255,20 @@ void wlr_seat_start_pointer_drag(struct wlr_seat *seat, struct wlr_drag *drag,
|
||||||
void wlr_seat_start_touch_drag(struct wlr_seat *seat, struct wlr_drag *drag,
|
void wlr_seat_start_touch_drag(struct wlr_seat *seat, struct wlr_drag *drag,
|
||||||
uint32_t serial, struct wlr_touch_point *point);
|
uint32_t serial, struct wlr_touch_point *point);
|
||||||
|
|
||||||
|
void wlr_drag_start(struct wlr_drag *drag);
|
||||||
|
|
||||||
|
void wlr_drag_enter(struct wlr_drag *drag, struct wlr_surface *surface,
|
||||||
|
double sx, double sy);
|
||||||
|
|
||||||
|
void wlr_drag_clear_focus(struct wlr_drag *drag);
|
||||||
|
|
||||||
|
void wlr_drag_send_motion(struct wlr_drag *drag, uint32_t time_msec,
|
||||||
|
double sx, double sy);
|
||||||
|
|
||||||
|
void wlr_drag_drop_and_destroy(struct wlr_drag *drag, uint32_t time_msec);
|
||||||
|
|
||||||
|
void wlr_drag_destroy(struct wlr_drag *drag);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the data source with the provided implementation.
|
* Initializes the data source with the provided implementation.
|
||||||
*/
|
*/
|
||||||
|
|
@ -261,4 +320,14 @@ void wlr_data_source_dnd_finish(struct wlr_data_source *source);
|
||||||
void wlr_data_source_dnd_action(struct wlr_data_source *source,
|
void wlr_data_source_dnd_action(struct wlr_data_source *source,
|
||||||
enum wl_data_device_manager_dnd_action action);
|
enum wl_data_device_manager_dnd_action action);
|
||||||
|
|
||||||
|
bool wlr_drag_input_router_layer_register(int32_t priority);
|
||||||
|
|
||||||
|
struct wlr_drag_input_router_layer *wlr_drag_input_router_layer_create_pointer(
|
||||||
|
struct wlr_input_router *router, struct wlr_drag *drag, uint32_t button);
|
||||||
|
|
||||||
|
struct wlr_drag_input_router_layer *wlr_drag_input_router_layer_create_touch(
|
||||||
|
struct wlr_input_router *router, struct wlr_drag *drag, int32_t id);
|
||||||
|
|
||||||
|
void wlr_drag_input_router_layer_destroy(struct wlr_drag_input_router_layer *layer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
#include <wlr/types/wlr_seat.h>
|
#include <wlr/types/wlr_seat.h>
|
||||||
#include <wlr/util/box.h>
|
#include <wlr/util/box.h>
|
||||||
|
|
||||||
|
struct wlr_text_input_v3;
|
||||||
|
|
||||||
struct wlr_input_method_v2_preedit_string {
|
struct wlr_input_method_v2_preedit_string {
|
||||||
char *text;
|
char *text;
|
||||||
int32_t cursor_begin;
|
int32_t cursor_begin;
|
||||||
|
|
@ -104,6 +106,43 @@ struct wlr_input_method_manager_v2 {
|
||||||
} WLR_PRIVATE;
|
} WLR_PRIVATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A zwp_input_method_v2 input router layer which redirects keyboard events to
|
||||||
|
* an active zwp_input_method_keyboard_grab_v2 object, if one exists. This layer
|
||||||
|
* detects virtual keyboard devices belonging to the input method client and
|
||||||
|
* does not process events from them.
|
||||||
|
*/
|
||||||
|
struct wlr_input_method_v2_input_router_layer {
|
||||||
|
struct wlr_input_router *router;
|
||||||
|
struct wlr_input_method_v2 *input_method;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wlr_input_router_keyboard keyboard;
|
||||||
|
|
||||||
|
struct wlr_input_method_keyboard_grab_v2 *grab;
|
||||||
|
bool device_grabbed;
|
||||||
|
|
||||||
|
uint32_t forwarded_keys[WLR_KEYBOARD_KEYS_CAP];
|
||||||
|
size_t n_forwarded_keys;
|
||||||
|
|
||||||
|
struct wlr_text_input_v3 *active_text_input;
|
||||||
|
|
||||||
|
struct wl_listener active_text_input_destroy;
|
||||||
|
struct wl_listener active_text_input_commit;
|
||||||
|
|
||||||
|
struct wl_listener input_method_destroy;
|
||||||
|
struct wl_listener input_method_commit;
|
||||||
|
struct wl_listener input_method_grab_keyboard;
|
||||||
|
|
||||||
|
struct wl_listener router_destroy;
|
||||||
|
struct wl_listener grab_destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
struct wlr_input_method_manager_v2 *wlr_input_method_manager_v2_create(
|
struct wlr_input_method_manager_v2 *wlr_input_method_manager_v2_create(
|
||||||
struct wl_display *display);
|
struct wl_display *display);
|
||||||
|
|
||||||
|
|
@ -147,4 +186,18 @@ void wlr_input_method_keyboard_grab_v2_set_keyboard(
|
||||||
void wlr_input_method_keyboard_grab_v2_destroy(
|
void wlr_input_method_keyboard_grab_v2_destroy(
|
||||||
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab);
|
struct wlr_input_method_keyboard_grab_v2 *keyboard_grab);
|
||||||
|
|
||||||
|
bool wlr_input_method_v2_input_router_layer_register(int32_t priority);
|
||||||
|
|
||||||
|
struct wlr_input_method_v2_input_router_layer *wlr_input_method_v2_input_router_layer_create(
|
||||||
|
struct wlr_input_router *router);
|
||||||
|
void wlr_input_method_v2_input_router_layer_destroy(
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer);
|
||||||
|
|
||||||
|
void wlr_input_method_v2_input_router_layer_set_input_method(
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer,
|
||||||
|
struct wlr_input_method_v2 *input_method);
|
||||||
|
void wlr_input_method_v2_input_router_layer_set_active_text_input(
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer,
|
||||||
|
struct wlr_text_input_v3 *text_input);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
551
include/wlr/types/wlr_input_router.h
Normal file
551
include/wlr/types/wlr_input_router.h
Normal file
|
|
@ -0,0 +1,551 @@
|
||||||
|
/*
|
||||||
|
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||||
|
* future consistency of this API.
|
||||||
|
*/
|
||||||
|
#ifndef WLR_USE_UNSTABLE
|
||||||
|
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WLR_TYPES_WLR_INPUT_ROUTER_H
|
||||||
|
#define WLR_TYPES_WLR_INPUT_ROUTER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <wayland-server-protocol.h>
|
||||||
|
|
||||||
|
#include <wlr/types/wlr_keyboard.h>
|
||||||
|
#include <wlr/types/wlr_pointer.h>
|
||||||
|
#include <wlr/util/addon.h>
|
||||||
|
|
||||||
|
#define WLR_INPUT_ROUTER_MAX_POINTER_BUTTONS 32
|
||||||
|
#define WLR_INPUT_ROUTER_MAX_TOUCH_POINTS 16
|
||||||
|
|
||||||
|
struct wlr_input_router_handler {
|
||||||
|
struct {
|
||||||
|
int32_t priority;
|
||||||
|
struct wlr_input_router_handler *head;
|
||||||
|
struct wlr_input_router_handler *next;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_handler_interface {
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A registry of input event handler interface priorities.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_handler_priority_list {
|
||||||
|
struct {
|
||||||
|
struct wl_array entries; // struct wlr_input_router_handler_priority_entry
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wlr_input_router_focus_type {
|
||||||
|
WLR_INPUT_ROUTER_FOCUS_NONE,
|
||||||
|
WLR_INPUT_ROUTER_FOCUS_SURFACE,
|
||||||
|
WLR_INPUT_ROUTER_FOCUS_USER,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A helper object to store focus information. When the underlying object is
|
||||||
|
* destroyed, the focus is automatically reset.
|
||||||
|
*
|
||||||
|
* Input router focus readers accept NULL, which is treated the same way as an
|
||||||
|
* empty focus.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_focus {
|
||||||
|
enum wlr_input_router_focus_type type;
|
||||||
|
union {
|
||||||
|
struct wlr_surface *surface;
|
||||||
|
struct {
|
||||||
|
void *user;
|
||||||
|
struct wl_signal *destroy_signal;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_listener destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router;
|
||||||
|
|
||||||
|
struct wlr_input_router_interface {
|
||||||
|
const char *name;
|
||||||
|
|
||||||
|
void (*at)(struct wlr_input_router *router, double x, double y,
|
||||||
|
struct wlr_input_router_focus *focus, double *local_x, double *local_y);
|
||||||
|
bool (*get_surface_position)(struct wlr_input_router *router,
|
||||||
|
struct wlr_surface *surface, double *x, double *y);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_keyboard;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event notifying of a new keyboard focus. It is not guaranteed that the focus
|
||||||
|
* has actually changed.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_keyboard_focus_event {
|
||||||
|
const struct wlr_input_router_focus *focus;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event notifying of a new active keyboard device.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_keyboard_device_event {
|
||||||
|
// May be NULL
|
||||||
|
struct wlr_keyboard *device;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event notifying of a key press or release. It is guaranteed that the current
|
||||||
|
* keyboard device is not NULL.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_keyboard_key_event {
|
||||||
|
uint32_t time_msec;
|
||||||
|
uint32_t key;
|
||||||
|
enum wl_keyboard_key_state state;
|
||||||
|
|
||||||
|
// If true, this event has already been consumed and should only be used for
|
||||||
|
// bookkeeping.
|
||||||
|
bool intercepted;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event notifying that the keyboard device modifiers have changed. It is
|
||||||
|
* guaranteed that the current keyboard device is not NULL.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_keyboard_modifiers_event {
|
||||||
|
struct {
|
||||||
|
char unused;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_keyboard_interface {
|
||||||
|
struct wlr_input_router_handler_interface base;
|
||||||
|
|
||||||
|
uint32_t (*focus)(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_focus_event *event);
|
||||||
|
void (*device)(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_device_event *event);
|
||||||
|
uint32_t (*key)(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_key_event *event);
|
||||||
|
void (*modifiers)(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_modifiers_event *event);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_keyboard {
|
||||||
|
struct wlr_input_router_handler base;
|
||||||
|
const struct wlr_input_router_keyboard_interface *impl;
|
||||||
|
|
||||||
|
struct wlr_input_router_focus focus;
|
||||||
|
struct wlr_keyboard *device;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_listener device_destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event notifying of a pointer position. The position is not guaranteed to
|
||||||
|
* be different from the previous one.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_pointer_position_event {
|
||||||
|
uint32_t time_msec;
|
||||||
|
|
||||||
|
double x, y;
|
||||||
|
const struct wlr_input_router_focus *focus;
|
||||||
|
/**
|
||||||
|
* If true, the focus provided with this event should be prioritized over
|
||||||
|
* focus determined by the handler implementation.
|
||||||
|
*/
|
||||||
|
bool explicit_focus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, this event has not been caused by a physical action.
|
||||||
|
*/
|
||||||
|
bool synthetic;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Components of pointer motion vectors. It is not guaranteed that (x - dx,
|
||||||
|
* y - dy) is equal to the previous position.
|
||||||
|
*/
|
||||||
|
double dx, dy;
|
||||||
|
double unaccel_dx, unaccel_dy;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event notifying of a pointer button press or release.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_pointer_button_event {
|
||||||
|
uint32_t time_msec;
|
||||||
|
|
||||||
|
uint32_t button;
|
||||||
|
enum wl_pointer_button_state state;
|
||||||
|
|
||||||
|
// The index of the button in the input router pointer, set automatically.
|
||||||
|
size_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer_axis_event {
|
||||||
|
uint32_t time_msec;
|
||||||
|
|
||||||
|
enum wl_pointer_axis_source source;
|
||||||
|
enum wl_pointer_axis orientation;
|
||||||
|
enum wl_pointer_axis_relative_direction relative_direction;
|
||||||
|
double delta;
|
||||||
|
int32_t delta_discrete;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer_frame_event {
|
||||||
|
struct {
|
||||||
|
char unused;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer;
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer_interface {
|
||||||
|
struct wlr_input_router_handler_interface base;
|
||||||
|
|
||||||
|
uint32_t (*position)(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_position_event *event);
|
||||||
|
uint32_t (*button)(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_button_event *event);
|
||||||
|
void (*axis)(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_axis_event *event);
|
||||||
|
void (*frame)(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_frame_event *event);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer_button {
|
||||||
|
uint32_t button;
|
||||||
|
// The number of times the button has been pressed.
|
||||||
|
uint32_t count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer {
|
||||||
|
struct wlr_input_router_handler base;
|
||||||
|
const struct wlr_input_router_pointer_interface *impl;
|
||||||
|
|
||||||
|
double x, y;
|
||||||
|
struct wlr_input_router_focus focus;
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer_button buttons[WLR_INPUT_ROUTER_MAX_POINTER_BUTTONS];
|
||||||
|
uint32_t n_buttons;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event notifying of a touch point position. The position is not guaranteed to
|
||||||
|
* be different from the previous one. id is guaranteed to abe a valid touch
|
||||||
|
* point ID.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_touch_position_event {
|
||||||
|
uint32_t time_msec;
|
||||||
|
int32_t id;
|
||||||
|
|
||||||
|
double x, y;
|
||||||
|
const struct wlr_input_router_focus *focus;
|
||||||
|
|
||||||
|
// The index of the touch point in the input router touch, set
|
||||||
|
// automatically.
|
||||||
|
size_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event notifying of a new touch point. id is guaranteed to be unique among
|
||||||
|
* all touch points. This event adds a touch point.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_touch_down_event {
|
||||||
|
uint32_t time_msec;
|
||||||
|
int32_t id;
|
||||||
|
|
||||||
|
double x, y;
|
||||||
|
const struct wlr_input_router_focus *focus;
|
||||||
|
|
||||||
|
// The index of the touch point in the input router touch, set
|
||||||
|
// automatically.
|
||||||
|
size_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event notifying that a touch point has disappeared. id is guaranteed to be
|
||||||
|
* a valid touch point ID. This event removes the touch point.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_touch_up_event {
|
||||||
|
uint32_t time_msec;
|
||||||
|
int32_t id;
|
||||||
|
|
||||||
|
// The index of the touch point in the input router touch, set
|
||||||
|
// automatically.
|
||||||
|
size_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event notifying that a touch point has been cancelled. id is guaranteed to be
|
||||||
|
* a valid touch point ID. This event removes the touch point.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_touch_cancel_event {
|
||||||
|
int32_t id;
|
||||||
|
|
||||||
|
// The index of the touch point in the input router touch, set
|
||||||
|
// automatically.
|
||||||
|
size_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_touch_frame_event {
|
||||||
|
struct {
|
||||||
|
char unused;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_touch;
|
||||||
|
|
||||||
|
struct wlr_input_router_touch_interface {
|
||||||
|
struct wlr_input_router_handler_interface base;
|
||||||
|
|
||||||
|
void (*position)(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_position_event *event);
|
||||||
|
uint32_t (*down)(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_down_event *event);
|
||||||
|
uint32_t (*up)(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_up_event *event);
|
||||||
|
void (*cancel)(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_cancel_event *event);
|
||||||
|
void (*frame)(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_frame_event *event);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_touch_point {
|
||||||
|
int32_t id;
|
||||||
|
|
||||||
|
double x, y;
|
||||||
|
struct wlr_input_router_focus focus;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_touch {
|
||||||
|
struct wlr_input_router_handler base;
|
||||||
|
const struct wlr_input_router_touch_interface *impl;
|
||||||
|
|
||||||
|
struct wlr_input_router_touch_point points[WLR_INPUT_ROUTER_MAX_TOUCH_POINTS];
|
||||||
|
size_t n_points;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An input router is an object which has keyboard, pointer, and touch event
|
||||||
|
* handler chains.
|
||||||
|
*
|
||||||
|
* Each handler can receive events and send events to the next handler in the
|
||||||
|
* chain. If the function in the handler interface responsible for handling
|
||||||
|
* events of a specific type is NULL, events of that type are automatically
|
||||||
|
* passed along to the next handler.
|
||||||
|
*
|
||||||
|
* When an input event handler is added, it's placed accordingly to its
|
||||||
|
* priority, which must be registered beforehand. The newly added handler copies
|
||||||
|
* the state from the next handler in the chain, if one exists.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router {
|
||||||
|
struct wlr_input_router_keyboard keyboard;
|
||||||
|
struct wlr_input_router_pointer pointer;
|
||||||
|
struct wlr_input_router_touch touch;
|
||||||
|
|
||||||
|
const struct wlr_input_router_interface *impl;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
struct wlr_addon_set addons;
|
||||||
|
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An input router focus layer which assigns focus for revelant pointer and
|
||||||
|
* touch events based on position.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_focus_layer {
|
||||||
|
struct wlr_input_router *router;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wlr_input_router_pointer pointer;
|
||||||
|
struct wlr_input_router_touch touch;
|
||||||
|
|
||||||
|
struct wlr_input_router_focus focus;
|
||||||
|
|
||||||
|
struct wl_listener router_destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_input_router_implicit_grab_layer_touch_point {
|
||||||
|
struct {
|
||||||
|
uint32_t serial;
|
||||||
|
struct wlr_input_router_focus focus;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An input router implicit grab layer which implements implicit grab semantics.
|
||||||
|
* For pointer, it means that the focus is locked if at least one button is
|
||||||
|
* pressed. For touch, it means the focus received with a new touch point always
|
||||||
|
* stays the same.
|
||||||
|
*/
|
||||||
|
struct wlr_input_router_implicit_grab_layer {
|
||||||
|
struct wlr_input_router *router;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wlr_input_router_pointer pointer;
|
||||||
|
struct wlr_input_router_focus pointer_focus;
|
||||||
|
uint32_t pointer_init_button;
|
||||||
|
uint32_t pointer_init_serial;
|
||||||
|
bool pointer_grabbed;
|
||||||
|
|
||||||
|
struct wlr_input_router_touch touch;
|
||||||
|
struct wlr_input_router_implicit_grab_layer_touch_point
|
||||||
|
touch_points[WLR_INPUT_ROUTER_MAX_TOUCH_POINTS];
|
||||||
|
|
||||||
|
struct wl_listener router_destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
void wlr_input_router_init(struct wlr_input_router *router,
|
||||||
|
const struct wlr_input_router_interface *impl);
|
||||||
|
void wlr_input_router_finish(struct wlr_input_router *router);
|
||||||
|
|
||||||
|
void wlr_input_router_focus_init(struct wlr_input_router_focus *focus);
|
||||||
|
void wlr_input_router_focus_finish(struct wlr_input_router_focus *focus);
|
||||||
|
|
||||||
|
bool wlr_input_router_focus_is_none(const struct wlr_input_router_focus *focus);
|
||||||
|
struct wlr_surface *wlr_input_router_focus_get_surface(
|
||||||
|
const struct wlr_input_router_focus *focus);
|
||||||
|
void *wlr_input_router_focus_get_user(const struct wlr_input_router_focus *focus);
|
||||||
|
|
||||||
|
void wlr_input_router_focus_clear(struct wlr_input_router_focus *focus);
|
||||||
|
void wlr_input_router_focus_set_surface(struct wlr_input_router_focus *focus,
|
||||||
|
struct wlr_surface *surface);
|
||||||
|
void wlr_input_router_focus_set_user(struct wlr_input_router_focus *focus,
|
||||||
|
void *user, struct wl_signal *destroy_signal);
|
||||||
|
|
||||||
|
void wlr_input_router_focus_copy(struct wlr_input_router_focus *dst,
|
||||||
|
const struct wlr_input_router_focus *src);
|
||||||
|
|
||||||
|
// TODO: this is only required by the focus layer, remove?
|
||||||
|
void wlr_input_router_at(struct wlr_input_router *router, double x, double y,
|
||||||
|
struct wlr_input_router_focus *focus, double *local_x, double *local_y);
|
||||||
|
|
||||||
|
bool wlr_input_router_get_surface_position(struct wlr_input_router *router,
|
||||||
|
struct wlr_surface *surface, double *x, double *y);
|
||||||
|
|
||||||
|
bool wlr_input_router_register_handler_interface(
|
||||||
|
const struct wlr_input_router_handler_interface *iface,
|
||||||
|
int32_t priority, struct wlr_input_router_handler_priority_list *priority_list);
|
||||||
|
|
||||||
|
void wlr_input_router_handler_init(struct wlr_input_router_handler *handler,
|
||||||
|
struct wlr_input_router_handler *head,
|
||||||
|
const struct wlr_input_router_handler_interface *impl,
|
||||||
|
const struct wlr_input_router_handler_priority_list *priority_list);
|
||||||
|
|
||||||
|
void wlr_input_router_handler_finish(struct wlr_input_router_handler *handler);
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_keyboard_notify_focus(
|
||||||
|
struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_focus_event *event);
|
||||||
|
|
||||||
|
void wlr_input_router_keyboard_notify_device(
|
||||||
|
struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_device_event *event);
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_keyboard_notify_key(
|
||||||
|
struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_key_event *event);
|
||||||
|
|
||||||
|
void wlr_input_router_keyboard_notify_modifiers(
|
||||||
|
struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_modifiers_event *event);
|
||||||
|
|
||||||
|
bool wlr_input_router_keyboard_register_interface(
|
||||||
|
const struct wlr_input_router_keyboard_interface *iface, int32_t priority);
|
||||||
|
|
||||||
|
void wlr_input_router_keyboard_init(
|
||||||
|
struct wlr_input_router_keyboard *handler, struct wlr_input_router *router,
|
||||||
|
const struct wlr_input_router_keyboard_interface *impl);
|
||||||
|
|
||||||
|
void wlr_input_router_keyboard_finish(struct wlr_input_router_keyboard *handler);
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_pointer_notify_position(
|
||||||
|
struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_position_event *event);
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_pointer_notify_button(
|
||||||
|
struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_button_event *event);
|
||||||
|
|
||||||
|
void wlr_input_router_pointer_notify_axis(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_axis_event *event);
|
||||||
|
|
||||||
|
void wlr_input_router_pointer_notify_frame(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_frame_event *event);
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_pointer_refresh_position(struct wlr_input_router_pointer *pointer);
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_pointer_clear_focus(struct wlr_input_router_pointer *pointer);
|
||||||
|
|
||||||
|
bool wlr_input_router_pointer_register_interface(
|
||||||
|
const struct wlr_input_router_pointer_interface *iface, int32_t priority);
|
||||||
|
|
||||||
|
void wlr_input_router_pointer_init(struct wlr_input_router_pointer *pointer,
|
||||||
|
struct wlr_input_router *router, const struct wlr_input_router_pointer_interface *impl);
|
||||||
|
void wlr_input_router_pointer_finish(struct wlr_input_router_pointer *pointer);
|
||||||
|
|
||||||
|
void wlr_input_router_touch_notify_position(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_position_event *event);
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_touch_notify_down(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_down_event *event);
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_touch_notify_up(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_up_event *event);
|
||||||
|
|
||||||
|
void wlr_input_router_touch_notify_cancel(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_cancel_event *event);
|
||||||
|
|
||||||
|
void wlr_input_router_touch_notify_frame(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_frame_event *event);
|
||||||
|
|
||||||
|
bool wlr_input_router_touch_register_interface(
|
||||||
|
const struct wlr_input_router_touch_interface *iface, int32_t priority);
|
||||||
|
|
||||||
|
void wlr_input_router_touch_init(struct wlr_input_router_touch *touch,
|
||||||
|
struct wlr_input_router *router, const struct wlr_input_router_touch_interface *impl);
|
||||||
|
void wlr_input_router_touch_finish(struct wlr_input_router_touch *touch);
|
||||||
|
|
||||||
|
bool wlr_input_router_focus_layer_register(int32_t priority);
|
||||||
|
|
||||||
|
struct wlr_input_router_focus_layer *wlr_input_router_focus_layer_create(
|
||||||
|
struct wlr_input_router *router);
|
||||||
|
void wlr_input_router_focus_layer_destroy(struct wlr_input_router_focus_layer *layer);
|
||||||
|
|
||||||
|
bool wlr_input_router_implicit_grab_layer_register(int32_t priority);
|
||||||
|
|
||||||
|
struct wlr_input_router_implicit_grab_layer *wlr_input_router_implicit_grab_layer_create(
|
||||||
|
struct wlr_input_router *router);
|
||||||
|
void wlr_input_router_implicit_grab_layer_destroy(
|
||||||
|
struct wlr_input_router_implicit_grab_layer *layer);
|
||||||
|
|
||||||
|
bool wlr_input_router_implicit_grab_layer_validate_pointer_serial(
|
||||||
|
struct wlr_input_router_implicit_grab_layer *layer, struct wlr_surface *origin,
|
||||||
|
uint32_t serial, uint32_t *button);
|
||||||
|
|
||||||
|
bool wlr_input_router_implicit_grab_layer_validate_touch_serial(
|
||||||
|
struct wlr_input_router_implicit_grab_layer *layer, struct wlr_surface *origin,
|
||||||
|
uint32_t serial, int32_t *id);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <pixman.h>
|
#include <pixman.h>
|
||||||
#include <wlr/types/wlr_compositor.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
#include <wlr/types/wlr_seat.h>
|
#include <wlr/types/wlr_seat.h>
|
||||||
#include "pointer-constraints-unstable-v1-protocol.h"
|
#include "pointer-constraints-unstable-v1-protocol.h"
|
||||||
|
|
||||||
|
|
@ -89,6 +90,53 @@ struct wlr_pointer_constraints_v1 {
|
||||||
} WLR_PRIVATE;
|
} WLR_PRIVATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A zwp_pointer_constraints_v1 input router layer which modifiers pointer
|
||||||
|
* position based on the constraint of an active surface.
|
||||||
|
*/
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer {
|
||||||
|
struct wlr_input_router *router;
|
||||||
|
struct wlr_pointer_constraints_v1 *constraints;
|
||||||
|
struct wlr_seat *seat;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted when a pointer lock with a cursor hint is unlocked. The
|
||||||
|
* compositor should then warp the pointer to the specified position.
|
||||||
|
*/
|
||||||
|
struct wl_signal cursor_hint;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wlr_input_router_pointer pointer;
|
||||||
|
|
||||||
|
struct wlr_surface *active_surface;
|
||||||
|
struct wlr_pointer_constraint_v1 *active;
|
||||||
|
|
||||||
|
double last_x, last_y;
|
||||||
|
double lock_sx, lock_sy;
|
||||||
|
bool lock_applied;
|
||||||
|
|
||||||
|
struct wl_listener active_surface_destroy;
|
||||||
|
|
||||||
|
struct wl_listener active_destroy;
|
||||||
|
struct wl_listener active_set_region;
|
||||||
|
|
||||||
|
struct wl_listener constraints_destroy;
|
||||||
|
struct wl_listener constraints_new_constraint;
|
||||||
|
|
||||||
|
struct wl_listener router_destroy;
|
||||||
|
struct wl_listener seat_destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer_cursor_hint_event {
|
||||||
|
// Global position to warp the pointer to
|
||||||
|
double x, y;
|
||||||
|
};
|
||||||
|
|
||||||
struct wlr_pointer_constraints_v1 *wlr_pointer_constraints_v1_create(
|
struct wlr_pointer_constraints_v1 *wlr_pointer_constraints_v1_create(
|
||||||
struct wl_display *display);
|
struct wl_display *display);
|
||||||
|
|
||||||
|
|
@ -105,4 +153,17 @@ void wlr_pointer_constraint_v1_send_activated(
|
||||||
void wlr_pointer_constraint_v1_send_deactivated(
|
void wlr_pointer_constraint_v1_send_deactivated(
|
||||||
struct wlr_pointer_constraint_v1 *constraint);
|
struct wlr_pointer_constraint_v1 *constraint);
|
||||||
|
|
||||||
|
bool wlr_pointer_constraints_v1_input_router_layer_register(int32_t priority);
|
||||||
|
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *
|
||||||
|
wlr_pointer_constraints_v1_input_router_layer_create(
|
||||||
|
struct wlr_input_router *router, struct wlr_pointer_constraints_v1 *constraints,
|
||||||
|
struct wlr_seat *seat);
|
||||||
|
void wlr_pointer_constraints_v1_input_router_layer_destroy(
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer);
|
||||||
|
|
||||||
|
void wlr_pointer_constraints_v1_input_router_layer_set_active_surface(
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer,
|
||||||
|
struct wlr_surface *surface);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#define WLR_TYPES_WLR_RELATIVE_POINTER_V1_H
|
#define WLR_TYPES_WLR_RELATIVE_POINTER_V1_H
|
||||||
|
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This protocol specifies a set of interfaces used for making clients able to
|
* This protocol specifies a set of interfaces used for making clients able to
|
||||||
|
|
@ -61,6 +62,29 @@ struct wlr_relative_pointer_v1 {
|
||||||
} WLR_PRIVATE;
|
} WLR_PRIVATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A zwp_relative_pointer_v1 input router layer which
|
||||||
|
* zwp_relative_pointer_v1.relative_motion events based on pointer position
|
||||||
|
* events.
|
||||||
|
*/
|
||||||
|
struct wlr_relative_pointer_v1_input_router_layer {
|
||||||
|
struct wlr_input_router *router;
|
||||||
|
struct wlr_relative_pointer_manager_v1 *manager;
|
||||||
|
struct wlr_seat *seat;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wlr_input_router_pointer pointer;
|
||||||
|
|
||||||
|
struct wl_listener router_destroy;
|
||||||
|
struct wl_listener manager_destroy;
|
||||||
|
struct wl_listener seat_destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
struct wlr_relative_pointer_manager_v1 *wlr_relative_pointer_manager_v1_create(
|
struct wlr_relative_pointer_manager_v1 *wlr_relative_pointer_manager_v1_create(
|
||||||
struct wl_display *display);
|
struct wl_display *display);
|
||||||
|
|
||||||
|
|
@ -79,4 +103,13 @@ void wlr_relative_pointer_manager_v1_send_relative_motion(
|
||||||
struct wlr_relative_pointer_v1 *wlr_relative_pointer_v1_from_resource(
|
struct wlr_relative_pointer_v1 *wlr_relative_pointer_v1_from_resource(
|
||||||
struct wl_resource *resource);
|
struct wl_resource *resource);
|
||||||
|
|
||||||
|
bool wlr_relative_pointer_v1_input_router_layer_register(int32_t priority);
|
||||||
|
|
||||||
|
struct wlr_relative_pointer_v1_input_router_layer *
|
||||||
|
wlr_relative_pointer_v1_input_router_layer_create(
|
||||||
|
struct wlr_input_router *router, struct wlr_relative_pointer_manager_v1 *manager,
|
||||||
|
struct wlr_seat *seat);
|
||||||
|
void wlr_relative_pointer_v1_input_router_layer_destroy(
|
||||||
|
struct wlr_relative_pointer_v1_input_router_layer *layer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
#include <wlr/types/wlr_input_device.h>
|
#include <wlr/types/wlr_input_device.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
#include <wlr/types/wlr_keyboard.h>
|
#include <wlr/types/wlr_keyboard.h>
|
||||||
#include <wlr/types/wlr_pointer.h>
|
#include <wlr/types/wlr_pointer.h>
|
||||||
|
|
||||||
|
|
@ -346,6 +347,39 @@ struct wlr_seat_keyboard_focus_change_event {
|
||||||
struct wlr_surface *old_surface, *new_surface;
|
struct wlr_surface *old_surface, *new_surface;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_seat_input_router_layer_touch_point {
|
||||||
|
struct {
|
||||||
|
struct wlr_seat_client *seat_client;
|
||||||
|
struct wl_listener seat_client_destroy;
|
||||||
|
wl_fixed_t sx, sy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wl_seat input router layer which sends wl_keyboard, wl_pointer, and
|
||||||
|
* wl_touch events.
|
||||||
|
*/
|
||||||
|
struct wlr_seat_input_router_layer {
|
||||||
|
struct wlr_input_router *router;
|
||||||
|
struct wlr_seat *seat;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wlr_input_router_keyboard keyboard;
|
||||||
|
struct wlr_input_router_pointer pointer;
|
||||||
|
|
||||||
|
struct wlr_input_router_touch touch;
|
||||||
|
struct wlr_seat_input_router_layer_touch_point
|
||||||
|
touch_points[WLR_INPUT_ROUTER_MAX_TOUCH_POINTS];
|
||||||
|
|
||||||
|
struct wl_listener router_destroy;
|
||||||
|
struct wl_listener seat_destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allocates a new struct wlr_seat and adds a wl_seat global to the display.
|
* Allocates a new struct wlr_seat and adds a wl_seat global to the display.
|
||||||
*/
|
*/
|
||||||
|
|
@ -762,4 +796,11 @@ struct wlr_seat_client *wlr_seat_client_from_pointer_resource(
|
||||||
*/
|
*/
|
||||||
bool wlr_surface_accepts_touch(struct wlr_surface *surface, struct wlr_seat *wlr_seat);
|
bool wlr_surface_accepts_touch(struct wlr_surface *surface, struct wlr_seat *wlr_seat);
|
||||||
|
|
||||||
|
bool wlr_seat_input_router_layer_register(int32_t priority);
|
||||||
|
|
||||||
|
struct wlr_seat_input_router_layer *wlr_seat_input_router_layer_create(
|
||||||
|
struct wlr_input_router *router, struct wlr_seat *seat);
|
||||||
|
void wlr_seat_input_router_layer_destroy(struct wlr_seat_input_router_layer *layer);
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
#define WLR_TYPES_WLR_TEXT_INPUT_V3_H
|
#define WLR_TYPES_WLR_TEXT_INPUT_V3_H
|
||||||
|
|
||||||
#include <wayland-server-core.h>
|
#include <wayland-server-core.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
#include <wlr/types/wlr_seat.h>
|
#include <wlr/types/wlr_seat.h>
|
||||||
#include <wlr/util/box.h>
|
#include <wlr/util/box.h>
|
||||||
|
|
||||||
|
|
@ -83,6 +84,40 @@ struct wlr_text_input_manager_v3 {
|
||||||
} WLR_PRIVATE;
|
} WLR_PRIVATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A zwp_text_input_v3 input router layer which synchronizes focuses of text
|
||||||
|
* inputs to the keyboard focus and tracks the currently active text input.
|
||||||
|
*/
|
||||||
|
struct wlr_text_input_v3_input_router_layer {
|
||||||
|
struct wlr_input_router *router;
|
||||||
|
struct wlr_text_input_manager_v3 *manager;
|
||||||
|
struct wlr_seat *seat;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
|
||||||
|
// struct wlr_text_input_v3_input_router_layer_set_active_event
|
||||||
|
struct wl_signal set_active_text_input;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wlr_input_router_keyboard keyboard;
|
||||||
|
|
||||||
|
struct wl_list text_inputs;
|
||||||
|
struct wlr_text_input_v3 *active_text_input;
|
||||||
|
|
||||||
|
struct wl_listener manager_destroy;
|
||||||
|
struct wl_listener manager_text_input;
|
||||||
|
|
||||||
|
struct wl_listener router_destroy;
|
||||||
|
struct wl_listener seat_destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_text_input_v3_input_router_layer_set_active_event {
|
||||||
|
struct wlr_text_input_v3 *active_text_input;
|
||||||
|
};
|
||||||
|
|
||||||
struct wlr_text_input_manager_v3 *wlr_text_input_manager_v3_create(
|
struct wlr_text_input_manager_v3 *wlr_text_input_manager_v3_create(
|
||||||
struct wl_display *wl_display);
|
struct wl_display *wl_display);
|
||||||
|
|
||||||
|
|
@ -100,4 +135,12 @@ void wlr_text_input_v3_send_delete_surrounding_text(
|
||||||
uint32_t after_length);
|
uint32_t after_length);
|
||||||
void wlr_text_input_v3_send_done(struct wlr_text_input_v3 *text_input);
|
void wlr_text_input_v3_send_done(struct wlr_text_input_v3 *text_input);
|
||||||
|
|
||||||
|
bool wlr_text_input_v3_input_router_layer_register(int32_t priority);
|
||||||
|
|
||||||
|
struct wlr_text_input_v3_input_router_layer *wlr_text_input_v3_input_router_layer_create(
|
||||||
|
struct wlr_input_router *router, struct wlr_text_input_manager_v3 *manager,
|
||||||
|
struct wlr_seat *seat);
|
||||||
|
void wlr_text_input_v3_input_router_layer_destroy(
|
||||||
|
struct wlr_text_input_v3_input_router_layer *layer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ struct wlr_xdg_shell {
|
||||||
struct wl_signal new_surface; // struct wlr_xdg_surface
|
struct wl_signal new_surface; // struct wlr_xdg_surface
|
||||||
struct wl_signal new_toplevel; // struct wlr_xdg_toplevel
|
struct wl_signal new_toplevel; // struct wlr_xdg_toplevel
|
||||||
struct wl_signal new_popup; // struct wlr_xdg_popup
|
struct wl_signal new_popup; // struct wlr_xdg_popup
|
||||||
|
struct wl_signal popup_grab; // struct wlr_xdg_shell_popup_grab_event
|
||||||
struct wl_signal destroy;
|
struct wl_signal destroy;
|
||||||
} events;
|
} events;
|
||||||
|
|
||||||
|
|
@ -36,6 +37,12 @@ struct wlr_xdg_shell {
|
||||||
} WLR_PRIVATE;
|
} WLR_PRIVATE;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct wlr_xdg_shell_popup_grab_event {
|
||||||
|
struct wlr_xdg_popup *popup;
|
||||||
|
struct wlr_seat_client *seat_client;
|
||||||
|
uint32_t serial;
|
||||||
|
};
|
||||||
|
|
||||||
struct wlr_xdg_client {
|
struct wlr_xdg_client {
|
||||||
struct wlr_xdg_shell *shell;
|
struct wlr_xdg_shell *shell;
|
||||||
struct wl_resource *resource;
|
struct wl_resource *resource;
|
||||||
|
|
@ -340,6 +347,32 @@ struct wlr_xdg_toplevel_show_window_menu_event {
|
||||||
int32_t x, y;
|
int32_t x, y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A input router layer which implements xdg_popup.grab semantics. It is
|
||||||
|
* destroyed automatically when the grab is dismissed.
|
||||||
|
*/
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer {
|
||||||
|
struct wlr_input_router *router;
|
||||||
|
struct wlr_xdg_popup *popup;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wl_signal destroy;
|
||||||
|
} events;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct wlr_input_router_keyboard keyboard;
|
||||||
|
struct wlr_input_router_focus keyboard_focus;
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer pointer;
|
||||||
|
|
||||||
|
struct wlr_input_router_touch touch;
|
||||||
|
|
||||||
|
struct wlr_addon router_addon;
|
||||||
|
|
||||||
|
struct wl_listener popup_destroy;
|
||||||
|
} WLR_PRIVATE;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the xdg_wm_base global with the specified version.
|
* Create the xdg_wm_base global with the specified version.
|
||||||
*/
|
*/
|
||||||
|
|
@ -580,4 +613,12 @@ void wlr_xdg_surface_for_each_popup_surface(struct wlr_xdg_surface *surface,
|
||||||
*/
|
*/
|
||||||
uint32_t wlr_xdg_surface_schedule_configure(struct wlr_xdg_surface *surface);
|
uint32_t wlr_xdg_surface_schedule_configure(struct wlr_xdg_surface *surface);
|
||||||
|
|
||||||
|
bool wlr_xdg_popup_grab_input_router_layer_register(int32_t priority);
|
||||||
|
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *wlr_xdg_popup_grab_input_router_layer_get_or_create(
|
||||||
|
struct wlr_input_router *router, struct wlr_xdg_popup *popup);
|
||||||
|
|
||||||
|
void wlr_xdg_popup_grab_input_router_layer_destroy(
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *layer);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include "types/wlr_data_device.h"
|
#include "types/wlr_data_device.h"
|
||||||
|
|
||||||
|
// TODO: drop seat grabs
|
||||||
|
|
||||||
static void drag_handle_seat_client_destroy(struct wl_listener *listener,
|
static void drag_handle_seat_client_destroy(struct wl_listener *listener,
|
||||||
void *data) {
|
void *data) {
|
||||||
struct wlr_drag *drag =
|
struct wlr_drag *drag =
|
||||||
|
|
@ -539,3 +541,54 @@ void wlr_seat_start_touch_drag(struct wlr_seat *seat, struct wlr_drag *drag,
|
||||||
|
|
||||||
wlr_seat_start_drag(seat, drag, serial);
|
wlr_seat_start_drag(seat, drag, serial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wlr_drag_start(struct wlr_drag *drag) {
|
||||||
|
wlr_seat_start_drag(drag->seat, drag, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drag_enter(struct wlr_drag *drag, struct wlr_surface *surface,
|
||||||
|
double sx, double sy) {
|
||||||
|
drag_set_focus(drag, surface, sx, sy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drag_clear_focus(struct wlr_drag *drag) {
|
||||||
|
drag_set_focus(drag, NULL, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drag_send_motion(struct wlr_drag *drag, uint32_t time_msec,
|
||||||
|
double sx, double sy) {
|
||||||
|
if (drag->focus != NULL && drag->focus_client != NULL) {
|
||||||
|
struct wl_resource *resource;
|
||||||
|
wl_resource_for_each(resource, &drag->focus_client->data_devices) {
|
||||||
|
wl_data_device_send_motion(resource, time_msec, wl_fixed_from_double(sx),
|
||||||
|
wl_fixed_from_double(sy));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drag_motion_event event = {
|
||||||
|
.drag = drag,
|
||||||
|
.time = time_msec,
|
||||||
|
.sx = sx,
|
||||||
|
.sy = sy,
|
||||||
|
};
|
||||||
|
wl_signal_emit_mutable(&drag->events.motion, &event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drag_drop_and_destroy(struct wlr_drag *drag, uint32_t time_msec) {
|
||||||
|
if (drag->source != NULL) {
|
||||||
|
if (drag->focus_client != NULL && drag->source->current_dnd_action &&
|
||||||
|
drag->source->accepted) {
|
||||||
|
drag_drop(drag, time_msec);
|
||||||
|
} else if (drag->source->impl->dnd_finish) {
|
||||||
|
// This will end the grab and free `drag`
|
||||||
|
wlr_data_source_destroy(drag->source);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drag_destroy(drag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drag_destroy(struct wlr_drag *drag) {
|
||||||
|
drag_destroy(drag);
|
||||||
|
}
|
||||||
|
|
|
||||||
250
types/input_router/drag.c
Normal file
250
types/input_router/drag.c
Normal file
|
|
@ -0,0 +1,250 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/types/wlr_compositor.h>
|
||||||
|
#include <wlr/types/wlr_data_device.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
static void update_position(struct wlr_drag_input_router_layer *layer, bool synthetic,
|
||||||
|
uint32_t time_msec, const struct wlr_input_router_focus *focus, double x, double y) {
|
||||||
|
struct wlr_surface *surface = wlr_input_router_focus_get_surface(focus);
|
||||||
|
double sx = 0, sy = 0;
|
||||||
|
|
||||||
|
if (surface != NULL) {
|
||||||
|
double surface_x, surface_y;
|
||||||
|
if (!wlr_input_router_get_surface_position(layer->router, surface,
|
||||||
|
&surface_x, &surface_y)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
sx = x - surface_x;
|
||||||
|
sy = y - surface_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// One of these will short-circuit
|
||||||
|
wlr_drag_enter(layer->drag, surface, sx, sy);
|
||||||
|
wlr_drag_send_motion(layer->drag, time_msec, sx, sy);
|
||||||
|
|
||||||
|
out:
|
||||||
|
if (layer->icon_position.x != x || layer->icon_position.y != y) {
|
||||||
|
layer->icon_position.x = x;
|
||||||
|
layer->icon_position.y = y;
|
||||||
|
}
|
||||||
|
wl_signal_emit_mutable(&layer->events.set_icon_position, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t pointer_position(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_position_event *event) {
|
||||||
|
struct wlr_drag_input_router_layer *layer = wl_container_of(pointer, layer, pointer);
|
||||||
|
update_position(layer, false, event->time_msec, event->focus, event->x, event->y);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t pointer_button(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_button_event *event) {
|
||||||
|
struct wlr_drag_input_router_layer *layer = wl_container_of(pointer, layer, pointer);
|
||||||
|
uint32_t serial = wlr_input_router_pointer_notify_button(pointer, event);
|
||||||
|
|
||||||
|
if (event->button == layer->pointer_button &&
|
||||||
|
event->state == WL_POINTER_BUTTON_STATE_RELEASED) {
|
||||||
|
wlr_drag_drop_and_destroy(layer->drag, event->time_msec);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pointer_axis(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_axis_event *event) {
|
||||||
|
// Consumed
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pointer_frame(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_frame_event *event) {
|
||||||
|
// Consumed
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_pointer_interface pointer_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_drag_input_router_layer-pointer",
|
||||||
|
},
|
||||||
|
.position = pointer_position,
|
||||||
|
.button = pointer_button,
|
||||||
|
.axis = pointer_axis,
|
||||||
|
.frame = pointer_frame,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void touch_position(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_position_event *event) {
|
||||||
|
struct wlr_drag_input_router_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
if (event->id == layer->touch_id) {
|
||||||
|
update_position(layer, false, event->time_msec, event->focus, event->x, event->y);
|
||||||
|
} else {
|
||||||
|
wlr_input_router_touch_notify_position(touch, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t touch_down(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_down_event *event) {
|
||||||
|
struct wlr_drag_input_router_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
assert(event->id != layer->touch_id);
|
||||||
|
return wlr_input_router_touch_notify_down(touch, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t touch_up(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_up_event *event) {
|
||||||
|
struct wlr_drag_input_router_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
if (event->id == layer->touch_id) {
|
||||||
|
wlr_drag_drop_and_destroy(layer->drag, event->time_msec);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return wlr_input_router_touch_notify_up(touch, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touch_cancel(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_cancel_event *event) {
|
||||||
|
struct wlr_drag_input_router_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
if (event->id == layer->touch_id) {
|
||||||
|
wlr_drag_destroy(layer->drag);
|
||||||
|
} else {
|
||||||
|
wlr_input_router_touch_notify_cancel(touch, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touch_frame(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_frame_event *event) {
|
||||||
|
// Consumed
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_touch_interface touch_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_drag_input_router_layer-touch",
|
||||||
|
},
|
||||||
|
.position = touch_position,
|
||||||
|
.down = touch_down,
|
||||||
|
.up = touch_up,
|
||||||
|
.cancel = touch_cancel,
|
||||||
|
.frame = touch_frame,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_router_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_drag_input_router_layer *layer = wl_container_of(listener, layer, router_destroy);
|
||||||
|
wlr_drag_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_drag_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_drag_input_router_layer *layer = wl_container_of(listener, layer, drag_destroy);
|
||||||
|
wlr_drag_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wlr_drag_input_router_layer *layer_create(struct wlr_input_router *router,
|
||||||
|
struct wlr_drag *drag, enum wlr_drag_input_router_layer_type type) {
|
||||||
|
struct wlr_drag_input_router_layer *layer = calloc(1, sizeof(*layer));
|
||||||
|
if (layer == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->router = router;
|
||||||
|
layer->router_destroy.notify = handle_router_destroy;
|
||||||
|
wl_signal_add(&router->events.destroy, &layer->router_destroy);
|
||||||
|
|
||||||
|
layer->drag = drag;
|
||||||
|
layer->drag_destroy.notify = handle_drag_destroy;
|
||||||
|
wl_signal_add(&drag->events.destroy, &layer->drag_destroy);
|
||||||
|
|
||||||
|
wl_signal_init(&layer->events.destroy);
|
||||||
|
wl_signal_init(&layer->events.set_icon_position);
|
||||||
|
|
||||||
|
layer->icon_position.x = NAN;
|
||||||
|
layer->icon_position.y = NAN;
|
||||||
|
|
||||||
|
layer->type = type;
|
||||||
|
|
||||||
|
wlr_drag_start(drag);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case WLR_DRAG_INPUT_ROUTER_LAYER_POINTER:
|
||||||
|
wlr_input_router_pointer_init(&layer->pointer, router, &pointer_impl);
|
||||||
|
wlr_input_router_pointer_clear_focus(&layer->pointer);
|
||||||
|
update_position(layer, 0, true, &layer->pointer.focus,
|
||||||
|
layer->pointer.x, layer->pointer.y);
|
||||||
|
break;
|
||||||
|
case WLR_DRAG_INPUT_ROUTER_LAYER_TOUCH:
|
||||||
|
wlr_input_router_touch_init(&layer->touch, router, &touch_impl);
|
||||||
|
wlr_input_router_touch_notify_cancel(&layer->touch,
|
||||||
|
&(struct wlr_input_router_touch_cancel_event){
|
||||||
|
.id = layer->touch_id,
|
||||||
|
});
|
||||||
|
for (size_t i = 0; i < layer->touch.n_points; i++) {
|
||||||
|
struct wlr_input_router_touch_point *point = &layer->touch.points[i];
|
||||||
|
if (point != NULL) {
|
||||||
|
update_position(layer, 0, true, &point->focus, point->x, point->y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_drag_input_router_layer_register(int32_t priority) {
|
||||||
|
if (!wlr_input_router_pointer_register_interface(&pointer_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_input_router_touch_register_interface(&touch_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drag_input_router_layer *wlr_drag_input_router_layer_create_pointer(
|
||||||
|
struct wlr_input_router *router, struct wlr_drag *drag, uint32_t button) {
|
||||||
|
struct wlr_drag_input_router_layer *layer =
|
||||||
|
layer_create(router, drag, WLR_DRAG_INPUT_ROUTER_LAYER_POINTER);
|
||||||
|
if (layer == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
layer->pointer_button = button;
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drag_input_router_layer *wlr_drag_input_router_layer_create_touch(
|
||||||
|
struct wlr_input_router *router, struct wlr_drag *drag, int32_t id) {
|
||||||
|
struct wlr_drag_input_router_layer *layer =
|
||||||
|
layer_create(router, drag, WLR_DRAG_INPUT_ROUTER_LAYER_TOUCH);
|
||||||
|
if (layer == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
layer->touch_id = id;
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drag_input_router_layer_destroy(struct wlr_drag_input_router_layer *layer) {
|
||||||
|
if (layer == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_emit_mutable(&layer->events.destroy, NULL);
|
||||||
|
|
||||||
|
assert(wl_list_empty(&layer->events.destroy.listener_list));
|
||||||
|
assert(wl_list_empty(&layer->events.set_icon_position.listener_list));
|
||||||
|
|
||||||
|
switch (layer->type) {
|
||||||
|
case WLR_DRAG_INPUT_ROUTER_LAYER_POINTER:
|
||||||
|
wlr_input_router_pointer_refresh_position(&layer->pointer);
|
||||||
|
wlr_input_router_pointer_finish(&layer->pointer);
|
||||||
|
break;
|
||||||
|
case WLR_DRAG_INPUT_ROUTER_LAYER_TOUCH:
|
||||||
|
wlr_input_router_touch_finish(&layer->touch);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_remove(&layer->router_destroy.link);
|
||||||
|
wl_list_remove(&layer->drag_destroy.link);
|
||||||
|
|
||||||
|
free(layer);
|
||||||
|
}
|
||||||
114
types/input_router/focus.c
Normal file
114
types/input_router/focus.c
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
static void update_focus(struct wlr_input_router_focus_layer *layer, double x, double y) {
|
||||||
|
wlr_input_router_at(layer->router, x, y, &layer->focus, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t pointer_position(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_position_event *event) {
|
||||||
|
struct wlr_input_router_focus_layer *layer = wl_container_of(pointer, layer, pointer);
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer_position_event copy;
|
||||||
|
if (!event->explicit_focus) {
|
||||||
|
update_focus(layer, event->x, event->y);
|
||||||
|
copy = *event;
|
||||||
|
copy.focus = &layer->focus;
|
||||||
|
event = ©
|
||||||
|
}
|
||||||
|
return wlr_input_router_pointer_notify_position(pointer, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_pointer_interface pointer_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_input_router_focus_layer-pointer",
|
||||||
|
},
|
||||||
|
.position = pointer_position,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void touch_position(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_position_event *event) {
|
||||||
|
struct wlr_input_router_focus_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
update_focus(layer, event->x, event->y);
|
||||||
|
|
||||||
|
struct wlr_input_router_touch_position_event relayed = *event;
|
||||||
|
relayed.focus = &layer->focus;
|
||||||
|
wlr_input_router_touch_notify_position(touch, &relayed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t touch_down(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_down_event *event) {
|
||||||
|
struct wlr_input_router_focus_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
update_focus(layer, event->x, event->y);
|
||||||
|
|
||||||
|
struct wlr_input_router_touch_down_event relayed = *event;
|
||||||
|
relayed.focus = &layer->focus;
|
||||||
|
return wlr_input_router_touch_notify_down(touch, &relayed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_touch_interface touch_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_input_router_focus_layer-touch",
|
||||||
|
},
|
||||||
|
.position = touch_position,
|
||||||
|
.down = touch_down,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_router_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_input_router_focus_layer *layer = wl_container_of(listener, layer, router_destroy);
|
||||||
|
wlr_input_router_focus_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_input_router_focus_layer_register(int32_t priority) {
|
||||||
|
if (!wlr_input_router_pointer_register_interface(&pointer_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_input_router_touch_register_interface(&touch_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_input_router_focus_layer *wlr_input_router_focus_layer_create(
|
||||||
|
struct wlr_input_router *router) {
|
||||||
|
struct wlr_input_router_focus_layer *layer = calloc(1, sizeof(*layer));
|
||||||
|
if (layer == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_pointer_init(&layer->pointer, router, &pointer_impl);
|
||||||
|
wlr_input_router_touch_init(&layer->touch, router, &touch_impl);
|
||||||
|
|
||||||
|
wlr_input_router_focus_init(&layer->focus);
|
||||||
|
|
||||||
|
layer->router = router;
|
||||||
|
layer->router_destroy.notify = handle_router_destroy;
|
||||||
|
wl_signal_add(&router->events.destroy, &layer->router_destroy);
|
||||||
|
|
||||||
|
wl_signal_init(&layer->events.destroy);
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_focus_layer_destroy(struct wlr_input_router_focus_layer *layer) {
|
||||||
|
if (layer == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_emit_mutable(&layer->events.destroy, NULL);
|
||||||
|
|
||||||
|
assert(wl_list_empty(&layer->events.destroy.listener_list));
|
||||||
|
|
||||||
|
wlr_input_router_pointer_finish(&layer->pointer);
|
||||||
|
wlr_input_router_touch_finish(&layer->touch);
|
||||||
|
|
||||||
|
wlr_input_router_focus_finish(&layer->focus);
|
||||||
|
|
||||||
|
wl_list_remove(&layer->router_destroy.link);
|
||||||
|
|
||||||
|
free(layer);
|
||||||
|
|
||||||
|
}
|
||||||
206
types/input_router/implicit_grab.c
Normal file
206
types/input_router/implicit_grab.c
Normal file
|
|
@ -0,0 +1,206 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
static uint32_t pointer_position(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_position_event *event) {
|
||||||
|
struct wlr_input_router_implicit_grab_layer *layer = wl_container_of(pointer, layer, pointer);
|
||||||
|
|
||||||
|
if (event->explicit_focus) {
|
||||||
|
// Invalidate implicit grab serial: the grab is no longer implicit
|
||||||
|
layer->pointer_init_serial = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer_position_event copy;
|
||||||
|
if (!event->explicit_focus && layer->pointer_grabbed) {
|
||||||
|
copy = *event;
|
||||||
|
copy.focus = &layer->pointer_focus;
|
||||||
|
event = ©
|
||||||
|
} else {
|
||||||
|
wlr_input_router_focus_copy(&layer->pointer_focus, event->focus);
|
||||||
|
}
|
||||||
|
return wlr_input_router_pointer_notify_position(pointer, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t pointer_button(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_button_event *event) {
|
||||||
|
struct wlr_input_router_implicit_grab_layer *layer = wl_container_of(pointer, layer, pointer);
|
||||||
|
|
||||||
|
uint32_t serial = wlr_input_router_pointer_notify_button(pointer, event);
|
||||||
|
|
||||||
|
if (event->state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||||
|
if (pointer->n_buttons == 1) {
|
||||||
|
layer->pointer_grabbed = true;
|
||||||
|
layer->pointer_init_button = event->button;
|
||||||
|
layer->pointer_init_serial = serial;
|
||||||
|
} else {
|
||||||
|
// Ensure we didn't miss the first button press event
|
||||||
|
assert(layer->pointer_grabbed);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (event->button == layer->pointer_init_button) {
|
||||||
|
// Invalidate implicit grab serial: the furst button has been released
|
||||||
|
layer->pointer_init_serial = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointer->n_buttons == 0) {
|
||||||
|
// Ensure we didn't miss the first button release event
|
||||||
|
assert(layer->pointer_init_serial == 0);
|
||||||
|
layer->pointer_grabbed = false;
|
||||||
|
wlr_input_router_pointer_refresh_position(pointer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_pointer_interface pointer_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_input_router_implicit_grab_layer-pointer",
|
||||||
|
},
|
||||||
|
.position = pointer_position,
|
||||||
|
.button = pointer_button,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void touch_position(struct wlr_input_router_touch *pointer,
|
||||||
|
const struct wlr_input_router_touch_position_event *event) {
|
||||||
|
struct wlr_input_router_implicit_grab_layer *layer =
|
||||||
|
wl_container_of(pointer, layer, touch);
|
||||||
|
|
||||||
|
struct wlr_input_router_touch_position_event relayed = *event;
|
||||||
|
relayed.focus = &layer->touch_points[event->index].focus;
|
||||||
|
wlr_input_router_touch_notify_position(pointer, &relayed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t touch_down(struct wlr_input_router_touch *pointer,
|
||||||
|
const struct wlr_input_router_touch_down_event *event) {
|
||||||
|
struct wlr_input_router_implicit_grab_layer *layer =
|
||||||
|
wl_container_of(pointer, layer, touch);
|
||||||
|
|
||||||
|
uint32_t serial = wlr_input_router_touch_notify_down(pointer, event);
|
||||||
|
|
||||||
|
struct wlr_input_router_implicit_grab_layer_touch_point *point =
|
||||||
|
&layer->touch_points[event->index];
|
||||||
|
point->serial = serial;
|
||||||
|
wlr_input_router_focus_copy(&point->focus, event->focus);
|
||||||
|
|
||||||
|
return serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_touch_interface touch_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_input_router_implicit_grab_layer-touch",
|
||||||
|
},
|
||||||
|
.position = touch_position,
|
||||||
|
.down = touch_down,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_router_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_input_router_implicit_grab_layer *layer =
|
||||||
|
wl_container_of(listener, layer, router_destroy);
|
||||||
|
wlr_input_router_implicit_grab_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_input_router_implicit_grab_layer_validate_pointer_serial(
|
||||||
|
struct wlr_input_router_implicit_grab_layer *layer, struct wlr_surface *origin,
|
||||||
|
uint32_t serial, uint32_t *button) {
|
||||||
|
if (serial == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layer->pointer_init_serial != serial) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (origin != NULL && origin != wlr_input_router_focus_get_surface(&layer->pointer_focus)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (button != NULL) {
|
||||||
|
*button = layer->pointer_init_button;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_input_router_implicit_grab_layer_validate_touch_serial(
|
||||||
|
struct wlr_input_router_implicit_grab_layer *layer, struct wlr_surface *origin,
|
||||||
|
uint32_t serial, int32_t *id) {
|
||||||
|
if (serial == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < layer->touch.n_points; i++) {
|
||||||
|
struct wlr_input_router_implicit_grab_layer_touch_point *point = &layer->touch_points[i];
|
||||||
|
if (layer->touch_points[i].serial != serial) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (origin != NULL && origin != wlr_input_router_focus_get_surface(&point->focus)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id != NULL) {
|
||||||
|
*id = layer->touch.points[i].id;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_input_router_implicit_grab_layer_register(int32_t priority) {
|
||||||
|
if (!wlr_input_router_pointer_register_interface(&pointer_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_input_router_touch_register_interface(&touch_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_input_router_implicit_grab_layer *wlr_input_router_implicit_grab_layer_create(
|
||||||
|
struct wlr_input_router *router) {
|
||||||
|
struct wlr_input_router_implicit_grab_layer *layer = calloc(1, sizeof(*layer));
|
||||||
|
if (layer == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_pointer_init(&layer->pointer, router, &pointer_impl);
|
||||||
|
wlr_input_router_focus_init(&layer->pointer_focus);
|
||||||
|
|
||||||
|
wlr_input_router_touch_init(&layer->touch, router, &touch_impl);
|
||||||
|
for (size_t i = 0; i < WLR_INPUT_ROUTER_MAX_TOUCH_POINTS; i++) {
|
||||||
|
wlr_input_router_focus_init(&layer->touch_points[i].focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->router = router;
|
||||||
|
layer->router_destroy.notify = handle_router_destroy;
|
||||||
|
wl_signal_add(&router->events.destroy, &layer->router_destroy);
|
||||||
|
|
||||||
|
wl_signal_init(&layer->events.destroy);
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_implicit_grab_layer_destroy(
|
||||||
|
struct wlr_input_router_implicit_grab_layer *layer) {
|
||||||
|
if (layer == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_emit_mutable(&layer->events.destroy, NULL);
|
||||||
|
|
||||||
|
assert(wl_list_empty(&layer->events.destroy.listener_list));
|
||||||
|
|
||||||
|
wlr_input_router_pointer_finish(&layer->pointer);
|
||||||
|
wlr_input_router_focus_finish(&layer->pointer_focus);
|
||||||
|
|
||||||
|
wlr_input_router_touch_finish(&layer->touch);
|
||||||
|
for (size_t i = 0; i < WLR_INPUT_ROUTER_MAX_TOUCH_POINTS; i++) {
|
||||||
|
wlr_input_router_focus_finish(&layer->touch_points[i].focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_remove(&layer->router_destroy.link);
|
||||||
|
|
||||||
|
free(layer);
|
||||||
|
}
|
||||||
409
types/input_router/input_method.c
Normal file
409
types/input_router/input_method.c
Normal file
|
|
@ -0,0 +1,409 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/types/wlr_input_method_v2.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/types/wlr_seat.h>
|
||||||
|
#include <wlr/types/wlr_text_input_v3.h>
|
||||||
|
#include <wlr/types/wlr_virtual_keyboard_v1.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
struct text_input {
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer;
|
||||||
|
struct wlr_text_input_v3 *wlr_text_input;
|
||||||
|
|
||||||
|
struct wl_list link;
|
||||||
|
|
||||||
|
struct wl_listener destroy;
|
||||||
|
struct wl_listener enable;
|
||||||
|
struct wl_listener disable;
|
||||||
|
struct wl_listener commit;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void update_device_grab(struct wlr_input_method_v2_input_router_layer *layer) {
|
||||||
|
layer->device_grabbed = false;
|
||||||
|
struct wlr_keyboard *device = layer->keyboard.device;
|
||||||
|
if (layer->grab == NULL || device == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_virtual_keyboard_v1 *virtual_device =
|
||||||
|
wlr_input_device_get_virtual_keyboard(&device->base);
|
||||||
|
if (virtual_device != NULL && wl_resource_get_client(virtual_device->resource) ==
|
||||||
|
wl_resource_get_client(layer->grab->resource)) {
|
||||||
|
// The current device is a virtual keyboard created by the input method
|
||||||
|
// client to relay events to other clients, don't grab it
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->device_grabbed = true;
|
||||||
|
if (layer->grab->keyboard != device) {
|
||||||
|
wlr_input_method_keyboard_grab_v2_set_keyboard(layer->grab, device);
|
||||||
|
|
||||||
|
// We can't relay the effective keyboard state without
|
||||||
|
// zwp_input_method_keyboard_grab_v2.key.
|
||||||
|
layer->n_forwarded_keys = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if needs wlr_input_method_v2_send_done() afterwards
|
||||||
|
static bool update_input_method_active(struct wlr_input_method_v2_input_router_layer *layer) {
|
||||||
|
assert(layer->input_method != NULL);
|
||||||
|
|
||||||
|
bool active = layer->active_text_input != NULL;
|
||||||
|
if (layer->input_method->active != active) {
|
||||||
|
if (active) {
|
||||||
|
wlr_input_method_v2_send_activate(layer->input_method);
|
||||||
|
} else {
|
||||||
|
wlr_input_method_v2_send_deactivate(layer->input_method);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if needs wlr_input_method_v2_send_done() afterwards
|
||||||
|
static bool active_text_input_state(struct wlr_input_method_v2_input_router_layer *layer,
|
||||||
|
bool send_full) {
|
||||||
|
assert(layer->input_method != NULL);
|
||||||
|
|
||||||
|
struct wlr_text_input_v3 *text_input = layer->active_text_input;
|
||||||
|
if (text_input == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
struct wlr_text_input_v3_state *state = &text_input->current;
|
||||||
|
|
||||||
|
bool sent = false;
|
||||||
|
if (send_full) {
|
||||||
|
if (text_input->active_features & WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT) {
|
||||||
|
wlr_input_method_v2_send_surrounding_text(layer->input_method,
|
||||||
|
state->surrounding.text, state->surrounding.cursor, state->surrounding.anchor);
|
||||||
|
sent = true;
|
||||||
|
}
|
||||||
|
if (text_input->active_features & WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE) {
|
||||||
|
wlr_input_method_v2_send_content_type(layer->input_method,
|
||||||
|
state->content_type.hint, state->content_type.purpose);
|
||||||
|
sent = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (state->features & WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT) {
|
||||||
|
wlr_input_method_v2_send_surrounding_text(layer->input_method,
|
||||||
|
state->surrounding.text, state->surrounding.cursor, state->surrounding.anchor);
|
||||||
|
sent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: add proper wlr_text_input_v3 state field bitmask
|
||||||
|
if (true) {
|
||||||
|
wlr_input_method_v2_send_text_change_cause(layer->input_method,
|
||||||
|
state->text_change_cause);
|
||||||
|
sent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->features & WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE) {
|
||||||
|
wlr_input_method_v2_send_content_type(layer->input_method,
|
||||||
|
state->content_type.hint, state->content_type.purpose);
|
||||||
|
sent = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_grab(struct wlr_input_method_v2_input_router_layer *layer,
|
||||||
|
struct wlr_input_method_keyboard_grab_v2 *grab) {
|
||||||
|
if (layer->grab == grab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->grab = grab;
|
||||||
|
wl_list_remove(&layer->grab_destroy.link);
|
||||||
|
if (grab != NULL) {
|
||||||
|
wl_signal_add(&grab->events.destroy, &layer->grab_destroy);
|
||||||
|
} else {
|
||||||
|
wl_list_init(&layer->grab_destroy.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
update_device_grab(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboard_device(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_device_event *event) {
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer =
|
||||||
|
wl_container_of(keyboard, layer, keyboard);
|
||||||
|
update_device_grab(layer);
|
||||||
|
|
||||||
|
if (layer->device_grabbed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_notify_device(keyboard, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t keyboard_key(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_key_event *event) {
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer =
|
||||||
|
wl_container_of(keyboard, layer, keyboard);
|
||||||
|
if (layer->device_grabbed) {
|
||||||
|
if (event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
|
||||||
|
// We can't relay the effective keyboard state without
|
||||||
|
// zwp_input_method_keyboard_grab_v2.key, so the event is dropped.
|
||||||
|
if (event->intercepted) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
assert(layer->n_forwarded_keys < WLR_KEYBOARD_KEYS_CAP);
|
||||||
|
layer->forwarded_keys[layer->n_forwarded_keys++] = event->key;
|
||||||
|
} else {
|
||||||
|
bool found = false;
|
||||||
|
for (size_t i = 0; i < layer->n_forwarded_keys; i++) {
|
||||||
|
if (layer->forwarded_keys[i] == event->key) {
|
||||||
|
layer->forwarded_keys[i] = layer->forwarded_keys[--layer->n_forwarded_keys];
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We can't relay the effective keyboard state without
|
||||||
|
// zwp_input_method_keyboard_grab_v2.key, so intercepted releases of
|
||||||
|
// relayed pressed keys are sent too.
|
||||||
|
if (!found) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_method_keyboard_grab_v2_send_key(layer->grab,
|
||||||
|
event->time_msec, event->key, event->state);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wlr_input_router_keyboard_notify_key(keyboard, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboard_modifiers(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_modifiers_event *event) {
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer =
|
||||||
|
wl_container_of(keyboard, layer, keyboard);
|
||||||
|
if (layer->device_grabbed) {
|
||||||
|
wlr_input_method_keyboard_grab_v2_send_modifiers(layer->grab,
|
||||||
|
&keyboard->device->modifiers);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_notify_modifiers(keyboard, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_keyboard_interface keyboard_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_input_method_v2_input_router_layer-keyboard",
|
||||||
|
},
|
||||||
|
.device = keyboard_device,
|
||||||
|
.key = keyboard_key,
|
||||||
|
.modifiers = keyboard_modifiers,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_active_text_input_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, active_text_input_destroy);
|
||||||
|
wlr_input_method_v2_input_router_layer_set_active_text_input(layer, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_active_text_input_commit(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, active_text_input_commit);
|
||||||
|
if (layer->input_method != NULL && active_text_input_state(layer, false)) {
|
||||||
|
wlr_input_method_v2_send_done(layer->input_method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_input_method_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, input_method_destroy);
|
||||||
|
wlr_input_method_v2_input_router_layer_set_input_method(layer, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_input_method_commit(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, input_method_commit);
|
||||||
|
struct wlr_text_input_v3 *text_input = layer->active_text_input;
|
||||||
|
if (text_input == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_input_method_v2_state *state = &layer->input_method->current;
|
||||||
|
bool sent = false;
|
||||||
|
|
||||||
|
if (state->commit_text != NULL) {
|
||||||
|
wlr_text_input_v3_send_commit_string(text_input, state->commit_text);
|
||||||
|
sent = true;
|
||||||
|
}
|
||||||
|
if (state->delete.before_length != 0 || state->delete.after_length != 0) {
|
||||||
|
wlr_text_input_v3_send_delete_surrounding_text(text_input,
|
||||||
|
state->delete.before_length, state->delete.after_length);
|
||||||
|
sent = true;
|
||||||
|
}
|
||||||
|
if (state->preedit.text != NULL) {
|
||||||
|
wlr_text_input_v3_send_preedit_string(text_input, state->preedit.text,
|
||||||
|
state->preedit.cursor_begin, state->preedit.cursor_end);
|
||||||
|
sent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sent) {
|
||||||
|
wlr_text_input_v3_send_done(text_input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_input_method_grab_keyboard(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, input_method_grab_keyboard);
|
||||||
|
struct wlr_input_method_keyboard_grab_v2 *grab = data;
|
||||||
|
set_grab(layer, grab);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_router_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, router_destroy);
|
||||||
|
wlr_input_method_v2_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_grab_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, grab_destroy);
|
||||||
|
set_grab(layer, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_method_v2_input_router_layer_set_input_method(
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer,
|
||||||
|
struct wlr_input_method_v2 *input_method) {
|
||||||
|
if (layer->input_method == input_method) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layer->input_method != NULL && layer->input_method->active) {
|
||||||
|
// XXX: this shouldn't be possible actually
|
||||||
|
wlr_input_method_v2_send_deactivate(layer->input_method);
|
||||||
|
wlr_input_method_v2_send_done(layer->input_method);
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->input_method = input_method;
|
||||||
|
|
||||||
|
wl_list_remove(&layer->input_method_destroy.link);
|
||||||
|
wl_list_remove(&layer->input_method_commit.link);
|
||||||
|
wl_list_remove(&layer->input_method_grab_keyboard.link);
|
||||||
|
|
||||||
|
if (input_method != NULL) {
|
||||||
|
wl_signal_add(&input_method->events.destroy, &layer->input_method_destroy);
|
||||||
|
wl_signal_add(&input_method->events.commit, &layer->input_method_commit);
|
||||||
|
wl_signal_add(&input_method->events.grab_keyboard, &layer->input_method_grab_keyboard);
|
||||||
|
|
||||||
|
if (update_input_method_active(layer)) {
|
||||||
|
wlr_input_method_v2_send_done(layer->input_method);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wl_list_init(&layer->input_method_destroy.link);
|
||||||
|
wl_list_init(&layer->input_method_commit.link);
|
||||||
|
wl_list_init(&layer->input_method_grab_keyboard.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_grab(layer, input_method != NULL ? input_method->keyboard_grab : NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_method_v2_input_router_layer_set_active_text_input(
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer,
|
||||||
|
struct wlr_text_input_v3 *text_input) {
|
||||||
|
if (layer->active_text_input == text_input) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->active_text_input = text_input;
|
||||||
|
|
||||||
|
wl_list_remove(&layer->active_text_input_destroy.link);
|
||||||
|
wl_list_remove(&layer->active_text_input_commit.link);
|
||||||
|
|
||||||
|
if (text_input != NULL) {
|
||||||
|
wl_signal_add(&text_input->events.destroy, &layer->active_text_input_destroy);
|
||||||
|
wl_signal_add(&text_input->events.commit, &layer->active_text_input_commit);
|
||||||
|
} else {
|
||||||
|
wl_list_init(&layer->active_text_input_destroy.link);
|
||||||
|
wl_list_init(&layer->active_text_input_commit.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layer->input_method != NULL) {
|
||||||
|
bool sent = false;
|
||||||
|
sent |= update_input_method_active(layer);
|
||||||
|
sent |= active_text_input_state(layer, true);
|
||||||
|
if (sent) {
|
||||||
|
wlr_input_method_v2_send_done(layer->input_method);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_input_method_v2_input_router_layer_register(int32_t priority) {
|
||||||
|
if (!wlr_input_router_keyboard_register_interface(&keyboard_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_input_method_v2_input_router_layer *wlr_input_method_v2_input_router_layer_create(
|
||||||
|
struct wlr_input_router *router) {
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer = calloc(1, sizeof(*layer));
|
||||||
|
if (layer == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_init(&layer->keyboard,
|
||||||
|
router, &keyboard_impl);
|
||||||
|
|
||||||
|
layer->active_text_input_destroy.notify = handle_active_text_input_destroy;
|
||||||
|
wl_list_init(&layer->active_text_input_destroy.link);
|
||||||
|
layer->active_text_input_commit.notify = handle_active_text_input_commit;
|
||||||
|
wl_list_init(&layer->active_text_input_commit.link);
|
||||||
|
|
||||||
|
layer->input_method_destroy.notify = handle_input_method_destroy;
|
||||||
|
wl_list_init(&layer->input_method_destroy.link);
|
||||||
|
layer->input_method_commit.notify = handle_input_method_commit;
|
||||||
|
wl_list_init(&layer->input_method_commit.link);
|
||||||
|
layer->input_method_grab_keyboard.notify = handle_input_method_grab_keyboard;
|
||||||
|
wl_list_init(&layer->input_method_grab_keyboard.link);
|
||||||
|
|
||||||
|
layer->router = router;
|
||||||
|
layer->router_destroy.notify = handle_router_destroy;
|
||||||
|
wl_signal_add(&router->events.destroy, &layer->router_destroy);
|
||||||
|
|
||||||
|
layer->grab_destroy.notify = handle_grab_destroy;
|
||||||
|
wl_list_init(&layer->grab_destroy.link);
|
||||||
|
|
||||||
|
wl_signal_init(&layer->events.destroy);
|
||||||
|
|
||||||
|
update_device_grab(layer);
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_method_v2_input_router_layer_destroy(
|
||||||
|
struct wlr_input_method_v2_input_router_layer *layer) {
|
||||||
|
if (layer == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_emit_mutable(&layer->events.destroy, NULL);
|
||||||
|
|
||||||
|
assert(wl_list_empty(&layer->events.destroy.listener_list));
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_notify_device(&layer->keyboard,
|
||||||
|
&(struct wlr_input_router_keyboard_device_event){
|
||||||
|
.device = layer->keyboard.device,
|
||||||
|
});
|
||||||
|
wlr_input_router_keyboard_finish(&layer->keyboard);
|
||||||
|
|
||||||
|
wl_list_remove(&layer->active_text_input_destroy.link);
|
||||||
|
wl_list_remove(&layer->active_text_input_commit.link);
|
||||||
|
|
||||||
|
wl_list_remove(&layer->input_method_destroy.link);
|
||||||
|
wl_list_remove(&layer->input_method_commit.link);
|
||||||
|
wl_list_remove(&layer->input_method_grab_keyboard.link);
|
||||||
|
|
||||||
|
wl_list_remove(&layer->router_destroy.link);
|
||||||
|
wl_list_remove(&layer->grab_destroy.link);
|
||||||
|
|
||||||
|
free(layer);
|
||||||
|
}
|
||||||
110
types/input_router/keyboard.c
Normal file
110
types/input_router/keyboard.c
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
static struct wlr_input_router_handler_priority_list keyboard_priority_list = {0};
|
||||||
|
|
||||||
|
static void set_device(struct wlr_input_router_keyboard *keyboard, struct wlr_keyboard *device) {
|
||||||
|
keyboard->device = device;
|
||||||
|
wl_list_remove(&keyboard->device_destroy.link);
|
||||||
|
if (device != NULL) {
|
||||||
|
wl_signal_add(&device->base.events.destroy, &keyboard->device_destroy);
|
||||||
|
} else {
|
||||||
|
wl_list_init(&keyboard->device_destroy.link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_device_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_input_router_keyboard *keyboard =
|
||||||
|
wl_container_of(listener, keyboard, device_destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_keyboard_notify_focus(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_focus_event *event) {
|
||||||
|
while ((keyboard = wl_container_of(keyboard->base.next, keyboard, base)) != NULL) {
|
||||||
|
wlr_input_router_focus_copy(&keyboard->focus, event->focus);
|
||||||
|
|
||||||
|
if (keyboard->impl->focus != NULL) {
|
||||||
|
return keyboard->impl->focus(keyboard, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_keyboard_notify_device(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_device_event *event) {
|
||||||
|
while ((keyboard = wl_container_of(keyboard->base.next, keyboard, base)) != NULL) {
|
||||||
|
if (keyboard->device == event->device) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
set_device(keyboard, event->device);
|
||||||
|
|
||||||
|
if (keyboard->impl->device != NULL) {
|
||||||
|
keyboard->impl->device(keyboard, event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_keyboard_notify_key(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_key_event *event) {
|
||||||
|
while ((keyboard = wl_container_of(keyboard->base.next, keyboard, base)) != NULL) {
|
||||||
|
if (keyboard->device == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "%s received a key event without an active device",
|
||||||
|
keyboard->impl->base.name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyboard->impl->key != NULL) {
|
||||||
|
return keyboard->impl->key(keyboard, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_keyboard_notify_modifiers(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_modifiers_event *event) {
|
||||||
|
while ((keyboard = wl_container_of(keyboard->base.next, keyboard, base)) != NULL) {
|
||||||
|
if (keyboard->device == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "%s received a modifiers event without an active device",
|
||||||
|
keyboard->impl->base.name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyboard->impl->modifiers != NULL) {
|
||||||
|
keyboard->impl->modifiers(keyboard, event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_input_router_keyboard_register_interface(
|
||||||
|
const struct wlr_input_router_keyboard_interface *iface, int32_t priority) {
|
||||||
|
return wlr_input_router_register_handler_interface(&iface->base,
|
||||||
|
priority, &keyboard_priority_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_keyboard_init(
|
||||||
|
struct wlr_input_router_keyboard *keyboard, struct wlr_input_router *router,
|
||||||
|
const struct wlr_input_router_keyboard_interface *impl) {
|
||||||
|
*keyboard = (struct wlr_input_router_keyboard){
|
||||||
|
.impl = impl,
|
||||||
|
};
|
||||||
|
wlr_input_router_handler_init(&keyboard->base, &router->keyboard.base,
|
||||||
|
&impl->base, &keyboard_priority_list);
|
||||||
|
wlr_input_router_focus_init(&keyboard->focus);
|
||||||
|
|
||||||
|
keyboard->device_destroy.notify = handle_device_destroy;
|
||||||
|
wl_list_init(&keyboard->device_destroy.link);
|
||||||
|
|
||||||
|
struct wlr_input_router_keyboard *next = wl_container_of(keyboard->base.next, next, base);
|
||||||
|
if (next != NULL) {
|
||||||
|
wlr_input_router_focus_copy(&keyboard->focus, &next->focus);
|
||||||
|
set_device(keyboard, next->device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_keyboard_finish(struct wlr_input_router_keyboard *keyboard) {
|
||||||
|
wlr_input_router_focus_finish(&keyboard->focus);
|
||||||
|
wl_list_remove(&keyboard->device_destroy.link);
|
||||||
|
wlr_input_router_handler_finish(&keyboard->base);
|
||||||
|
}
|
||||||
141
types/input_router/pointer.c
Normal file
141
types/input_router/pointer.c
Normal file
|
|
@ -0,0 +1,141 @@
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
static struct wlr_input_router_handler_priority_list pointer_priority_list = {0};
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_pointer_notify_position(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_position_event *event) {
|
||||||
|
while ((pointer = wl_container_of(pointer->base.next, pointer, base)) != NULL) {
|
||||||
|
pointer->x = event->x;
|
||||||
|
pointer->y = event->y;
|
||||||
|
wlr_input_router_focus_copy(&pointer->focus, event->focus);
|
||||||
|
|
||||||
|
if (pointer->impl->position != NULL) {
|
||||||
|
return pointer->impl->position(pointer, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_pointer_notify_button(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_button_event *event) {
|
||||||
|
while ((pointer = wl_container_of(pointer->base.next, pointer, base)) != NULL) {
|
||||||
|
struct wlr_input_router_pointer_button *button = NULL;
|
||||||
|
for (size_t i = 0; i < pointer->n_buttons; i++) {
|
||||||
|
if (pointer->buttons[i].button == event->button) {
|
||||||
|
button = &pointer->buttons[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||||
|
if (button == NULL) {
|
||||||
|
if (pointer->n_buttons == WLR_INPUT_ROUTER_MAX_POINTER_BUTTONS) {
|
||||||
|
wlr_log(WLR_ERROR, "%s has too many pressed buttons, ignoring %"PRIi32,
|
||||||
|
pointer->impl->base.name, event->button);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
button = &pointer->buttons[pointer->n_buttons++];
|
||||||
|
*button = (struct wlr_input_router_pointer_button){
|
||||||
|
.button = event->button,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
++button->count;
|
||||||
|
if (button->count != 1) {
|
||||||
|
// Already pressed
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (button == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "%s received a release for a non-pressed button %"PRIi32,
|
||||||
|
pointer->impl->base.name, event->button);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
--button->count;
|
||||||
|
if (button->count != 0) {
|
||||||
|
// Still pressed
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*button = pointer->buttons[--pointer->n_buttons];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointer->impl->button != NULL) {
|
||||||
|
struct wlr_input_router_pointer_button_event relayed = *event;
|
||||||
|
relayed.index = button - pointer->buttons;
|
||||||
|
return pointer->impl->button(pointer, &relayed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_pointer_notify_axis(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_axis_event *event) {
|
||||||
|
while ((pointer = wl_container_of(pointer->base.next, pointer, base)) != NULL) {
|
||||||
|
if (pointer->impl->axis != NULL) {
|
||||||
|
pointer->impl->axis(pointer, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_pointer_notify_frame(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_frame_event *event) {
|
||||||
|
while ((pointer = wl_container_of(pointer->base.next, pointer, base)) != NULL) {
|
||||||
|
if (pointer->impl->frame != NULL) {
|
||||||
|
pointer->impl->frame(pointer, event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_pointer_refresh_position(struct wlr_input_router_pointer *pointer) {
|
||||||
|
return wlr_input_router_pointer_notify_position(pointer,
|
||||||
|
&(struct wlr_input_router_pointer_position_event){
|
||||||
|
.x = pointer->x,
|
||||||
|
.y = pointer->y,
|
||||||
|
.focus = &pointer->focus,
|
||||||
|
.synthetic = true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_pointer_clear_focus(struct wlr_input_router_pointer *pointer) {
|
||||||
|
return wlr_input_router_pointer_notify_position(pointer,
|
||||||
|
&(struct wlr_input_router_pointer_position_event){
|
||||||
|
.x = pointer->x,
|
||||||
|
.y = pointer->y,
|
||||||
|
.focus = NULL,
|
||||||
|
.explicit_focus = true,
|
||||||
|
.synthetic = true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_input_router_pointer_register_interface(
|
||||||
|
const struct wlr_input_router_pointer_interface *iface, int32_t priority) {
|
||||||
|
return wlr_input_router_register_handler_interface(&iface->base,
|
||||||
|
priority, &pointer_priority_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_pointer_init(struct wlr_input_router_pointer *pointer,
|
||||||
|
struct wlr_input_router *router, const struct wlr_input_router_pointer_interface *impl) {
|
||||||
|
*pointer = (struct wlr_input_router_pointer){
|
||||||
|
.impl = impl,
|
||||||
|
};
|
||||||
|
wlr_input_router_handler_init(&pointer->base, &router->pointer.base,
|
||||||
|
&impl->base, &pointer_priority_list);
|
||||||
|
wlr_input_router_focus_init(&pointer->focus);
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer *next = wl_container_of(pointer->base.next, next, base);
|
||||||
|
if (next != NULL) {
|
||||||
|
pointer->x = next->x;
|
||||||
|
pointer->y = next->y;
|
||||||
|
wlr_input_router_focus_copy(&pointer->focus, &next->focus);
|
||||||
|
for (size_t i = 0; i < next->n_buttons; i++) {
|
||||||
|
pointer->buttons[i] = next->buttons[i];
|
||||||
|
}
|
||||||
|
pointer->n_buttons = next->n_buttons;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_pointer_finish(struct wlr_input_router_pointer *pointer) {
|
||||||
|
wlr_input_router_focus_finish(&pointer->focus);
|
||||||
|
wlr_input_router_handler_finish(&pointer->base);
|
||||||
|
}
|
||||||
280
types/input_router/pointer_constraints.c
Normal file
280
types/input_router/pointer_constraints.c
Normal file
|
|
@ -0,0 +1,280 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
#include <wlr/util/region.h>
|
||||||
|
|
||||||
|
static void closest_point(pixman_region32_t *region, double x, double y,
|
||||||
|
double *out_x, double *out_y) {
|
||||||
|
*out_x = x;
|
||||||
|
*out_y = y;
|
||||||
|
double d2_best = INFINITY;
|
||||||
|
|
||||||
|
int nrects;
|
||||||
|
pixman_box32_t *rects = pixman_region32_rectangles(region, &nrects);
|
||||||
|
for (int i = 0; i < nrects; i++) {
|
||||||
|
pixman_box32_t *rect = &rects[i];
|
||||||
|
double box_x = x < rect->x1 ? rect->x1 : x >= rect->x2 ? rect->x2 - 1 : x;
|
||||||
|
double box_y = y < rect->y1 ? rect->y1 : y >= rect->y2 ? rect->y2 - 1 : y;
|
||||||
|
double dx = box_x - x, dy = box_y - y;
|
||||||
|
double d2 = dx * dx + dy * dy;
|
||||||
|
if (d2 <= d2_best) {
|
||||||
|
d2_best = d2;
|
||||||
|
*out_x = box_x;
|
||||||
|
*out_y = box_y;
|
||||||
|
}
|
||||||
|
if (d2_best == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t update_position(struct wlr_pointer_constraints_v1_input_router_layer *layer,
|
||||||
|
const struct wlr_input_router_pointer_position_event *event) {
|
||||||
|
struct wlr_pointer_constraint_v1 *constraint = layer->active;
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer_position_event copy;
|
||||||
|
if (constraint != NULL) {
|
||||||
|
double surface_x, surface_y;
|
||||||
|
if (!wlr_input_router_get_surface_position(layer->router, constraint->surface,
|
||||||
|
&surface_x, &surface_y)) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
double sx = event->x - surface_x, sy = event->y - surface_y;
|
||||||
|
|
||||||
|
copy = *event;
|
||||||
|
switch (constraint->type) {
|
||||||
|
case WLR_POINTER_CONSTRAINT_V1_LOCKED:
|
||||||
|
if (!layer->lock_applied) {
|
||||||
|
closest_point(&constraint->region, sx, sy, &layer->lock_sx, &layer->lock_sy);
|
||||||
|
layer->lock_applied = true;
|
||||||
|
}
|
||||||
|
copy.x = surface_x + layer->lock_sx;
|
||||||
|
copy.y = surface_y + layer->lock_sy;
|
||||||
|
break;
|
||||||
|
case WLR_POINTER_CONSTRAINT_V1_CONFINED:
|
||||||
|
if (!wlr_region_confine(&constraint->region, layer->last_x - surface_x,
|
||||||
|
layer->last_y - surface_y, sx, sy, &sx, &sy)) {
|
||||||
|
closest_point(&constraint->region, sx, sy, &sx, &sy);
|
||||||
|
}
|
||||||
|
copy.x = surface_x + sx;
|
||||||
|
copy.y = surface_y + sy;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
event = ©
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
layer->last_x = event->x;
|
||||||
|
layer->last_y = event->y;
|
||||||
|
return wlr_input_router_pointer_notify_position(&layer->pointer, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t pointer_position(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_position_event *event) {
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer =
|
||||||
|
wl_container_of(pointer, layer, pointer);
|
||||||
|
return update_position(layer, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_pointer_interface pointer_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_pointer_constraints_v1_input_router_layer-pointer",
|
||||||
|
},
|
||||||
|
.position = pointer_position,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void refresh_position(struct wlr_pointer_constraints_v1_input_router_layer *layer) {
|
||||||
|
update_position(layer,
|
||||||
|
&(struct wlr_input_router_pointer_position_event){
|
||||||
|
.x = layer->pointer.x,
|
||||||
|
.y = layer->pointer.y,
|
||||||
|
.focus = &layer->pointer.focus,
|
||||||
|
.synthetic = true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_active(struct wlr_pointer_constraints_v1_input_router_layer *layer,
|
||||||
|
struct wlr_pointer_constraint_v1 *constraint) {
|
||||||
|
struct wlr_pointer_constraint_v1 *prev = layer->active;
|
||||||
|
if (constraint == prev) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->lock_applied = false;
|
||||||
|
layer->active = constraint;
|
||||||
|
|
||||||
|
wl_list_remove(&layer->active_destroy.link);
|
||||||
|
wl_list_remove(&layer->active_set_region.link);
|
||||||
|
|
||||||
|
if (prev != NULL) {
|
||||||
|
if (prev->type == WLR_POINTER_CONSTRAINT_V1_LOCKED && prev->current.cursor_hint.enabled) {
|
||||||
|
double surface_x, surface_y;
|
||||||
|
if (wlr_input_router_get_surface_position(layer->router, prev->surface,
|
||||||
|
&surface_x, &surface_y)) {
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer_cursor_hint_event event = {
|
||||||
|
.x = surface_x + prev->current.cursor_hint.x,
|
||||||
|
.y = surface_y + prev->current.cursor_hint.y,
|
||||||
|
};
|
||||||
|
wl_signal_emit_mutable(&layer->events.cursor_hint, &event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_pointer_constraint_v1_send_deactivated(prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (constraint != NULL) {
|
||||||
|
wl_signal_add(&constraint->events.destroy, &layer->active_destroy);
|
||||||
|
wl_signal_add(&constraint->events.set_region, &layer->active_set_region);
|
||||||
|
|
||||||
|
wlr_pointer_constraint_v1_send_activated(constraint);
|
||||||
|
} else {
|
||||||
|
wl_list_init(&layer->active_destroy.link);
|
||||||
|
wl_list_init(&layer->active_set_region.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
refresh_position(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_active_surface_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, active_surface_destroy);
|
||||||
|
wlr_pointer_constraints_v1_input_router_layer_set_active_surface(layer, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_active_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, active_destroy);
|
||||||
|
set_active(layer, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_active_set_region(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, active_set_region);
|
||||||
|
layer->lock_applied = false;
|
||||||
|
refresh_position(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_constraints_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, constraints_destroy);
|
||||||
|
wlr_pointer_constraints_v1_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_constraints_new_constraint(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, constraints_new_constraint);
|
||||||
|
struct wlr_pointer_constraint_v1 *constraint = data;
|
||||||
|
if (layer->active_surface == constraint->surface) {
|
||||||
|
set_active(layer, constraint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_router_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, router_destroy);
|
||||||
|
wlr_pointer_constraints_v1_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_seat_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, seat_destroy);
|
||||||
|
wlr_pointer_constraints_v1_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_pointer_constraints_v1_input_router_layer_set_active_surface(
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer,
|
||||||
|
struct wlr_surface *surface) {
|
||||||
|
if (layer->active_surface == surface) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->active_surface = surface;
|
||||||
|
|
||||||
|
wl_list_remove(&layer->active_surface_destroy.link);
|
||||||
|
if (surface != NULL) {
|
||||||
|
wl_signal_add(&surface->events.destroy, &layer->active_surface_destroy);
|
||||||
|
} else {
|
||||||
|
wl_list_init(&layer->active_surface_destroy.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_pointer_constraint_v1 *constraint =
|
||||||
|
wlr_pointer_constraints_v1_constraint_for_surface(layer->constraints,
|
||||||
|
surface, layer->seat);
|
||||||
|
set_active(layer, constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_pointer_constraints_v1_input_router_layer_register(int32_t priority) {
|
||||||
|
if (!wlr_input_router_pointer_register_interface(&pointer_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *
|
||||||
|
wlr_pointer_constraints_v1_input_router_layer_create(
|
||||||
|
struct wlr_input_router *router, struct wlr_pointer_constraints_v1 *constraints,
|
||||||
|
struct wlr_seat *seat) {
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer = calloc(1, sizeof(*layer));
|
||||||
|
if (layer == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_pointer_init(&layer->pointer, router, &pointer_impl);
|
||||||
|
|
||||||
|
layer->active_surface_destroy.notify = handle_active_surface_destroy;
|
||||||
|
wl_list_init(&layer->active_surface_destroy.link);
|
||||||
|
|
||||||
|
layer->active_destroy.notify = handle_active_destroy;
|
||||||
|
wl_list_init(&layer->active_destroy.link);
|
||||||
|
|
||||||
|
layer->active_set_region.notify = handle_active_set_region;
|
||||||
|
wl_list_init(&layer->active_set_region.link);
|
||||||
|
|
||||||
|
layer->constraints = constraints;
|
||||||
|
|
||||||
|
layer->constraints_destroy.notify = handle_constraints_destroy;
|
||||||
|
wl_signal_add(&constraints->events.destroy, &layer->constraints_destroy);
|
||||||
|
layer->constraints_new_constraint.notify = handle_constraints_new_constraint;
|
||||||
|
wl_signal_add(&constraints->events.new_constraint, &layer->constraints_new_constraint);
|
||||||
|
|
||||||
|
layer->router = router;
|
||||||
|
layer->router_destroy.notify = handle_router_destroy;
|
||||||
|
wl_signal_add(&router->events.destroy, &layer->router_destroy);
|
||||||
|
|
||||||
|
layer->seat = seat;
|
||||||
|
layer->seat_destroy.notify = handle_seat_destroy;
|
||||||
|
wl_signal_add(&seat->events.destroy, &layer->seat_destroy);
|
||||||
|
|
||||||
|
wl_signal_init(&layer->events.destroy);
|
||||||
|
wl_signal_init(&layer->events.cursor_hint);
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_pointer_constraints_v1_input_router_layer_destroy(
|
||||||
|
struct wlr_pointer_constraints_v1_input_router_layer *layer) {
|
||||||
|
if (layer == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_emit_mutable(&layer->events.destroy, NULL);
|
||||||
|
|
||||||
|
assert(wl_list_empty(&layer->events.destroy.listener_list));
|
||||||
|
assert(wl_list_empty(&layer->events.cursor_hint.listener_list));
|
||||||
|
|
||||||
|
wlr_input_router_pointer_finish(&layer->pointer);
|
||||||
|
|
||||||
|
wl_list_remove(&layer->active_surface_destroy.link);
|
||||||
|
wl_list_remove(&layer->active_destroy.link);
|
||||||
|
wl_list_remove(&layer->active_set_region.link);
|
||||||
|
wl_list_remove(&layer->constraints_new_constraint.link);
|
||||||
|
wl_list_remove(&layer->constraints_destroy.link);
|
||||||
|
wl_list_remove(&layer->router_destroy.link);
|
||||||
|
wl_list_remove(&layer->seat_destroy.link);
|
||||||
|
|
||||||
|
free(layer);
|
||||||
|
}
|
||||||
96
types/input_router/relative_pointer.c
Normal file
96
types/input_router/relative_pointer.c
Normal file
|
|
@ -0,0 +1,96 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/types/wlr_relative_pointer_v1.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/types/wlr_seat.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
static uint32_t pointer_position(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_position_event *event) {
|
||||||
|
struct wlr_relative_pointer_v1_input_router_layer *layer =
|
||||||
|
wl_container_of(pointer, layer, pointer);
|
||||||
|
wlr_relative_pointer_manager_v1_send_relative_motion(layer->manager,
|
||||||
|
layer->seat, (uint64_t)event->time_msec * 1000, event->dx, event->dy,
|
||||||
|
event->unaccel_dx, event->unaccel_dy);
|
||||||
|
return wlr_input_router_pointer_notify_position(pointer, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_pointer_interface pointer_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_relative_pointer_v1_input_router_layer-pointer",
|
||||||
|
},
|
||||||
|
.position = pointer_position,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_router_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_relative_pointer_v1_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, router_destroy);
|
||||||
|
wlr_relative_pointer_v1_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_manager_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_relative_pointer_v1_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, manager_destroy);
|
||||||
|
wlr_relative_pointer_v1_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_seat_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_relative_pointer_v1_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, seat_destroy);
|
||||||
|
wlr_relative_pointer_v1_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_relative_pointer_v1_input_router_layer_register(int32_t priority) {
|
||||||
|
if (!wlr_input_router_pointer_register_interface(&pointer_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_relative_pointer_v1_input_router_layer *
|
||||||
|
wlr_relative_pointer_v1_input_router_layer_create(
|
||||||
|
struct wlr_input_router *router, struct wlr_relative_pointer_manager_v1 *manager,
|
||||||
|
struct wlr_seat *seat) {
|
||||||
|
struct wlr_relative_pointer_v1_input_router_layer *layer = calloc(1, sizeof(*layer));
|
||||||
|
if (layer == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_pointer_init(&layer->pointer, router, &pointer_impl);
|
||||||
|
|
||||||
|
layer->router = router;
|
||||||
|
layer->router_destroy.notify = handle_router_destroy;
|
||||||
|
wl_signal_add(&router->events.destroy, &layer->router_destroy);
|
||||||
|
|
||||||
|
layer->manager = manager;
|
||||||
|
layer->manager_destroy.notify = handle_manager_destroy;
|
||||||
|
wl_signal_add(&manager->events.destroy, &layer->manager_destroy);
|
||||||
|
|
||||||
|
layer->seat = seat;
|
||||||
|
layer->seat_destroy.notify = handle_seat_destroy;
|
||||||
|
wl_signal_add(&seat->events.destroy, &layer->seat_destroy);
|
||||||
|
|
||||||
|
wl_signal_init(&layer->events.destroy);
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_relative_pointer_v1_input_router_layer_destroy(
|
||||||
|
struct wlr_relative_pointer_v1_input_router_layer *layer) {
|
||||||
|
if (layer == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_emit_mutable(&layer->events.destroy, NULL);
|
||||||
|
|
||||||
|
assert(wl_list_empty(&layer->events.destroy.listener_list));
|
||||||
|
|
||||||
|
wlr_input_router_pointer_finish(&layer->pointer);
|
||||||
|
|
||||||
|
wl_list_remove(&layer->router_destroy.link);
|
||||||
|
wl_list_remove(&layer->manager_destroy.link);
|
||||||
|
wl_list_remove(&layer->seat_destroy.link);
|
||||||
|
|
||||||
|
free(layer);
|
||||||
|
}
|
||||||
293
types/input_router/router.c
Normal file
293
types/input_router/router.c
Normal file
|
|
@ -0,0 +1,293 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/types/wlr_compositor.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
struct wlr_input_router_handler_priority_entry {
|
||||||
|
const struct wlr_input_router_handler_interface *iface;
|
||||||
|
int32_t priority;
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wlr_input_router_keyboard_interface keyboard_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_input_router-keyboard",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wlr_input_router_pointer_interface pointer_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_input_router-pointer",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct wlr_input_router_touch_interface touch_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_input_router-touch",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static void focus_handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_input_router_focus *focus = wl_container_of(listener, focus, destroy);
|
||||||
|
wlr_input_router_focus_clear(focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void focus_set_generic(struct wlr_input_router_focus *focus,
|
||||||
|
enum wlr_input_router_focus_type type, struct wl_signal *destroy_signal) {
|
||||||
|
focus->type = type;
|
||||||
|
wl_list_remove(&focus->destroy.link);
|
||||||
|
if (destroy_signal != NULL) {
|
||||||
|
wl_signal_add(destroy_signal, &focus->destroy);
|
||||||
|
} else {
|
||||||
|
wl_list_init(&focus->destroy.link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_input_router_register_handler_interface(
|
||||||
|
const struct wlr_input_router_handler_interface *iface,
|
||||||
|
int32_t priority, struct wlr_input_router_handler_priority_list *priority_list) {
|
||||||
|
struct wlr_input_router_handler_priority_entry *entry;
|
||||||
|
wl_array_for_each(entry, &priority_list->entries) {
|
||||||
|
if (entry->iface == iface) {
|
||||||
|
if (entry->priority == priority) {
|
||||||
|
// Already registered with the same priority
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_log(WLR_ERROR,
|
||||||
|
"Tried to register an already registered input handler interface %s",
|
||||||
|
entry->iface->name);
|
||||||
|
abort();
|
||||||
|
} else if (entry->priority == priority) {
|
||||||
|
wlr_log(WLR_ERROR,
|
||||||
|
"Tried to register a input handler interface %s with the same priority %"PRIi32
|
||||||
|
" as %s",
|
||||||
|
iface->name, priority, entry->iface->name);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entry = wl_array_add(&priority_list->entries, sizeof(*entry));
|
||||||
|
if (entry == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*entry = (struct wlr_input_router_handler_priority_entry){
|
||||||
|
.iface = iface,
|
||||||
|
.priority = priority,
|
||||||
|
};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_handler_init(struct wlr_input_router_handler *handler,
|
||||||
|
struct wlr_input_router_handler *head,
|
||||||
|
const struct wlr_input_router_handler_interface *impl,
|
||||||
|
const struct wlr_input_router_handler_priority_list *priority_list) {
|
||||||
|
*handler = (struct wlr_input_router_handler){
|
||||||
|
.head = head,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (handler == head) {
|
||||||
|
// Special case: initializing the top of the chain. Do nothing else.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
struct wlr_input_router_handler_priority_entry *priority_entry;
|
||||||
|
wl_array_for_each(priority_entry, &priority_list->entries) {
|
||||||
|
if (priority_entry->iface == impl) {
|
||||||
|
handler->priority = priority_entry->priority;
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
wlr_log(WLR_ERROR,
|
||||||
|
"Tried to init an input handler with unregistered interface %s", impl->name);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_input_router_handler **target_ptr = &head->next;
|
||||||
|
struct wlr_input_router_handler *target;
|
||||||
|
while (true) {
|
||||||
|
target = *target_ptr;
|
||||||
|
if (target == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (target->priority == handler->priority) {
|
||||||
|
wlr_log(WLR_ERROR,
|
||||||
|
"Tried to init an input handler with interface %s twice", impl->name);
|
||||||
|
abort();
|
||||||
|
} else if (handler->priority > target->priority) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
target_ptr = &target->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
handler->next = target;
|
||||||
|
*target_ptr = handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_handler_finish(struct wlr_input_router_handler *handler) {
|
||||||
|
if (handler->head == handler) {
|
||||||
|
// Special case: finalizing the top of the chain. Do nothing else.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_input_router_handler **target_ptr = &handler->head->next;
|
||||||
|
while (true) {
|
||||||
|
struct wlr_input_router_handler *target = *target_ptr;
|
||||||
|
if (target == handler) {
|
||||||
|
*target_ptr = target->next;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
target_ptr = &target->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_at(struct wlr_input_router *router, double x, double y,
|
||||||
|
struct wlr_input_router_focus *focus, double *local_x, double *local_y) {
|
||||||
|
struct wlr_input_router_focus focus_placeholder;
|
||||||
|
wlr_input_router_focus_init(&focus_placeholder);
|
||||||
|
if (focus == NULL) {
|
||||||
|
focus = &focus_placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
double local_x_placeholder, local_y_placeholder;
|
||||||
|
if (local_x == NULL) {
|
||||||
|
local_x = &local_x_placeholder;
|
||||||
|
}
|
||||||
|
if (local_y == NULL) {
|
||||||
|
local_y = &local_y_placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_focus_clear(focus);
|
||||||
|
*local_x = NAN;
|
||||||
|
*local_y = NAN;
|
||||||
|
|
||||||
|
if (router->impl->at != NULL) {
|
||||||
|
router->impl->at(router, x, y, focus, local_x, local_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_focus_finish(&focus_placeholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_input_router_get_surface_position(struct wlr_input_router *router,
|
||||||
|
struct wlr_surface *surface, double *x, double *y) {
|
||||||
|
double x_placeholder, y_placeholder;
|
||||||
|
if (x == NULL) {
|
||||||
|
x = &x_placeholder;
|
||||||
|
}
|
||||||
|
if (y == NULL) {
|
||||||
|
y = &y_placeholder;
|
||||||
|
}
|
||||||
|
|
||||||
|
*x = NAN;
|
||||||
|
*y = NAN;
|
||||||
|
|
||||||
|
if (router->impl->get_surface_position != NULL) {
|
||||||
|
return router->impl->get_surface_position(router, surface, x, y);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_init(struct wlr_input_router *router,
|
||||||
|
const struct wlr_input_router_interface *impl) {
|
||||||
|
*router = (struct wlr_input_router){
|
||||||
|
.impl = impl,
|
||||||
|
};
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_init(&router->keyboard, router, &keyboard_impl);
|
||||||
|
wlr_input_router_pointer_init(&router->pointer, router, &pointer_impl);
|
||||||
|
wlr_input_router_touch_init(&router->touch, router, &touch_impl);
|
||||||
|
|
||||||
|
wlr_addon_set_init(&router->addons);
|
||||||
|
|
||||||
|
wl_signal_init(&router->events.destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_finish(struct wlr_input_router *router) {
|
||||||
|
wl_signal_emit_mutable(&router->events.destroy, NULL);
|
||||||
|
|
||||||
|
wlr_addon_set_finish(&router->addons);
|
||||||
|
|
||||||
|
assert(wl_list_empty(&router->events.destroy.listener_list));
|
||||||
|
|
||||||
|
assert(router->keyboard.base.next == NULL);
|
||||||
|
assert(router->pointer.base.next == NULL);
|
||||||
|
assert(router->touch.base.next == NULL);
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_finish(&router->keyboard);
|
||||||
|
wlr_input_router_pointer_finish(&router->pointer);
|
||||||
|
wlr_input_router_touch_finish(&router->touch);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_focus_init(struct wlr_input_router_focus *focus) {
|
||||||
|
*focus = (struct wlr_input_router_focus) {
|
||||||
|
.type = WLR_INPUT_ROUTER_FOCUS_NONE,
|
||||||
|
.destroy.notify = focus_handle_destroy,
|
||||||
|
};
|
||||||
|
wl_list_init(&focus->destroy.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_focus_finish(struct wlr_input_router_focus *focus) {
|
||||||
|
wl_list_remove(&focus->destroy.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_input_router_focus_is_none(const struct wlr_input_router_focus *focus) {
|
||||||
|
return focus == NULL || focus->type == WLR_INPUT_ROUTER_FOCUS_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_surface *wlr_input_router_focus_get_surface(
|
||||||
|
const struct wlr_input_router_focus *focus) {
|
||||||
|
return focus != NULL && focus->type == WLR_INPUT_ROUTER_FOCUS_SURFACE ? focus->surface : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *wlr_input_router_focus_get_user(const struct wlr_input_router_focus *focus) {
|
||||||
|
return focus != NULL && focus->type == WLR_INPUT_ROUTER_FOCUS_USER ? focus->user : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_focus_clear(struct wlr_input_router_focus *focus) {
|
||||||
|
focus_set_generic(focus, WLR_INPUT_ROUTER_FOCUS_NONE, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_focus_set_surface(struct wlr_input_router_focus *focus,
|
||||||
|
struct wlr_surface *surface) {
|
||||||
|
if (surface != NULL) {
|
||||||
|
focus_set_generic(focus, WLR_INPUT_ROUTER_FOCUS_SURFACE, &surface->events.destroy);
|
||||||
|
focus->surface = surface;
|
||||||
|
} else {
|
||||||
|
wlr_input_router_focus_clear(focus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_focus_set_user(struct wlr_input_router_focus *focus,
|
||||||
|
void *user, struct wl_signal *destroy_signal) {
|
||||||
|
if (user != NULL) {
|
||||||
|
focus_set_generic(focus, WLR_INPUT_ROUTER_FOCUS_USER, destroy_signal);
|
||||||
|
focus->user = user;
|
||||||
|
focus->destroy_signal = destroy_signal;
|
||||||
|
} else {
|
||||||
|
wlr_input_router_focus_clear(focus);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_focus_copy(struct wlr_input_router_focus *dst,
|
||||||
|
const struct wlr_input_router_focus *src) {
|
||||||
|
if (src == NULL) {
|
||||||
|
wlr_input_router_focus_clear(dst);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (src->type) {
|
||||||
|
case WLR_INPUT_ROUTER_FOCUS_NONE:
|
||||||
|
wlr_input_router_focus_clear(dst);
|
||||||
|
break;
|
||||||
|
case WLR_INPUT_ROUTER_FOCUS_SURFACE:
|
||||||
|
wlr_input_router_focus_set_surface(dst, src->surface);
|
||||||
|
break;
|
||||||
|
case WLR_INPUT_ROUTER_FOCUS_USER:
|
||||||
|
wlr_input_router_focus_set_user(dst, src->user, src->destroy_signal);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
387
types/input_router/seat.c
Normal file
387
types/input_router/seat.c
Normal file
|
|
@ -0,0 +1,387 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/types/wlr_compositor.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/types/wlr_seat.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
// TODO: wlr_seat_touch_send_*() functions are currently useless
|
||||||
|
// https://gitlab.freedesktop.org/wlroots/wlroots/-/issues/3478
|
||||||
|
|
||||||
|
// For touch points, seat_client is NULL if the client is not aware of the point
|
||||||
|
|
||||||
|
static void clear_touch_point_seat_client(struct wlr_seat_input_router_layer_touch_point *point) {
|
||||||
|
point->seat_client = NULL;
|
||||||
|
wl_list_remove(&point->seat_client_destroy.link);
|
||||||
|
wl_list_init(&point->seat_client_destroy.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touch_point_handle_seat_client_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_seat_input_router_layer_touch_point *point =
|
||||||
|
wl_container_of(listener, point, seat_client_destroy);
|
||||||
|
clear_touch_point_seat_client(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_touch_point(struct wlr_seat_input_router_layer_touch_point *point) {
|
||||||
|
*point = (struct wlr_seat_input_router_layer_touch_point){0};
|
||||||
|
point->seat_client_destroy.notify = touch_point_handle_seat_client_destroy;
|
||||||
|
wl_list_init(&point->seat_client_destroy.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void finish_touch_point(struct wlr_seat_input_router_layer_touch_point *point) {
|
||||||
|
wl_list_remove(&point->seat_client_destroy.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t keyboard_send_enter(struct wlr_seat_input_router_layer *layer,
|
||||||
|
struct wlr_surface *surface) {
|
||||||
|
uint32_t *keycodes = NULL;
|
||||||
|
size_t num_keycodes = 0;
|
||||||
|
const struct wlr_keyboard_modifiers *modifiers = NULL;
|
||||||
|
|
||||||
|
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(layer->seat);
|
||||||
|
if (keyboard != NULL) {
|
||||||
|
keycodes = keyboard->keycodes;
|
||||||
|
num_keycodes = keyboard->num_keycodes;
|
||||||
|
modifiers = &keyboard->modifiers;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_seat_keyboard_enter(layer->seat, surface, keycodes, num_keycodes, modifiers);
|
||||||
|
// TODO: get a serial from enter
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t keyboard_focus(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_focus_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(keyboard, layer, keyboard);
|
||||||
|
return keyboard_send_enter(layer, wlr_input_router_focus_get_surface(event->focus));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboard_device(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_device_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(keyboard, layer, keyboard);
|
||||||
|
struct wlr_keyboard *device = event->device;
|
||||||
|
|
||||||
|
if (wlr_seat_get_keyboard(layer->seat) == device) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Avoid sending new modifiers with old keys
|
||||||
|
struct wlr_surface *surface = layer->seat->keyboard_state.focused_surface;
|
||||||
|
wlr_seat_keyboard_clear_focus(layer->seat);
|
||||||
|
|
||||||
|
wlr_seat_set_keyboard(layer->seat, device);
|
||||||
|
|
||||||
|
keyboard_send_enter(layer, surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t keyboard_key(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_key_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(keyboard, layer, keyboard);
|
||||||
|
if (event->intercepted) {
|
||||||
|
// Update the client state without sending a wl_keyboard.key event
|
||||||
|
// XXX: this is suboptimal, wl_keyboard.keys would be better
|
||||||
|
// See https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/406
|
||||||
|
struct wlr_surface *surface = layer->seat->keyboard_state.focused_surface;
|
||||||
|
wlr_seat_keyboard_clear_focus(layer->seat);
|
||||||
|
keyboard_send_enter(layer, surface);
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
wlr_seat_keyboard_send_key(layer->seat, event->time_msec, event->key, event->state);
|
||||||
|
// TODO: get a serial from key
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void keyboard_modifiers(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_modifiers_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(keyboard, layer, keyboard);
|
||||||
|
wlr_seat_keyboard_send_modifiers(layer->seat, &keyboard->device->modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_keyboard_interface keyboard_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_seat_input_router_layer-keyboard",
|
||||||
|
},
|
||||||
|
.focus = keyboard_focus,
|
||||||
|
.device = keyboard_device,
|
||||||
|
.key = keyboard_key,
|
||||||
|
.modifiers = keyboard_modifiers,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t pointer_position(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_position_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(pointer, layer, pointer);
|
||||||
|
|
||||||
|
struct wlr_surface *surface = wlr_input_router_focus_get_surface(event->focus);
|
||||||
|
double sx = 0, sy = 0;
|
||||||
|
|
||||||
|
if (surface != NULL) {
|
||||||
|
double surface_x, surface_y;
|
||||||
|
if (!wlr_input_router_get_surface_position(layer->router, surface,
|
||||||
|
&surface_x, &surface_y)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
sx = event->x - surface_x;
|
||||||
|
sy = event->y - surface_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// One of these will short-circuit
|
||||||
|
wlr_seat_pointer_enter(layer->seat, surface, sx, sy);
|
||||||
|
wlr_seat_pointer_send_motion(layer->seat, event->time_msec, sx, sy);
|
||||||
|
|
||||||
|
// TODO: get a serial from enter
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t pointer_button(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_button_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(pointer, layer, pointer);
|
||||||
|
return wlr_seat_pointer_send_button(layer->seat,
|
||||||
|
event->time_msec, event->button, event->state);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pointer_axis(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_axis_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(pointer, layer, pointer);
|
||||||
|
wlr_seat_pointer_send_axis(layer->seat, event->time_msec, event->orientation,
|
||||||
|
event->delta, event->delta_discrete, event->source, event->relative_direction);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pointer_frame(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_frame_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(pointer, layer, pointer);
|
||||||
|
wlr_seat_pointer_send_frame(layer->seat);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_pointer_interface pointer_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_seat_input_router_layer-pointer",
|
||||||
|
},
|
||||||
|
.position = pointer_position,
|
||||||
|
.button = pointer_button,
|
||||||
|
.axis = pointer_axis,
|
||||||
|
.frame = pointer_frame,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void touch_position(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_position_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
|
||||||
|
struct wlr_seat_input_router_layer_touch_point *point = &layer->touch_points[event->index];
|
||||||
|
struct wlr_surface *surface = wlr_input_router_focus_get_surface(event->focus);
|
||||||
|
if (surface == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double surface_x, surface_y;
|
||||||
|
if (!wlr_input_router_get_surface_position(layer->router, surface, &surface_x, &surface_y)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
double sx = event->x - surface_x, sy = event->y - surface_y;
|
||||||
|
|
||||||
|
wl_fixed_t sx_fixed = wl_fixed_from_double(sx), sy_fixed = wl_fixed_from_double(sy);
|
||||||
|
if (point->sx == sx_fixed && point->sy == sy_fixed) {
|
||||||
|
// Avoid sending same values
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
point->sx = sx_fixed;
|
||||||
|
point->sy = sy_fixed;
|
||||||
|
|
||||||
|
struct wl_resource *resource;
|
||||||
|
wl_resource_for_each(resource, &point->seat_client->touches) {
|
||||||
|
wl_touch_send_motion(resource, event->time_msec, event->id, sx_fixed, sy_fixed);
|
||||||
|
}
|
||||||
|
point->seat_client->needs_touch_frame = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t touch_down(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_down_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
|
||||||
|
struct wlr_seat_input_router_layer_touch_point *point = &layer->touch_points[event->index];
|
||||||
|
init_touch_point(point);
|
||||||
|
|
||||||
|
struct wlr_surface *surface = wlr_input_router_focus_get_surface(event->focus);
|
||||||
|
if (surface == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double surface_x, surface_y;
|
||||||
|
if (!wlr_input_router_get_surface_position(layer->router, surface, &surface_x, &surface_y)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
double sx = event->x - surface_x, sy = event->y - surface_y;
|
||||||
|
|
||||||
|
struct wlr_seat_client *seat_client = wlr_seat_client_for_wl_client(layer->seat,
|
||||||
|
wl_resource_get_client(surface->resource));
|
||||||
|
if (seat_client == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
point->seat_client = seat_client;
|
||||||
|
wl_signal_add(&seat_client->events.destroy, &point->seat_client_destroy);
|
||||||
|
|
||||||
|
wl_fixed_t sx_fixed = wl_fixed_from_double(sx), sy_fixed = wl_fixed_from_double(sy);
|
||||||
|
point->sx = sx_fixed;
|
||||||
|
point->sy = sy_fixed;
|
||||||
|
|
||||||
|
uint32_t serial = wlr_seat_client_next_serial(seat_client);
|
||||||
|
|
||||||
|
struct wl_resource *resource;
|
||||||
|
wl_resource_for_each(resource, &seat_client->touches) {
|
||||||
|
wl_touch_send_down(resource, serial, event->time_msec, surface->resource,
|
||||||
|
event->id, sx_fixed, sy_fixed);
|
||||||
|
}
|
||||||
|
seat_client->needs_touch_frame = true;
|
||||||
|
|
||||||
|
return serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t touch_up(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_up_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
|
||||||
|
struct wlr_seat_input_router_layer_touch_point *point = &layer->touch_points[event->index];
|
||||||
|
struct wlr_seat_client *seat_client = point->seat_client;
|
||||||
|
finish_touch_point(point);
|
||||||
|
|
||||||
|
if (seat_client == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t serial = wlr_seat_client_next_serial(seat_client);
|
||||||
|
|
||||||
|
struct wl_resource *resource;
|
||||||
|
wl_resource_for_each(resource, &seat_client->touches) {
|
||||||
|
wl_touch_send_up(resource, serial, event->time_msec, event->id);
|
||||||
|
}
|
||||||
|
seat_client->needs_touch_frame = true;
|
||||||
|
|
||||||
|
return serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touch_cancel(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_cancel_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
|
||||||
|
struct wlr_seat_input_router_layer_touch_point *point = &layer->touch_points[event->index];
|
||||||
|
struct wlr_seat_client *seat_client = point->seat_client;
|
||||||
|
if (seat_client == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancels are client-wide
|
||||||
|
for (size_t i = 0; i < touch->n_points; i++) {
|
||||||
|
point = &layer->touch_points[i];
|
||||||
|
if (point->seat_client == seat_client) {
|
||||||
|
clear_touch_point_seat_client(point);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wl_resource *resource;
|
||||||
|
wl_resource_for_each(resource, &seat_client->touches) {
|
||||||
|
wl_touch_send_cancel(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void touch_frame(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_frame_event *event) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < touch->n_points; i++) {
|
||||||
|
struct wlr_seat_input_router_layer_touch_point *point = &layer->touch_points[i];
|
||||||
|
struct wlr_seat_client *seat_client = point->seat_client;
|
||||||
|
if (seat_client != NULL && seat_client->needs_touch_frame) {
|
||||||
|
struct wl_resource *resource;
|
||||||
|
wl_resource_for_each(resource, &seat_client->touches) {
|
||||||
|
wl_touch_send_frame(resource);
|
||||||
|
}
|
||||||
|
seat_client->needs_touch_frame = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_touch_interface touch_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_seat_input_router_layer-touch",
|
||||||
|
},
|
||||||
|
.position = touch_position,
|
||||||
|
.down = touch_down,
|
||||||
|
.up = touch_up,
|
||||||
|
.cancel = touch_cancel,
|
||||||
|
.frame = touch_frame,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_router_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(listener, layer, router_destroy);
|
||||||
|
wlr_seat_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_seat_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = wl_container_of(listener, layer, seat_destroy);
|
||||||
|
wlr_seat_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_seat_input_router_layer_register(int32_t priority) {
|
||||||
|
if (!wlr_input_router_keyboard_register_interface(&keyboard_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_input_router_pointer_register_interface(&pointer_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_input_router_touch_register_interface(&touch_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_seat_input_router_layer *wlr_seat_input_router_layer_create(
|
||||||
|
struct wlr_input_router *router, struct wlr_seat *seat) {
|
||||||
|
struct wlr_seat_input_router_layer *layer = calloc(1, sizeof(*layer));
|
||||||
|
if (layer == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_init(&layer->keyboard, router, &keyboard_impl);
|
||||||
|
wlr_input_router_pointer_init(&layer->pointer, router, &pointer_impl);
|
||||||
|
|
||||||
|
wlr_input_router_touch_init(&layer->touch, router, &touch_impl);
|
||||||
|
for (size_t i = 0; i < layer->touch.n_points; i++) {
|
||||||
|
init_touch_point(&layer->touch_points[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->router = router;
|
||||||
|
layer->router_destroy.notify = handle_router_destroy;
|
||||||
|
wl_signal_add(&router->events.destroy, &layer->router_destroy);
|
||||||
|
|
||||||
|
layer->seat = seat;
|
||||||
|
layer->seat_destroy.notify = handle_seat_destroy;
|
||||||
|
wl_signal_add(&seat->events.destroy, &layer->seat_destroy);
|
||||||
|
|
||||||
|
wl_signal_init(&layer->events.destroy);
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_seat_input_router_layer_destroy(struct wlr_seat_input_router_layer *layer) {
|
||||||
|
if (layer == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_emit_mutable(&layer->events.destroy, NULL);
|
||||||
|
|
||||||
|
assert(wl_list_empty(&layer->events.destroy.listener_list));
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_finish(&layer->keyboard);
|
||||||
|
wlr_input_router_pointer_finish(&layer->pointer);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < layer->touch.n_points; i++) {
|
||||||
|
finish_touch_point(&layer->touch_points[i]);
|
||||||
|
}
|
||||||
|
wlr_input_router_touch_finish(&layer->touch);
|
||||||
|
|
||||||
|
wl_list_remove(&layer->router_destroy.link);
|
||||||
|
wl_list_remove(&layer->seat_destroy.link);
|
||||||
|
free(layer);
|
||||||
|
}
|
||||||
105
types/input_router/session.c
Normal file
105
types/input_router/session.c
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/backend/session.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/types/wlr_seat.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
static uint32_t keyboard_key(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_key_event *event) {
|
||||||
|
struct wlr_session_input_router_layer *layer = wl_container_of(keyboard, layer, keyboard);
|
||||||
|
|
||||||
|
struct xkb_state *xkb_state = layer->keyboard.device->xkb_state;
|
||||||
|
|
||||||
|
struct wlr_input_router_keyboard_key_event copy;
|
||||||
|
if (xkb_state != NULL) {
|
||||||
|
bool intercepted = false;
|
||||||
|
|
||||||
|
const xkb_keysym_t *syms;
|
||||||
|
int n_syms = xkb_state_key_get_syms(xkb_state, event->key + 8, &syms);
|
||||||
|
for (int i = 0; i < n_syms; i++) {
|
||||||
|
xkb_keysym_t sym = syms[i];
|
||||||
|
if (sym >= XKB_KEY_XF86Switch_VT_1 && sym <= XKB_KEY_XF86Switch_VT_12) {
|
||||||
|
copy.intercepted = true;
|
||||||
|
|
||||||
|
unsigned int vt = sym + 1 - XKB_KEY_XF86Switch_VT_1;
|
||||||
|
wlr_session_change_vt(layer->session, vt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intercepted) {
|
||||||
|
copy = *event;
|
||||||
|
copy.intercepted = true;
|
||||||
|
event = ©
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wlr_input_router_keyboard_notify_key(keyboard, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_keyboard_interface keyboard_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_session_input_router_layer-keyboard",
|
||||||
|
},
|
||||||
|
.key = keyboard_key,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_router_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_session_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, router_destroy);
|
||||||
|
wlr_session_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_session_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_session_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, session_destroy);
|
||||||
|
wlr_session_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_session_input_router_layer_register(int32_t priority) {
|
||||||
|
if (!wlr_input_router_keyboard_register_interface(&keyboard_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_session_input_router_layer *wlr_session_input_router_layer_create(
|
||||||
|
struct wlr_input_router *router, struct wlr_session *session) {
|
||||||
|
struct wlr_session_input_router_layer *layer = calloc(1, sizeof(*layer));
|
||||||
|
if (layer == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_init(&layer->keyboard,
|
||||||
|
router, &keyboard_impl);
|
||||||
|
|
||||||
|
layer->router = router;
|
||||||
|
layer->router_destroy.notify = handle_router_destroy;
|
||||||
|
wl_signal_add(&router->events.destroy, &layer->router_destroy);
|
||||||
|
|
||||||
|
layer->session = session;
|
||||||
|
layer->session_destroy.notify = handle_session_destroy;
|
||||||
|
wl_signal_add(&session->events.destroy, &layer->session_destroy);
|
||||||
|
|
||||||
|
wl_signal_init(&layer->events.destroy);
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_session_input_router_layer_destroy(struct wlr_session_input_router_layer *layer) {
|
||||||
|
if (layer == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_emit_mutable(&layer->events.destroy, NULL);
|
||||||
|
|
||||||
|
assert(wl_list_empty(&layer->events.destroy.listener_list));
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_finish(&layer->keyboard);
|
||||||
|
|
||||||
|
wl_list_remove(&layer->router_destroy.link);
|
||||||
|
wl_list_remove(&layer->session_destroy.link);
|
||||||
|
|
||||||
|
free(layer);
|
||||||
|
}
|
||||||
251
types/input_router/text_input.c
Normal file
251
types/input_router/text_input.c
Normal file
|
|
@ -0,0 +1,251 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/types/wlr_compositor.h>
|
||||||
|
#include <wlr/types/wlr_text_input_v3.h>
|
||||||
|
#include "wlr/util/log.h"
|
||||||
|
|
||||||
|
struct text_input {
|
||||||
|
struct wlr_text_input_v3_input_router_layer *layer;
|
||||||
|
struct wlr_text_input_v3 *wlr_text_input;
|
||||||
|
|
||||||
|
struct wl_list link;
|
||||||
|
|
||||||
|
struct wl_listener destroy;
|
||||||
|
struct wl_listener enable;
|
||||||
|
struct wl_listener disable;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO: improve wlr_text_input_v3 focus API
|
||||||
|
static void text_input_safe_enter(struct text_input *text_input, struct wlr_surface *surface) {
|
||||||
|
struct wlr_text_input_v3 *wlr_text_input = text_input->wlr_text_input;
|
||||||
|
|
||||||
|
if (surface != NULL && wl_resource_get_client(wlr_text_input->resource) !=
|
||||||
|
wl_resource_get_client(surface->resource)) {
|
||||||
|
surface = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wlr_text_input->focused_surface == surface) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wlr_text_input->focused_surface != NULL) {
|
||||||
|
wlr_text_input_v3_send_leave(wlr_text_input);
|
||||||
|
}
|
||||||
|
if (surface != NULL) {
|
||||||
|
wlr_text_input_v3_send_enter(wlr_text_input, surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_active_text_input(struct wlr_text_input_v3_input_router_layer *layer) {
|
||||||
|
struct wlr_text_input_v3 *active_text_input = NULL;
|
||||||
|
struct wlr_surface *surface = wlr_input_router_focus_get_surface(&layer->keyboard.focus);
|
||||||
|
if (surface != NULL) {
|
||||||
|
struct text_input *text_input;
|
||||||
|
wl_list_for_each(text_input, &layer->text_inputs, link) {
|
||||||
|
struct wlr_text_input_v3 *wlr_text_input = text_input->wlr_text_input;
|
||||||
|
if (wlr_text_input->current_enabled && wlr_text_input->focused_surface == surface) {
|
||||||
|
active_text_input = wlr_text_input;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (layer->active_text_input == active_text_input) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
layer->active_text_input = active_text_input;
|
||||||
|
|
||||||
|
struct wlr_text_input_v3_input_router_layer_set_active_event event = {
|
||||||
|
.active_text_input = active_text_input,
|
||||||
|
};
|
||||||
|
wl_signal_emit_mutable(&layer->events.set_active_text_input, &event);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy_text_input(struct text_input *text_input) {
|
||||||
|
wl_list_remove(&text_input->link);
|
||||||
|
|
||||||
|
struct wlr_text_input_v3_input_router_layer *layer = text_input->layer;
|
||||||
|
if (layer->active_text_input == text_input->wlr_text_input) {
|
||||||
|
update_active_text_input(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_remove(&text_input->destroy.link);
|
||||||
|
wl_list_remove(&text_input->enable.link);
|
||||||
|
wl_list_remove(&text_input->disable.link);
|
||||||
|
free(text_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void text_input_handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct text_input *text_input = wl_container_of(listener, text_input, destroy);
|
||||||
|
destroy_text_input(text_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void text_input_handle_enable(struct wl_listener *listener, void *data) {
|
||||||
|
struct text_input *text_input = wl_container_of(listener, text_input, enable);
|
||||||
|
struct wlr_text_input_v3_input_router_layer *layer = text_input->layer;
|
||||||
|
if (layer->active_text_input == NULL) {
|
||||||
|
update_active_text_input(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void text_input_handle_disable(struct wl_listener *listener, void *data) {
|
||||||
|
struct text_input *text_input = wl_container_of(listener, text_input, disable);
|
||||||
|
struct wlr_text_input_v3_input_router_layer *layer = text_input->layer;
|
||||||
|
if (layer->active_text_input == text_input->wlr_text_input) {
|
||||||
|
update_active_text_input(layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_text_input(struct wlr_text_input_v3_input_router_layer *layer,
|
||||||
|
struct wlr_text_input_v3 *wlr_text_input) {
|
||||||
|
if (wlr_text_input->seat != layer->seat) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct text_input *text_input = calloc(1, sizeof(*text_input));
|
||||||
|
if (text_input == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
text_input->wlr_text_input = wlr_text_input;
|
||||||
|
text_input->layer = layer;
|
||||||
|
|
||||||
|
wl_list_insert(&layer->text_inputs, &text_input->link);
|
||||||
|
|
||||||
|
text_input->destroy.notify = text_input_handle_destroy;
|
||||||
|
wl_signal_add(&wlr_text_input->events.destroy, &text_input->destroy);
|
||||||
|
text_input->enable.notify = text_input_handle_enable;
|
||||||
|
wl_signal_add(&wlr_text_input->events.enable, &text_input->enable);
|
||||||
|
text_input->disable.notify = text_input_handle_disable;
|
||||||
|
wl_signal_add(&wlr_text_input->events.disable, &text_input->disable);
|
||||||
|
|
||||||
|
struct wlr_surface *surface = wlr_input_router_focus_get_surface(&layer->keyboard.focus);
|
||||||
|
text_input_safe_enter(text_input, surface);
|
||||||
|
update_active_text_input(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t keyboard_focus(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_focus_event *event) {
|
||||||
|
struct wlr_text_input_v3_input_router_layer *layer =
|
||||||
|
wl_container_of(keyboard, layer, keyboard);
|
||||||
|
|
||||||
|
// Relay the event first; "the text-input focus follows the keyboard focus".
|
||||||
|
uint32_t serial = wlr_input_router_keyboard_notify_focus(keyboard, event);
|
||||||
|
|
||||||
|
struct wlr_surface *surface = wlr_input_router_focus_get_surface(event->focus);
|
||||||
|
struct text_input *text_input;
|
||||||
|
wl_list_for_each(text_input, &layer->text_inputs, link) {
|
||||||
|
text_input_safe_enter(text_input, surface);
|
||||||
|
}
|
||||||
|
update_active_text_input(layer);
|
||||||
|
|
||||||
|
return serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_keyboard_interface keyboard_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_text_input_v3_input_router_layer-keyboard",
|
||||||
|
},
|
||||||
|
.focus = keyboard_focus,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_manager_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_text_input_v3_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, manager_destroy);
|
||||||
|
wlr_text_input_v3_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_manager_text_input(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_text_input_v3_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, manager_text_input);
|
||||||
|
struct wlr_text_input_v3 *wlr_text_input = data;
|
||||||
|
create_text_input(layer, wlr_text_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_router_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_text_input_v3_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, router_destroy);
|
||||||
|
wlr_text_input_v3_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_seat_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_text_input_v3_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, seat_destroy);
|
||||||
|
wlr_text_input_v3_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_text_input_v3_input_router_layer_register(int32_t priority) {
|
||||||
|
if (!wlr_input_router_keyboard_register_interface(&keyboard_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_text_input_v3_input_router_layer *wlr_text_input_v3_input_router_layer_create(
|
||||||
|
struct wlr_input_router *router, struct wlr_text_input_manager_v3 *manager,
|
||||||
|
struct wlr_seat *seat) {
|
||||||
|
struct wlr_text_input_v3_input_router_layer *layer = calloc(1, sizeof(*layer));
|
||||||
|
if (layer == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_init(&layer->keyboard,
|
||||||
|
router, &keyboard_impl);
|
||||||
|
|
||||||
|
layer->manager = manager;
|
||||||
|
layer->manager_destroy.notify = handle_manager_destroy;
|
||||||
|
wl_signal_add(&manager->events.destroy, &layer->manager_destroy);
|
||||||
|
layer->manager_text_input.notify = handle_manager_text_input;
|
||||||
|
wl_signal_add(&manager->events.text_input, &layer->manager_text_input);
|
||||||
|
|
||||||
|
layer->router = router;
|
||||||
|
layer->router_destroy.notify = handle_router_destroy;
|
||||||
|
wl_signal_add(&router->events.destroy, &layer->router_destroy);
|
||||||
|
|
||||||
|
layer->seat = seat;
|
||||||
|
layer->seat_destroy.notify = handle_seat_destroy;
|
||||||
|
wl_signal_add(&seat->events.destroy, &layer->seat_destroy);
|
||||||
|
|
||||||
|
wl_list_init(&layer->text_inputs);
|
||||||
|
|
||||||
|
struct wlr_text_input_v3 *wlr_text_input;
|
||||||
|
wl_list_for_each(wlr_text_input, &manager->text_inputs, link) {
|
||||||
|
create_text_input(layer, wlr_text_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_init(&layer->events.destroy);
|
||||||
|
wl_signal_init(&layer->events.set_active_text_input);
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_text_input_v3_input_router_layer_destroy(
|
||||||
|
struct wlr_text_input_v3_input_router_layer *layer) {
|
||||||
|
if (layer == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_emit_mutable(&layer->events.destroy, NULL);
|
||||||
|
|
||||||
|
assert(wl_list_empty(&layer->events.destroy.listener_list));
|
||||||
|
assert(wl_list_empty(&layer->events.set_active_text_input.listener_list));
|
||||||
|
|
||||||
|
layer->active_text_input = NULL;
|
||||||
|
|
||||||
|
struct text_input *text_input, *tmp;
|
||||||
|
wl_list_for_each_safe(text_input, tmp, &layer->text_inputs, link) {
|
||||||
|
destroy_text_input(text_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_finish(&layer->keyboard);
|
||||||
|
|
||||||
|
wl_list_remove(&layer->manager_destroy.link);
|
||||||
|
wl_list_remove(&layer->manager_text_input.link);
|
||||||
|
|
||||||
|
wl_list_remove(&layer->router_destroy.link);
|
||||||
|
wl_list_remove(&layer->seat_destroy.link);
|
||||||
|
|
||||||
|
free(layer);
|
||||||
|
}
|
||||||
164
types/input_router/touch.c
Normal file
164
types/input_router/touch.c
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
static struct wlr_input_router_handler_priority_list touch_priority_list = {0};
|
||||||
|
|
||||||
|
static struct wlr_input_router_touch_point *find_point(
|
||||||
|
struct wlr_input_router_touch *touch, int32_t id) {
|
||||||
|
for (size_t i = 0; i < touch->n_points; i++) {
|
||||||
|
if (touch->points[i].id == id) {
|
||||||
|
return &touch->points[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void remove_point(struct wlr_input_router_touch *touch,
|
||||||
|
struct wlr_input_router_touch_point *point) {
|
||||||
|
struct wlr_input_router_touch_point *last = &touch->points[--touch->n_points];
|
||||||
|
point->x = last->x;
|
||||||
|
point->y = last->y;
|
||||||
|
wlr_input_router_focus_copy(&point->focus, &last->focus);
|
||||||
|
wlr_input_router_focus_finish(&last->focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_touch_notify_position(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_position_event *event) {
|
||||||
|
while ((touch = wl_container_of(touch->base.next, touch, base)) != NULL) {
|
||||||
|
struct wlr_input_router_touch_point *point = find_point(touch, event->id);
|
||||||
|
if (point == NULL) {
|
||||||
|
// Skip silently to avoid noise
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
point->x = event->x;
|
||||||
|
point->y = event->y;
|
||||||
|
wlr_input_router_focus_copy(&point->focus, event->focus);
|
||||||
|
|
||||||
|
if (touch->impl->position != NULL) {
|
||||||
|
struct wlr_input_router_touch_position_event relayed = *event;
|
||||||
|
relayed.index = point - touch->points;
|
||||||
|
touch->impl->position(touch, &relayed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_touch_notify_down(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_down_event *event) {
|
||||||
|
while ((touch = wl_container_of(touch->base.next, touch, base)) != NULL) {
|
||||||
|
struct wlr_input_router_touch_point *point = find_point(touch, event->id);
|
||||||
|
if (find_point(touch, event->id) != NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "%s received down for an existing touch point %"PRIi32,
|
||||||
|
touch->impl->base.name, event->id);
|
||||||
|
return 0;
|
||||||
|
} else if (touch->n_points == WLR_INPUT_ROUTER_MAX_TOUCH_POINTS) {
|
||||||
|
wlr_log(WLR_ERROR, "%s has too many touch points, ignoring %"PRIi32,
|
||||||
|
touch->impl->base.name, event->id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
point = &touch->points[touch->n_points++];
|
||||||
|
wlr_input_router_focus_init(&point->focus);
|
||||||
|
|
||||||
|
point->id = event->id;
|
||||||
|
point->x = event->x;
|
||||||
|
point->y = event->y;
|
||||||
|
wlr_input_router_focus_copy(&point->focus, event->focus);
|
||||||
|
|
||||||
|
if (touch->impl->down != NULL) {
|
||||||
|
struct wlr_input_router_touch_down_event relayed = *event;
|
||||||
|
relayed.index = point - touch->points;
|
||||||
|
return touch->impl->down(touch, &relayed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t wlr_input_router_touch_notify_up(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_up_event *event) {
|
||||||
|
while ((touch = wl_container_of(touch->base.next, touch, base)) != NULL) {
|
||||||
|
struct wlr_input_router_touch_point *point = find_point(touch, event->id);
|
||||||
|
if (point == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "%s received up for an unknown touch point %"PRIi32,
|
||||||
|
touch->impl->base.name, event->id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
remove_point(touch, point);
|
||||||
|
|
||||||
|
if (touch->impl->up != NULL) {
|
||||||
|
struct wlr_input_router_touch_up_event relayed = *event;
|
||||||
|
relayed.index = point - touch->points;
|
||||||
|
return touch->impl->up(touch, &relayed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_touch_notify_cancel(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_cancel_event *event) {
|
||||||
|
while ((touch = wl_container_of(touch->base.next, touch, base)) != NULL) {
|
||||||
|
struct wlr_input_router_touch_point *point = find_point(touch, event->id);
|
||||||
|
if (point == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "%s received cancel for an unknown touch point %"PRIi32,
|
||||||
|
touch->impl->base.name, event->id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
remove_point(touch, point);
|
||||||
|
|
||||||
|
if (touch->impl->cancel != NULL) {
|
||||||
|
struct wlr_input_router_touch_cancel_event relayed = *event;
|
||||||
|
relayed.index = point - touch->points;
|
||||||
|
touch->impl->cancel(touch, &relayed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_touch_notify_frame(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_frame_event *event) {
|
||||||
|
while ((touch = wl_container_of(touch->base.next, touch, base)) != NULL) {
|
||||||
|
if (touch->impl->frame != NULL) {
|
||||||
|
touch->impl->frame(touch, event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_input_router_touch_register_interface(
|
||||||
|
const struct wlr_input_router_touch_interface *iface, int32_t priority) {
|
||||||
|
return wlr_input_router_register_handler_interface(&iface->base,
|
||||||
|
priority, &touch_priority_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_touch_init(struct wlr_input_router_touch *touch,
|
||||||
|
struct wlr_input_router *router, const struct wlr_input_router_touch_interface *impl) {
|
||||||
|
*touch = (struct wlr_input_router_touch){
|
||||||
|
.impl = impl,
|
||||||
|
};
|
||||||
|
wlr_input_router_handler_init(&touch->base, &router->touch.base,
|
||||||
|
&impl->base, &touch_priority_list);
|
||||||
|
|
||||||
|
struct wlr_input_router_touch *next = wl_container_of(touch->base.next, next, base);
|
||||||
|
if (next != NULL) {
|
||||||
|
for (size_t i = 0; i < next->n_points; i++) {
|
||||||
|
struct wlr_input_router_touch_point *dst = &touch->points[i];
|
||||||
|
wlr_input_router_focus_init(&dst->focus);
|
||||||
|
|
||||||
|
const struct wlr_input_router_touch_point *src = &next->points[i];
|
||||||
|
dst->id = src->id;
|
||||||
|
dst->x = src->x;
|
||||||
|
dst->y = src->y;
|
||||||
|
wlr_input_router_focus_copy(&dst->focus, &src->focus);
|
||||||
|
}
|
||||||
|
touch->n_points = next->n_points;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_input_router_touch_finish(struct wlr_input_router_touch *touch) {
|
||||||
|
for (size_t i = 0; i < touch->n_points; i++) {
|
||||||
|
wlr_input_router_focus_finish(&touch->points[i].focus);
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_handler_finish(&touch->base);
|
||||||
|
}
|
||||||
238
types/input_router/xdg_popup_grab.c
Normal file
238
types/input_router/xdg_popup_grab.c
Normal file
|
|
@ -0,0 +1,238 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <wlr/types/wlr_input_router.h>
|
||||||
|
#include <wlr/types/wlr_xdg_shell.h>
|
||||||
|
#include <wlr/util/addon.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
|
||||||
|
// TODO: better xdg_popup grab state management
|
||||||
|
|
||||||
|
static const struct wlr_input_router_focus *filter_focus(
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *layer,
|
||||||
|
const struct wlr_input_router_focus *focus) {
|
||||||
|
struct wlr_surface *surface = wlr_input_router_focus_get_surface(focus);
|
||||||
|
return surface != NULL && wl_resource_get_client(surface->resource) ==
|
||||||
|
wl_resource_get_client(layer->popup->resource) ? focus : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dismiss_grab(struct wlr_xdg_popup_grab_input_router_layer *layer) {
|
||||||
|
struct wlr_xdg_popup *popup = layer->popup;
|
||||||
|
wlr_xdg_popup_grab_input_router_layer_destroy(layer);
|
||||||
|
|
||||||
|
// Find the grabbing popup chain start
|
||||||
|
struct wlr_surface *parent;
|
||||||
|
while ((parent = popup->parent) != NULL) {
|
||||||
|
struct wlr_xdg_popup *parent_popup = wlr_xdg_popup_try_from_wlr_surface(parent);
|
||||||
|
// Note: wlr_xdg_popup.seat is non-NULL if it's a grabbing popup
|
||||||
|
if (parent_popup == NULL || parent_popup->seat == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
popup = parent_popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_xdg_popup_destroy(popup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t keyboard_focus(struct wlr_input_router_keyboard *keyboard,
|
||||||
|
const struct wlr_input_router_keyboard_focus_event *event) {
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *layer =
|
||||||
|
wl_container_of(keyboard, layer, keyboard);
|
||||||
|
|
||||||
|
struct wlr_input_router_keyboard_focus_event relayed = *event;
|
||||||
|
relayed.focus = &layer->keyboard_focus;
|
||||||
|
return wlr_input_router_keyboard_notify_focus(keyboard, &relayed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_keyboard_interface keyboard_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_xdg_popup_grab_input_router_layer-keyboard",
|
||||||
|
},
|
||||||
|
.focus = keyboard_focus,
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t pointer_position(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_position_event *event) {
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *layer = wl_container_of(pointer, layer, pointer);
|
||||||
|
|
||||||
|
struct wlr_input_router_pointer_position_event relayed = *event;
|
||||||
|
relayed.focus = event->explicit_focus ? event->focus : filter_focus(layer, event->focus);
|
||||||
|
relayed.explicit_focus = true;
|
||||||
|
return wlr_input_router_pointer_notify_position(pointer, &relayed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t pointer_button(struct wlr_input_router_pointer *pointer,
|
||||||
|
const struct wlr_input_router_pointer_button_event *event) {
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *layer = wl_container_of(pointer, layer, pointer);
|
||||||
|
uint32_t serial = wlr_input_router_pointer_notify_button(pointer, event);
|
||||||
|
|
||||||
|
if (event->state == WL_POINTER_BUTTON_STATE_PRESSED &&
|
||||||
|
filter_focus(layer, &pointer->focus) == NULL) {
|
||||||
|
dismiss_grab(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_pointer_interface pointer_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_xdg_popup_grab_input_router_layer-pointer",
|
||||||
|
},
|
||||||
|
.position = pointer_position,
|
||||||
|
.button = pointer_button,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void touch_position(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_position_event *event) {
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
|
||||||
|
struct wlr_input_router_touch_position_event relayed = *event;
|
||||||
|
relayed.focus = filter_focus(layer, event->focus);
|
||||||
|
wlr_input_router_touch_notify_position(touch, &relayed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t touch_down(struct wlr_input_router_touch *touch,
|
||||||
|
const struct wlr_input_router_touch_down_event *event) {
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *layer = wl_container_of(touch, layer, touch);
|
||||||
|
|
||||||
|
struct wlr_input_router_touch_down_event relayed = *event;
|
||||||
|
relayed.focus = filter_focus(layer, event->focus);
|
||||||
|
uint32_t serial = wlr_input_router_touch_notify_down(touch, &relayed);
|
||||||
|
|
||||||
|
if (relayed.focus == NULL) {
|
||||||
|
dismiss_grab(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_input_router_touch_interface touch_impl = {
|
||||||
|
.base = {
|
||||||
|
.name = "wlr_xdg_popup_grab_input_router_layer-touch",
|
||||||
|
},
|
||||||
|
.position = touch_position,
|
||||||
|
.down = touch_down,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void set_topmost_popup(struct wlr_xdg_popup_grab_input_router_layer *layer,
|
||||||
|
struct wlr_xdg_popup *popup) {
|
||||||
|
layer->popup = popup;
|
||||||
|
|
||||||
|
wl_list_remove(&layer->popup_destroy.link);
|
||||||
|
wl_signal_add(&popup->events.destroy, &layer->popup_destroy);
|
||||||
|
|
||||||
|
wlr_input_router_focus_set_surface(&layer->keyboard_focus, popup->base->surface);
|
||||||
|
wlr_input_router_keyboard_notify_focus(&layer->keyboard,
|
||||||
|
&(struct wlr_input_router_keyboard_focus_event){
|
||||||
|
.focus = &layer->keyboard_focus,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void router_addon_destroy(struct wlr_addon *addon) {
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *layer =
|
||||||
|
wl_container_of(addon, layer, router_addon);
|
||||||
|
wlr_xdg_popup_grab_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct wlr_addon_interface router_addon_impl = {
|
||||||
|
.name = "wlr_xdg_popup_grab_input_router_layer",
|
||||||
|
.destroy = router_addon_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_popup_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *layer =
|
||||||
|
wl_container_of(listener, layer, popup_destroy);
|
||||||
|
struct wlr_surface *parent = layer->popup->parent;
|
||||||
|
if (parent != NULL) {
|
||||||
|
struct wlr_xdg_popup *parent_popup = wlr_xdg_popup_try_from_wlr_surface(parent);
|
||||||
|
// Note: wlr_xdg_popup.seat is non-NULL if it's a grabbing popup
|
||||||
|
if (parent_popup != NULL && parent_popup->seat != NULL) {
|
||||||
|
set_topmost_popup(layer, parent_popup);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_xdg_popup_grab_input_router_layer_destroy(layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wlr_xdg_popup_grab_input_router_layer_register(int32_t priority) {
|
||||||
|
if (!wlr_input_router_keyboard_register_interface(&keyboard_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_input_router_pointer_register_interface(&pointer_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!wlr_input_router_touch_register_interface(&touch_impl, priority)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *wlr_xdg_popup_grab_input_router_layer_get_or_create(
|
||||||
|
struct wlr_input_router *router, struct wlr_xdg_popup *popup) {
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *layer;
|
||||||
|
|
||||||
|
struct wlr_addon *addon = wlr_addon_find(&router->addons, NULL, &router_addon_impl);
|
||||||
|
if (addon != NULL) {
|
||||||
|
layer = wl_container_of(addon, layer, router_addon);
|
||||||
|
set_topmost_popup(layer, popup);
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
layer = calloc(1, sizeof(*layer));
|
||||||
|
if (layer == NULL) {
|
||||||
|
wlr_log(WLR_ERROR, "Allocation failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_init(&layer->keyboard,
|
||||||
|
router, &keyboard_impl);
|
||||||
|
wlr_input_router_focus_init(&layer->keyboard_focus);
|
||||||
|
|
||||||
|
wlr_input_router_pointer_init(&layer->pointer, router, &pointer_impl);
|
||||||
|
|
||||||
|
wlr_input_router_touch_init(&layer->touch, router, &touch_impl);
|
||||||
|
|
||||||
|
layer->popup = popup;
|
||||||
|
layer->popup_destroy.notify = handle_popup_destroy;
|
||||||
|
wl_list_init(&layer->popup_destroy.link);
|
||||||
|
|
||||||
|
layer->router = router;
|
||||||
|
wlr_addon_init(&layer->router_addon, &router->addons, NULL, &router_addon_impl);
|
||||||
|
|
||||||
|
wl_signal_init(&layer->events.destroy);
|
||||||
|
|
||||||
|
set_topmost_popup(layer, popup);
|
||||||
|
|
||||||
|
wlr_input_router_pointer_clear_focus(&layer->pointer);
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_xdg_popup_grab_input_router_layer_destroy(
|
||||||
|
struct wlr_xdg_popup_grab_input_router_layer *layer) {
|
||||||
|
if (layer == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_emit_mutable(&layer->events.destroy, NULL);
|
||||||
|
|
||||||
|
assert(wl_list_empty(&layer->events.destroy.listener_list));
|
||||||
|
|
||||||
|
wlr_input_router_focus_finish(&layer->keyboard_focus);
|
||||||
|
|
||||||
|
wlr_input_router_keyboard_notify_focus(&layer->keyboard,
|
||||||
|
&(struct wlr_input_router_keyboard_focus_event){
|
||||||
|
.focus = &layer->keyboard.focus,
|
||||||
|
});
|
||||||
|
wlr_input_router_keyboard_finish(&layer->keyboard);
|
||||||
|
|
||||||
|
wlr_input_router_pointer_refresh_position(&layer->pointer);
|
||||||
|
wlr_input_router_pointer_finish(&layer->pointer);
|
||||||
|
|
||||||
|
wlr_input_router_touch_finish(&layer->touch);
|
||||||
|
|
||||||
|
wlr_addon_finish(&layer->router_addon);
|
||||||
|
wl_list_remove(&layer->popup_destroy.link);
|
||||||
|
|
||||||
|
free(layer);
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,19 @@ wlr_files += files(
|
||||||
'data_device/wlr_drag.c',
|
'data_device/wlr_drag.c',
|
||||||
'ext_image_capture_source_v1/base.c',
|
'ext_image_capture_source_v1/base.c',
|
||||||
'ext_image_capture_source_v1/output.c',
|
'ext_image_capture_source_v1/output.c',
|
||||||
|
'input_router/drag.c',
|
||||||
|
'input_router/focus.c',
|
||||||
|
'input_router/implicit_grab.c',
|
||||||
|
'input_router/input_method.c',
|
||||||
|
'input_router/keyboard.c',
|
||||||
|
'input_router/pointer.c',
|
||||||
|
'input_router/pointer_constraints.c',
|
||||||
|
'input_router/relative_pointer.c',
|
||||||
|
'input_router/router.c',
|
||||||
|
'input_router/seat.c',
|
||||||
|
'input_router/text_input.c',
|
||||||
|
'input_router/touch.c',
|
||||||
|
'input_router/xdg_popup_grab.c',
|
||||||
'output/cursor.c',
|
'output/cursor.c',
|
||||||
'output/output.c',
|
'output/output.c',
|
||||||
'output/render.c',
|
'output/render.c',
|
||||||
|
|
@ -106,3 +119,9 @@ if features.get('drm-backend')
|
||||||
'wlr_drm_lease_v1.c',
|
'wlr_drm_lease_v1.c',
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
if features.get('session')
|
||||||
|
wlr_files += files(
|
||||||
|
'input_router/session.c',
|
||||||
|
)
|
||||||
|
endif
|
||||||
|
|
|
||||||
|
|
@ -306,6 +306,14 @@ static void xdg_popup_handle_grab(struct wl_client *client,
|
||||||
&popup_grab->keyboard_grab);
|
&popup_grab->keyboard_grab);
|
||||||
wlr_seat_touch_start_grab(seat_client->seat,
|
wlr_seat_touch_start_grab(seat_client->seat,
|
||||||
&popup_grab->touch_grab);
|
&popup_grab->touch_grab);
|
||||||
|
|
||||||
|
struct wlr_xdg_shell_popup_grab_event event = {
|
||||||
|
.popup = popup,
|
||||||
|
.seat_client = seat_client,
|
||||||
|
.serial = serial,
|
||||||
|
};
|
||||||
|
|
||||||
|
wl_signal_emit_mutable(&popup->base->client->shell->events.popup_grab, &event);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xdg_popup_handle_reposition(
|
static void xdg_popup_handle_reposition(
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
|
||||||
assert(wl_list_empty(&xdg_shell->events.new_surface.listener_list));
|
assert(wl_list_empty(&xdg_shell->events.new_surface.listener_list));
|
||||||
assert(wl_list_empty(&xdg_shell->events.new_toplevel.listener_list));
|
assert(wl_list_empty(&xdg_shell->events.new_toplevel.listener_list));
|
||||||
assert(wl_list_empty(&xdg_shell->events.new_popup.listener_list));
|
assert(wl_list_empty(&xdg_shell->events.new_popup.listener_list));
|
||||||
|
assert(wl_list_empty(&xdg_shell->events.popup_grab.listener_list));
|
||||||
assert(wl_list_empty(&xdg_shell->events.destroy.listener_list));
|
assert(wl_list_empty(&xdg_shell->events.destroy.listener_list));
|
||||||
|
|
||||||
wl_list_remove(&xdg_shell->display_destroy.link);
|
wl_list_remove(&xdg_shell->display_destroy.link);
|
||||||
|
|
@ -166,6 +167,7 @@ struct wlr_xdg_shell *wlr_xdg_shell_create(struct wl_display *display,
|
||||||
wl_signal_init(&xdg_shell->events.new_surface);
|
wl_signal_init(&xdg_shell->events.new_surface);
|
||||||
wl_signal_init(&xdg_shell->events.new_toplevel);
|
wl_signal_init(&xdg_shell->events.new_toplevel);
|
||||||
wl_signal_init(&xdg_shell->events.new_popup);
|
wl_signal_init(&xdg_shell->events.new_popup);
|
||||||
|
wl_signal_init(&xdg_shell->events.popup_grab);
|
||||||
wl_signal_init(&xdg_shell->events.destroy);
|
wl_signal_init(&xdg_shell->events.destroy);
|
||||||
|
|
||||||
xdg_shell->display_destroy.notify = handle_display_destroy;
|
xdg_shell->display_destroy.notify = handle_display_destroy;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue