Commit 109389ac authored by Jonas Ådahl's avatar Jonas Ådahl Committed by Carlos Garnacho

MetaWaylandPointer: Put client resources in its own struct

Instead of moving around all the bound pointer resources for a client
when changing focus, keep all the resources bound by a client in a per
client struct, and track the focus by having a pointer to the current
active pointer client struct instance.

This will simplify having wl_pointer extensinos sharing the pointer
focus of the wl_pointer by only having to add them to the pointer
client.

https://bugzilla.gnome.org/show_bug.cgi?id=744104
parent b0b08d50
......@@ -58,10 +58,107 @@
#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10)
static MetaWaylandPointerClient *
meta_wayland_pointer_client_new (void)
{
MetaWaylandPointerClient *pointer_client;
pointer_client = g_slice_new0 (MetaWaylandPointerClient);
wl_list_init (&pointer_client->pointer_resources);
return pointer_client;
}
static void
meta_wayland_pointer_client_free (MetaWaylandPointerClient *pointer_client)
{
struct wl_resource *resource;
/* Since we make every wl_pointer resource defunct when we stop advertising
* the pointer capability on the wl_seat, we need to make sure all the
* resources in the pointer client instance gets removed.
*/
wl_resource_for_each (resource, &pointer_client->pointer_resources)
{
wl_list_remove (wl_resource_get_link (resource));
wl_list_init (wl_resource_get_link (resource));
}
g_slice_free (MetaWaylandPointerClient, pointer_client);
}
static gboolean
meta_wayland_pointer_client_is_empty (MetaWaylandPointerClient *pointer_client)
{
return wl_list_empty (&pointer_client->pointer_resources);
}
MetaWaylandPointerClient *
meta_wayland_pointer_get_pointer_client (MetaWaylandPointer *pointer,
struct wl_client *client)
{
return g_hash_table_lookup (pointer->pointer_clients, client);
}
static MetaWaylandPointerClient *
meta_wayland_pointer_ensure_pointer_client (MetaWaylandPointer *pointer,
struct wl_client *client)
{
MetaWaylandPointerClient *pointer_client;
pointer_client = meta_wayland_pointer_get_pointer_client (pointer, client);
if (pointer_client)
return pointer_client;
pointer_client = meta_wayland_pointer_client_new ();
g_hash_table_insert (pointer->pointer_clients, client, pointer_client);
if (!pointer->focus_client &&
pointer->focus_surface &&
wl_resource_get_client (pointer->focus_surface->resource) == client)
pointer->focus_client = pointer_client;
return pointer_client;
}
static void
unbind_resource (struct wl_resource *resource)
meta_wayland_pointer_cleanup_pointer_client (MetaWaylandPointer *pointer,
MetaWaylandPointerClient *pointer_client,
struct wl_client *client)
{
if (meta_wayland_pointer_client_is_empty (pointer_client))
{
if (pointer->focus_client == pointer_client)
pointer->focus_client = NULL;
g_hash_table_remove (pointer->pointer_clients, client);
}
}
void
meta_wayland_pointer_unbind_pointer_client_resource (struct wl_resource *resource)
{
MetaWaylandPointer *pointer = wl_resource_get_user_data (resource);
MetaWaylandPointerClient *pointer_client;
struct wl_client *client = wl_resource_get_client (resource);
wl_list_remove (wl_resource_get_link (resource));
pointer_client = meta_wayland_pointer_get_pointer_client (pointer, client);
if (!pointer_client)
{
/* This happens if all pointer devices were unplugged and no new resources
* were created by the client.
*
* If this is a resource that was previously made defunct, pointer_client
* be non-NULL but it is harmless since the below cleanup call will be
* prevented from removing the pointer client because of valid resources.
*/
return;
}
meta_wayland_pointer_cleanup_pointer_client (pointer,
pointer_client,
client);
}
static void
......@@ -131,17 +228,20 @@ meta_wayland_pointer_send_motion (MetaWaylandPointer *pointer,
const ClutterEvent *event)
{
struct wl_resource *resource;
struct wl_list *l;
uint32_t time;
wl_fixed_t sx, sy;
l = &pointer->focus_resource_list;
wl_resource_for_each(resource, l)
{
wl_fixed_t sx, sy;
if (!pointer->focus_client)
return;
meta_wayland_pointer_get_relative_coordinates (pointer,
pointer->focus_surface,
&sx, &sy);
wl_pointer_send_motion (resource, clutter_event_get_time (event), sx, sy);
time = clutter_event_get_time (event);
meta_wayland_pointer_get_relative_coordinates (pointer,
pointer->focus_surface,
&sx, &sy);
wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
{
wl_pointer_send_motion (resource, time, sx, sy);
}
}
......@@ -150,19 +250,21 @@ meta_wayland_pointer_send_button (MetaWaylandPointer *pointer,
const ClutterEvent *event)
{
struct wl_resource *resource;
struct wl_list *l;
ClutterEventType event_type;
event_type = clutter_event_type (event);
l = &pointer->focus_resource_list;
if (!wl_list_empty (l))
if (pointer->focus_client &&
!wl_list_empty (&pointer->focus_client->pointer_resources))
{
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client);
uint32_t time;
uint32_t button;
uint32_t serial;
time = clutter_event_get_time (event);
button = clutter_event_get_button (event);
switch (button)
{
......@@ -183,10 +285,10 @@ meta_wayland_pointer_send_button (MetaWaylandPointer *pointer,
serial = wl_display_next_serial (display);
wl_resource_for_each(resource, l)
wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
{
wl_pointer_send_button (resource, serial,
clutter_event_get_time (event), button,
time, button,
event_type == CLUTTER_BUTTON_PRESS ? 1 : 0);
}
}
......@@ -241,8 +343,9 @@ meta_wayland_pointer_init (MetaWaylandPointer *pointer,
pointer->display = display;
wl_list_init (&pointer->resource_list);
wl_list_init (&pointer->focus_resource_list);
pointer->pointer_clients =
g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) meta_wayland_pointer_client_free);
pointer->focus_surface_listener.notify = pointer_handle_focus_surface_destroy;
......@@ -265,6 +368,7 @@ meta_wayland_pointer_release (MetaWaylandPointer *pointer)
meta_wayland_pointer_set_focus (pointer, NULL);
set_cursor_surface (pointer, NULL);
g_clear_pointer (&pointer->pointer_clients, g_hash_table_unref);
pointer->display = NULL;
}
......@@ -358,7 +462,6 @@ handle_scroll_event (MetaWaylandPointer *pointer,
const ClutterEvent *event)
{
struct wl_resource *resource;
struct wl_list *l;
wl_fixed_t x_value = 0, y_value = 0;
if (clutter_event_is_pointer_emulated (event))
......@@ -399,15 +502,17 @@ handle_scroll_event (MetaWaylandPointer *pointer,
return;
}
l = &pointer->focus_resource_list;
wl_resource_for_each (resource, l)
if (pointer->focus_client)
{
if (x_value)
wl_pointer_send_axis (resource, clutter_event_get_time (event),
WL_POINTER_AXIS_HORIZONTAL_SCROLL, x_value);
if (y_value)
wl_pointer_send_axis (resource, clutter_event_get_time (event),
WL_POINTER_AXIS_VERTICAL_SCROLL, y_value);
wl_resource_for_each (resource, &pointer->focus_client->pointer_resources)
{
if (x_value)
wl_pointer_send_axis (resource, clutter_event_get_time (event),
WL_POINTER_AXIS_HORIZONTAL_SCROLL, x_value);
if (y_value)
wl_pointer_send_axis (resource, clutter_event_get_time (event),
WL_POINTER_AXIS_VERTICAL_SCROLL, y_value);
}
}
}
......@@ -437,29 +542,6 @@ meta_wayland_pointer_handle_event (MetaWaylandPointer *pointer,
return FALSE;
}
static void
move_resources (struct wl_list *destination, struct wl_list *source)
{
wl_list_insert_list (destination, source);
wl_list_init (source);
}
static void
move_resources_for_client (struct wl_list *destination,
struct wl_list *source,
struct wl_client *client)
{
struct wl_resource *resource, *tmp;
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));
}
}
}
static void
broadcast_focus (MetaWaylandPointer *pointer,
struct wl_resource *resource)
......@@ -482,22 +564,23 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
if (pointer->focus_surface != NULL)
{
struct wl_client *client =
wl_resource_get_client (pointer->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client);
uint32_t serial;
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_display *display = wl_client_get_display (client);
uint32_t serial = wl_display_next_serial (display);
serial = wl_display_next_serial (display);
wl_resource_for_each (resource, l)
if (pointer->focus_client)
{
wl_resource_for_each (resource,
&pointer->focus_client->pointer_resources)
{
wl_pointer_send_leave (resource, serial, pointer->focus_surface->resource);
}
move_resources (&pointer->resource_list, &pointer->focus_resource_list);
pointer->focus_client = NULL;
}
wl_list_remove (&pointer->focus_surface_listener.link);
......@@ -506,8 +589,9 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
if (surface != NULL)
{
struct wl_client *client = wl_resource_get_client (surface->resource);
struct wl_display *display = wl_client_get_display (client);
struct wl_resource *resource;
struct wl_list *l;
ClutterPoint pos;
pointer->focus_surface = surface;
......@@ -521,18 +605,14 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
clutter_get_current_event_time (),
pos.x, pos.y);
move_resources_for_client (&pointer->focus_resource_list,
&pointer->resource_list,
wl_resource_get_client (pointer->focus_surface->resource));
l = &pointer->focus_resource_list;
if (!wl_list_empty (l))
pointer->focus_client =
meta_wayland_pointer_get_pointer_client (pointer, client);
if (pointer->focus_client)
{
struct wl_client *client = wl_resource_get_client (pointer->focus_surface->resource);
struct wl_display *display = wl_client_get_display (client);
pointer->focus_serial = wl_display_next_serial (display);
wl_resource_for_each (resource, l)
wl_resource_for_each (resource,
&pointer->focus_client->pointer_resources)
{
broadcast_focus (pointer, resource);
}
......@@ -707,19 +787,19 @@ meta_wayland_pointer_create_new_resource (MetaWaylandPointer *pointer,
uint32_t id)
{
struct wl_resource *cr;
MetaWaylandPointerClient *pointer_client;
cr = wl_resource_create (client, &wl_pointer_interface, wl_resource_get_version (seat_resource), id);
wl_resource_set_implementation (cr, &pointer_interface, pointer, unbind_resource);
wl_resource_set_implementation (cr, &pointer_interface, pointer,
meta_wayland_pointer_unbind_pointer_client_resource);
if (pointer->focus_surface && wl_resource_get_client (pointer->focus_surface->resource) == client)
{
wl_list_insert (&pointer->focus_resource_list, wl_resource_get_link (cr));
broadcast_focus (pointer, cr);
}
else
{
wl_list_insert (&pointer->resource_list, wl_resource_get_link (cr));
}
pointer_client = meta_wayland_pointer_ensure_pointer_client (pointer, client);
wl_list_insert (&pointer_client->pointer_resources,
wl_resource_get_link (cr));
if (pointer->focus_client == pointer_client)
broadcast_focus (pointer, cr);
}
gboolean
......
......@@ -44,12 +44,17 @@ struct _MetaWaylandPointerGrab
MetaWaylandPointer *pointer;
};
struct _MetaWaylandPointerClient
{
struct wl_list pointer_resources;
};
struct _MetaWaylandPointer
{
struct wl_display *display;
struct wl_list resource_list;
struct wl_list focus_resource_list;
MetaWaylandPointerClient *focus_client;
GHashTable *pointer_clients;
MetaWaylandSurface *focus_surface;
struct wl_listener focus_surface_listener;
......@@ -127,4 +132,8 @@ gboolean meta_wayland_pointer_can_popup (MetaWaylandPointer *pointer,
MetaWaylandSurface *meta_wayland_pointer_get_top_popup (MetaWaylandPointer *pointer);
MetaWaylandPointerClient * meta_wayland_pointer_get_pointer_client (MetaWaylandPointer *pointer,
struct wl_client *client);
void meta_wayland_pointer_unbind_pointer_client_resource (struct wl_resource *resource);
#endif /* META_WAYLAND_POINTER_H */
......@@ -43,4 +43,6 @@ typedef struct _MetaWaylandOutput MetaWaylandOutput;
typedef struct _MetaWaylandSerial MetaWaylandSerial;
typedef struct _MetaWaylandPointerClient MetaWaylandPointerClient;
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment