pointer/keyboard: Support more than one focused resource

Sophisticated clients, like those using ClutterGtk, will have more
than one focused resource per client, as both Clutter and GDK will
ask for a wl_pointer / wl_keyboard. Support this naturally using
the same "hack" as Weston: multiple resource lists, where we move
elements from one to the other.
This commit is contained in:
Jasper St. Pierre 2014-04-16 15:11:10 -04:00
parent f1034d0459
commit 339a78718d
5 changed files with 135 additions and 72 deletions

View File

@ -211,7 +211,6 @@ keyboard_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
MetaWaylandKeyboard *keyboard = wl_container_of (listener, keyboard, focus_surface_listener); MetaWaylandKeyboard *keyboard = wl_container_of (listener, keyboard, focus_surface_listener);
keyboard->focus_surface = NULL; keyboard->focus_surface = NULL;
keyboard->focus_resource = NULL;
} }
static gboolean static gboolean
@ -220,34 +219,47 @@ default_grab_key (MetaWaylandKeyboardGrab *grab,
{ {
MetaWaylandKeyboard *keyboard = grab->keyboard; MetaWaylandKeyboard *keyboard = grab->keyboard;
struct wl_resource *resource; struct wl_resource *resource;
uint32_t serial; struct wl_list *l;
resource = keyboard->focus_resource; l = &keyboard->focus_resource_list;
if (resource) if (!wl_list_empty (l))
{ {
struct wl_client *client = wl_resource_get_client (keyboard->focus_surface->resource); struct wl_client *client = wl_resource_get_client (keyboard->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client); struct wl_display *display = wl_client_get_display (client);
serial = wl_display_next_serial (display); uint32_t serial = wl_display_next_serial (display);
wl_resource_for_each (resource, l)
{
wl_keyboard_send_key (resource, serial, time, key, state); wl_keyboard_send_key (resource, serial, time, key, state);
} }
return resource != NULL; return TRUE;
} }
static struct wl_resource * return FALSE;
find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface) }
static void
move_resources (struct wl_list *destination, struct wl_list *source)
{ {
struct wl_client *client; wl_list_insert_list (destination, source);
wl_list_init (source);
}
if (!surface) static void
return NULL; move_resources_for_client (struct wl_list *destination,
struct wl_list *source,
if (!surface->resource) struct wl_client *client)
return NULL; {
struct wl_resource *resource, *tmp;
client = wl_resource_get_client (surface->resource); wl_resource_for_each_safe (resource, tmp, source)
{
return wl_resource_find_for_client (list, client); if (wl_resource_get_client (resource) == client)
{
wl_list_remove (wl_resource_get_link (resource));
wl_list_insert (destination, wl_resource_get_link (resource));
}
}
} }
static void static void
@ -256,10 +268,13 @@ default_grab_modifiers (MetaWaylandKeyboardGrab *grab, uint32_t serial,
uint32_t mods_locked, uint32_t group) uint32_t mods_locked, uint32_t group)
{ {
MetaWaylandKeyboard *keyboard = grab->keyboard; MetaWaylandKeyboard *keyboard = grab->keyboard;
struct wl_resource *resource;
struct wl_list *l;
if (keyboard->focus_resource) l = &keyboard->focus_resource_list;
wl_resource_for_each (resource, l)
{ {
wl_keyboard_send_modifiers (keyboard->focus_resource, serial, mods_depressed, wl_keyboard_send_modifiers (resource, serial, mods_depressed,
mods_latched, mods_locked, group); mods_latched, mods_locked, group);
} }
} }
@ -278,6 +293,7 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
keyboard->xkb_info.keymap_fd = -1; keyboard->xkb_info.keymap_fd = -1;
wl_list_init (&keyboard->resource_list); wl_list_init (&keyboard->resource_list);
wl_list_init (&keyboard->focus_resource_list);
wl_array_init (&keyboard->keys); wl_array_init (&keyboard->keys);
keyboard->focus_surface_listener.notify = keyboard_handle_focus_surface_destroy; keyboard->focus_surface_listener.notify = keyboard_handle_focus_surface_destroy;
@ -418,19 +434,27 @@ void
meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard, meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
MetaWaylandSurface *surface) MetaWaylandSurface *surface)
{ {
if (keyboard->focus_surface == surface && keyboard->focus_resource != NULL) if (keyboard->focus_surface == surface && !wl_list_empty (&keyboard->focus_resource_list))
return; return;
if (keyboard->focus_surface != NULL) if (keyboard->focus_surface != NULL)
{ {
if (keyboard->focus_resource) struct wl_resource *resource;
struct wl_list *l;
l = &keyboard->focus_resource_list;
if (!wl_list_empty (l))
{ {
struct wl_client *client = wl_resource_get_client (keyboard->focus_surface->resource); struct wl_client *client = wl_resource_get_client (keyboard->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client); struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display); uint32_t serial = wl_display_next_serial (display);
wl_keyboard_send_leave (keyboard->focus_resource, serial, keyboard->focus_surface->resource);
keyboard->focus_resource = NULL; wl_resource_for_each (resource, l)
{
wl_keyboard_send_leave (resource, serial, keyboard->focus_surface->resource);
}
move_resources (&keyboard->resource_list, &keyboard->focus_resource_list);
} }
wl_list_remove (&keyboard->focus_surface_listener.link); wl_list_remove (&keyboard->focus_surface_listener.link);
@ -439,24 +463,34 @@ meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
if (surface != NULL) if (surface != NULL)
{ {
struct wl_resource *resource;
struct wl_list *l;
keyboard->focus_surface = surface; keyboard->focus_surface = surface;
wl_resource_add_destroy_listener (keyboard->focus_surface->resource, &keyboard->focus_surface_listener); wl_resource_add_destroy_listener (keyboard->focus_surface->resource, &keyboard->focus_surface_listener);
keyboard->focus_resource = find_resource_for_surface (&keyboard->resource_list, surface); move_resources_for_client (&keyboard->focus_resource_list,
if (keyboard->focus_resource) &keyboard->resource_list,
wl_resource_get_client (keyboard->focus_surface->resource));
l = &keyboard->focus_resource_list;
if (!wl_list_empty (l))
{ {
struct wl_client *client = wl_resource_get_client (keyboard->focus_surface->resource); struct wl_client *client = wl_resource_get_client (keyboard->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client); struct wl_display *display = wl_client_get_display (client);
struct xkb_state *state = keyboard->xkb_info.state; struct xkb_state *state = keyboard->xkb_info.state;
uint32_t serial = wl_display_next_serial (display); uint32_t serial = wl_display_next_serial (display);
wl_keyboard_send_modifiers (keyboard->focus_resource, serial, wl_resource_for_each (resource, l)
{
wl_keyboard_send_modifiers (resource, serial,
xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED), xkb_state_serialize_mods (state, XKB_STATE_MODS_DEPRESSED),
xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED), xkb_state_serialize_mods (state, XKB_STATE_MODS_LATCHED),
xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED), xkb_state_serialize_mods (state, XKB_STATE_MODS_LOCKED),
xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE)); xkb_state_serialize_layout (state, XKB_STATE_LAYOUT_EFFECTIVE));
wl_keyboard_send_enter (keyboard->focus_resource, serial, keyboard->focus_surface->resource, wl_keyboard_send_enter (resource, serial, keyboard->focus_surface->resource,
&keyboard->keys); &keyboard->keys);
}
keyboard->focus_serial = serial; keyboard->focus_serial = serial;
} }

View File

@ -78,10 +78,10 @@ typedef struct
struct _MetaWaylandKeyboard struct _MetaWaylandKeyboard
{ {
struct wl_list resource_list; struct wl_list resource_list;
struct wl_list focus_resource_list;
MetaWaylandSurface *focus_surface; MetaWaylandSurface *focus_surface;
struct wl_listener focus_surface_listener; struct wl_listener focus_surface_listener;
struct wl_resource *focus_resource;
uint32_t focus_serial; uint32_t focus_serial;
MetaWaylandKeyboardGrab *grab; MetaWaylandKeyboardGrab *grab;

View File

@ -60,7 +60,6 @@ pointer_handle_focus_surface_destroy (struct wl_listener *listener, void *data)
MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_surface_listener); MetaWaylandPointer *pointer = wl_container_of (listener, pointer, focus_surface_listener);
pointer->focus_surface = NULL; pointer->focus_surface = NULL;
pointer->focus_resource = NULL;
} }
static void static void
@ -81,9 +80,10 @@ default_grab_motion (MetaWaylandPointerGrab *grab,
{ {
MetaWaylandPointer *pointer = grab->pointer; MetaWaylandPointer *pointer = grab->pointer;
struct wl_resource *resource; struct wl_resource *resource;
struct wl_list *l;
resource = pointer->focus_resource; l = &pointer->focus_resource_list;
if (resource) wl_resource_for_each(resource, l)
{ {
wl_fixed_t sx, sy; wl_fixed_t sx, sy;
@ -100,12 +100,13 @@ default_grab_button (MetaWaylandPointerGrab *grab,
{ {
MetaWaylandPointer *pointer = grab->pointer; MetaWaylandPointer *pointer = grab->pointer;
struct wl_resource *resource; struct wl_resource *resource;
struct wl_list *l;
ClutterEventType event_type; ClutterEventType event_type;
event_type = clutter_event_type (event); event_type = clutter_event_type (event);
resource = pointer->focus_resource; l = &grab->pointer->focus_resource_list;
if (resource) wl_resource_for_each(resource, l)
{ {
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource); struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client); struct wl_display *display = wl_client_get_display (client);
@ -256,6 +257,7 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer)
memset (pointer, 0, sizeof *pointer); memset (pointer, 0, sizeof *pointer);
wl_list_init (&pointer->resource_list); wl_list_init (&pointer->resource_list);
wl_list_init (&pointer->focus_resource_list);
pointer->focus_surface_listener.notify = pointer_handle_focus_surface_destroy; pointer->focus_surface_listener.notify = pointer_handle_focus_surface_destroy;
@ -288,37 +290,54 @@ meta_wayland_pointer_release (MetaWaylandPointer *pointer)
/* Do nothing. */ /* Do nothing. */
} }
static struct wl_resource * static void
find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface) move_resources (struct wl_list *destination, struct wl_list *source)
{ {
struct wl_client *client; wl_list_insert_list (destination, source);
wl_list_init (source);
}
if (!surface) static void
return NULL; move_resources_for_client (struct wl_list *destination,
struct wl_list *source,
g_assert (surface->resource); struct wl_client *client)
client = wl_resource_get_client (surface->resource); {
struct wl_resource *resource, *tmp;
return wl_resource_find_for_client (list, client); wl_resource_for_each_safe (resource, tmp, source)
{
if (wl_resource_get_client (resource) == client)
{
wl_list_remove (wl_resource_get_link (resource));
wl_list_insert (destination, wl_resource_get_link (resource));
}
}
} }
void void
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer, meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface) MetaWaylandSurface *surface)
{ {
if (pointer->focus_surface == surface && pointer->focus_resource != NULL) if (pointer->focus_surface == surface && !wl_list_empty (&pointer->focus_resource_list))
return; return;
if (pointer->focus_surface) if (pointer->focus_surface)
{ {
if (pointer->focus_resource) struct wl_resource *resource;
struct wl_list *l;
l = &pointer->focus_resource_list;
if (!wl_list_empty (l))
{ {
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource); struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client); struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display); uint32_t serial = wl_display_next_serial (display);
wl_pointer_send_leave (pointer->focus_resource, serial, pointer->focus_surface->resource);
pointer->focus_resource = NULL; wl_resource_for_each (resource, l)
{
wl_pointer_send_leave (resource, serial, pointer->focus_surface->resource);
}
move_resources (&pointer->resource_list, &pointer->focus_resource_list);
} }
wl_list_remove (&pointer->focus_surface_listener.link); wl_list_remove (&pointer->focus_surface_listener.link);
@ -327,6 +346,9 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
if (surface != NULL) if (surface != NULL)
{ {
struct wl_resource *resource;
struct wl_list *l;
pointer->focus_surface = surface; pointer->focus_surface = surface;
wl_resource_add_destroy_listener (pointer->focus_surface->resource, &pointer->focus_surface_listener); wl_resource_add_destroy_listener (pointer->focus_surface->resource, &pointer->focus_surface_listener);
@ -336,18 +358,23 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
wl_fixed_to_int (pointer->x), wl_fixed_to_int (pointer->x),
wl_fixed_to_int (pointer->y)); wl_fixed_to_int (pointer->y));
pointer->focus_resource = find_resource_for_surface (&pointer->resource_list, surface); move_resources_for_client (&pointer->focus_resource_list,
if (pointer->focus_resource) &pointer->resource_list,
wl_resource_get_client (pointer->focus_surface->resource));
l = &pointer->focus_resource_list;
if (!wl_list_empty (l))
{ {
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource); struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client); struct wl_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display); uint32_t serial = wl_display_next_serial (display);
wl_resource_for_each (resource, l)
{ {
wl_fixed_t sx, sy; wl_fixed_t sx, sy;
meta_wayland_pointer_get_relative_coordinates (pointer, pointer->focus_surface, &sx, &sy); meta_wayland_pointer_get_relative_coordinates (pointer, pointer->focus_surface, &sx, &sy);
wl_pointer_send_enter (pointer->focus_resource, serial, pointer->focus_surface->resource, sx, sy); wl_pointer_send_enter (resource, serial, pointer->focus_surface->resource, sx, sy);
} }
pointer->focus_serial = serial; pointer->focus_serial = serial;
@ -419,7 +446,6 @@ static void
popup_grab_button (MetaWaylandPointerGrab *grab, popup_grab_button (MetaWaylandPointerGrab *grab,
const ClutterEvent *event) const ClutterEvent *event)
{ {
MetaWaylandPopupGrab *popup_grab = (MetaWaylandPopupGrab*)grab;
MetaWaylandPointer *pointer = grab->pointer; MetaWaylandPointer *pointer = grab->pointer;
if (pointer->focus_surface) if (pointer->focus_surface)

View File

@ -45,10 +45,10 @@ struct _MetaWaylandPointerGrab
struct _MetaWaylandPointer struct _MetaWaylandPointer
{ {
struct wl_list resource_list; struct wl_list resource_list;
struct wl_list focus_resource_list;
MetaWaylandSurface *focus_surface; MetaWaylandSurface *focus_surface;
struct wl_listener focus_surface_listener; struct wl_listener focus_surface_listener;
struct wl_resource *focus_resource;
guint32 focus_serial; guint32 focus_serial;
guint32 click_serial; guint32 click_serial;

View File

@ -301,13 +301,12 @@ static void
handle_scroll_event (MetaWaylandSeat *seat, handle_scroll_event (MetaWaylandSeat *seat,
const ClutterEvent *event) const ClutterEvent *event)
{ {
struct wl_resource *resource;
struct wl_list *l;
wl_fixed_t x_value = 0, y_value = 0; wl_fixed_t x_value = 0, y_value = 0;
notify_motion (seat, event); notify_motion (seat, event);
if (!seat->pointer.focus_resource)
return;
if (clutter_event_is_pointer_emulated (event)) if (clutter_event_is_pointer_emulated (event))
return; return;
@ -342,13 +341,17 @@ handle_scroll_event (MetaWaylandSeat *seat,
return; return;
} }
l = &seat->pointer.focus_resource_list;
wl_resource_for_each (resource, l)
{
if (x_value) if (x_value)
wl_pointer_send_axis (seat->pointer.focus_resource, clutter_event_get_time (event), wl_pointer_send_axis (resource, clutter_event_get_time (event),
WL_POINTER_AXIS_HORIZONTAL_SCROLL, x_value); WL_POINTER_AXIS_HORIZONTAL_SCROLL, x_value);
if (y_value) if (y_value)
wl_pointer_send_axis (seat->pointer.focus_resource, clutter_event_get_time (event), wl_pointer_send_axis (resource, clutter_event_get_time (event),
WL_POINTER_AXIS_VERTICAL_SCROLL, y_value); WL_POINTER_AXIS_VERTICAL_SCROLL, y_value);
} }
}
static int static int
count_buttons (const ClutterEvent *event) count_buttons (const ClutterEvent *event)