[mutter/wip/tablet-protocol: 94/100] wayland: Add focus management to MetaWaylandTabletTool
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/tablet-protocol: 94/100] wayland: Add focus management to MetaWaylandTabletTool
- Date: Mon, 25 Jan 2016 22:54:03 +0000 (UTC)
commit c92cf35058e0f89b6e72b0eaabef2e73d8173c79
Author: Carlos Garnacho <carlosg gnome org>
Date: Wed Oct 28 11:08:09 2015 +0100
wayland: Add focus management to MetaWaylandTabletTool
Tools can now switch between surfaces, which implies the emission
of wl_tablet_tool.proximity_in/out events.
src/wayland/meta-wayland-tablet-tool.c | 262 +++++++++++++++++++++++++++++++-
src/wayland/meta-wayland-tablet-tool.h | 11 ++
2 files changed, 269 insertions(+), 4 deletions(-)
---
diff --git a/src/wayland/meta-wayland-tablet-tool.c b/src/wayland/meta-wayland-tablet-tool.c
index a1d57b8..01221ed 100644
--- a/src/wayland/meta-wayland-tablet-tool.c
+++ b/src/wayland/meta-wayland-tablet-tool.c
@@ -30,6 +30,9 @@
#include <wayland-server.h>
#include "tablet-unstable-v1-server-protocol.h"
#include "meta-wayland-private.h"
+#include "meta-surface-actor-wayland.h"
+#include "meta-wayland-tablet.h"
+#include "meta-wayland-tablet-seat.h"
#include "meta-wayland-tablet-tool.h"
static void
@@ -38,6 +41,135 @@ unbind_resource (struct wl_resource *resource)
wl_list_remove (wl_resource_get_link (resource));
}
+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_proximity_in (MetaWaylandTabletTool *tool)
+{
+ struct wl_resource *resource, *tablet_resource;
+ struct wl_client *client;
+
+ client = wl_resource_get_client (tool->focus_surface->resource);
+ tablet_resource = meta_wayland_tablet_lookup_resource (tool->current_tablet,
+ client);
+
+ wl_resource_for_each (resource, &tool->focus_resource_list)
+ {
+ zwp_tablet_tool_v1_send_proximity_in (resource, tool->proximity_serial,
+ tablet_resource,
+ tool->focus_surface->resource);
+ }
+}
+
+static void
+broadcast_proximity_out (MetaWaylandTabletTool *tool)
+{
+ struct wl_resource *resource;
+
+ wl_resource_for_each (resource, &tool->focus_resource_list)
+ {
+ zwp_tablet_tool_v1_send_proximity_out (resource);
+ }
+}
+
+static void
+broadcast_frame (MetaWaylandTabletTool *tool,
+ const ClutterEvent *event)
+{
+ struct wl_resource *resource;
+ guint32 _time = event ? clutter_event_get_time (event) : CLUTTER_CURRENT_TIME;
+
+ wl_resource_for_each (resource, &tool->focus_resource_list)
+ {
+ zwp_tablet_tool_v1_send_frame (resource, _time);
+ }
+}
+
+static void
+meta_wayland_tablet_tool_set_focus (MetaWaylandTabletTool *tool,
+ MetaWaylandSurface *surface,
+ const ClutterEvent *event)
+{
+ if (tool->focus_surface == surface)
+ return;
+
+ if (tool->focus_surface != NULL)
+ {
+ struct wl_list *l;
+
+ l = &tool->focus_resource_list;
+ if (!wl_list_empty (l))
+ {
+ broadcast_proximity_out (tool);
+ broadcast_frame (tool, event);
+ move_resources (&tool->resource_list, &tool->focus_resource_list);
+ }
+
+ wl_list_remove (&tool->focus_surface_destroy_listener.link);
+ tool->focus_surface = NULL;
+ }
+
+ if (surface != NULL)
+ {
+ struct wl_client *client;
+ struct wl_list *l;
+
+ tool->focus_surface = surface;
+ client = wl_resource_get_client (tool->focus_surface->resource);
+ wl_resource_add_destroy_listener (tool->focus_surface->resource,
+ &tool->focus_surface_destroy_listener);
+
+ move_resources_for_client (&tool->focus_resource_list,
+ &tool->resource_list, client);
+
+ l = &tool->focus_resource_list;
+
+ if (!wl_list_empty (l))
+ {
+ struct wl_client *client = wl_resource_get_client (tool->focus_surface->resource);
+ struct wl_display *display = wl_client_get_display (client);
+
+ tool->proximity_serial = wl_display_next_serial (display);
+
+ broadcast_proximity_in (tool);
+ broadcast_frame (tool, event);
+ }
+ }
+}
+
+static void
+tablet_tool_handle_focus_surface_destroy (struct wl_listener *listener,
+ void *data)
+{
+ MetaWaylandTabletTool *tool;
+
+ tool = wl_container_of (listener, tool, focus_surface_destroy_listener);
+ meta_wayland_tablet_tool_set_focus (tool, NULL, NULL);
+}
+
MetaWaylandTabletTool *
meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
ClutterInputDevice *device,
@@ -50,6 +182,9 @@ meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
tool->device = device;
tool->device_tool = device_tool;
wl_list_init (&tool->resource_list);
+ wl_list_init (&tool->focus_resource_list);
+
+ tool->focus_surface_destroy_listener.notify = tablet_tool_handle_focus_surface_destroy;
return tool;
}
@@ -59,6 +194,8 @@ meta_wayland_tablet_tool_free (MetaWaylandTabletTool *tool)
{
struct wl_resource *resource, *next;
+ meta_wayland_tablet_tool_set_focus (tool, NULL, NULL);
+
wl_resource_for_each_safe (resource, next, &tool->resource_list)
{
zwp_tablet_tool_v1_send_removed (resource);
@@ -90,6 +227,24 @@ static const struct zwp_tablet_tool_v1_interface tool_interface = {
tool_destroy
};
+static void
+emit_proximity_in (MetaWaylandTabletTool *tool,
+ struct wl_resource *resource)
+{
+ struct wl_resource *tablet_resource;
+ struct wl_client *client;
+
+ if (!tool->focus_surface)
+ return;
+
+ client = wl_resource_get_client (resource);
+ tablet_resource = meta_wayland_tablet_lookup_resource (tool->current_tablet,
+ client);
+
+ zwp_tablet_tool_v1_send_proximity_in (resource, tool->proximity_serial,
+ tablet_resource, tool->focus_surface->resource);
+}
+
struct wl_resource *
meta_wayland_tablet_tool_create_new_resource (MetaWaylandTabletTool *tool,
struct wl_client *client,
@@ -103,7 +258,17 @@ meta_wayland_tablet_tool_create_new_resource (MetaWaylandTabletTool *tool,
wl_resource_set_implementation (resource, &tool_interface,
tool, unbind_resource);
wl_resource_set_user_data (resource, tool);
- wl_list_insert (&tool->resource_list, wl_resource_get_link (resource));
+
+ if (tool->focus_surface &&
+ wl_resource_get_client (tool->focus_surface->resource) == client)
+ {
+ wl_list_insert (&tool->focus_resource_list, wl_resource_get_link (resource));
+ emit_proximity_in (tool, resource);
+ }
+ else
+ {
+ wl_list_insert (&tool->resource_list, wl_resource_get_link (resource));
+ }
return resource;
}
@@ -112,21 +277,110 @@ struct wl_resource *
meta_wayland_tablet_tool_lookup_resource (MetaWaylandTabletTool *tool,
struct wl_client *client)
{
- if (wl_list_empty (&tool->resource_list))
- return NULL;
+ struct wl_resource *resource = NULL;
+
+ if (!wl_list_empty (&tool->resource_list))
+ resource = wl_resource_find_for_client (&tool->resource_list, client);
+
+ if (!wl_list_empty (&tool->focus_resource_list))
+ resource = wl_resource_find_for_client (&tool->focus_resource_list, client);
+
+ return resource;
+}
+
+static void
+meta_wayland_tablet_tool_account_button (MetaWaylandTabletTool *tool,
+ const ClutterEvent *event)
+{
+ if (event->type == CLUTTER_BUTTON_PRESS)
+ tool->pressed_buttons |= 1 << (event->button.button - 1);
+ else if (event->type == CLUTTER_BUTTON_RELEASE)
+ tool->pressed_buttons &= ~(1 << (event->button.button - 1));
+}
- return wl_resource_find_for_client (&tool->resource_list, client);
+static void
+sync_focus_surface (MetaWaylandTabletTool *tool,
+ const ClutterEvent *event)
+{
+ MetaDisplay *display = meta_get_display ();
+
+ switch (display->event_route)
+ {
+ case META_EVENT_ROUTE_WINDOW_OP:
+ case META_EVENT_ROUTE_COMPOSITOR_GRAB:
+ case META_EVENT_ROUTE_FRAME_BUTTON:
+ /* The compositor has a grab, so remove our focus */
+ meta_wayland_tablet_tool_set_focus (tool, NULL, event);
+ break;
+
+ case META_EVENT_ROUTE_NORMAL:
+ case META_EVENT_ROUTE_WAYLAND_POPUP:
+ meta_wayland_tablet_tool_set_focus (tool, tool->current, event);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static void
+repick_for_event (MetaWaylandTabletTool *tool,
+ const ClutterEvent *for_event)
+{
+ ClutterActor *actor = NULL;
+
+ actor = clutter_event_get_source (for_event);
+
+ if (META_IS_SURFACE_ACTOR_WAYLAND (actor))
+ tool->current = meta_surface_actor_wayland_get_surface (META_SURFACE_ACTOR_WAYLAND (actor));
+ else
+ tool->current = NULL;
+
+ sync_focus_surface (tool, for_event);
}
void
meta_wayland_tablet_tool_update (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
+ switch (event->type)
+ {
+ case CLUTTER_BUTTON_PRESS:
+ case CLUTTER_BUTTON_RELEASE:
+ meta_wayland_tablet_tool_account_button (tool, event);
+ break;
+ case CLUTTER_MOTION:
+ if (!tool->pressed_buttons)
+ repick_for_event (tool, event);
+ break;
+ case CLUTTER_PROXIMITY_IN:
+ tool->current_tablet =
+ meta_wayland_tablet_seat_lookup_tablet (tool->seat,
+ clutter_event_get_source_device (event));
+ break;
+ default:
+ break;
+ }
}
gboolean
meta_wayland_tablet_tool_handle_event (MetaWaylandTabletTool *tool,
const ClutterEvent *event)
{
+ switch (event->type)
+ {
+ case CLUTTER_PROXIMITY_IN:
+ /* We don't have much info here to make anything useful out of it,
+ * wait until the first motion event so we have both coordinates
+ * and tool.
+ */
+ break;
+ case CLUTTER_PROXIMITY_OUT:
+ meta_wayland_tablet_tool_set_focus (tool, NULL, event);
+ break;
+ default:
+ return CLUTTER_EVENT_PROPAGATE;
+ }
+
return CLUTTER_EVENT_STOP;
}
diff --git a/src/wayland/meta-wayland-tablet-tool.h b/src/wayland/meta-wayland-tablet-tool.h
index 04f7db8..12510c4 100644
--- a/src/wayland/meta-wayland-tablet-tool.h
+++ b/src/wayland/meta-wayland-tablet-tool.h
@@ -35,6 +35,17 @@ struct _MetaWaylandTabletTool
ClutterInputDevice *device;
ClutterInputDeviceTool *device_tool;
struct wl_list resource_list;
+ struct wl_list focus_resource_list;
+
+ MetaWaylandSurface *focus_surface;
+ struct wl_listener focus_surface_destroy_listener;
+
+ MetaWaylandSurface *current;
+ guint32 pressed_buttons;
+
+ guint32 proximity_serial;
+
+ MetaWaylandTablet *current_tablet;
};
MetaWaylandTabletTool * meta_wayland_tablet_tool_new (MetaWaylandTabletSeat *seat,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]