[mutter/wip/tablet-protocol: 197/200] wayland: Maintain wl_tablet current focus window and tool.



commit d9e11b11cb6efdbe4a62c9903b0518874bcfd194
Author: Carlos Garnacho <carlosg gnome org>
Date:   Thu Feb 5 12:07:47 2015 +0100

    wayland: Maintain wl_tablet current focus window and tool.
    
    wl_tablet.proximity_in/out events are now sent, along with the necessary
    wl_tablet_manager.tool_added if the tool wasn't known to the focused client

 src/wayland/meta-wayland-tablet.c |  262 ++++++++++++++++++++++++++++++++++++-
 src/wayland/meta-wayland-tablet.h |   11 ++
 2 files changed, 272 insertions(+), 1 deletions(-)
---
diff --git a/src/wayland/meta-wayland-tablet.c b/src/wayland/meta-wayland-tablet.c
index 3d8eea4..81dcbaf 100644
--- a/src/wayland/meta-wayland-tablet.c
+++ b/src/wayland/meta-wayland-tablet.c
@@ -33,6 +33,10 @@
 #include "meta-surface-actor-wayland.h"
 #include "meta-wayland-private.h"
 #include "meta-wayland-tablet.h"
+#include "meta-wayland-tablet-tool.h"
+
+static void meta_wayland_tablet_set_focus          (MetaWaylandTablet  *tablet,
+                                                    MetaWaylandSurface *surface);
 
 static void
 unbind_resource (struct wl_resource *resource)
@@ -40,6 +44,39 @@ 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
+tablet_handle_focus_surface_destroy (struct wl_listener *listener,
+                                     void               *data)
+{
+  MetaWaylandTablet *tablet;
+
+  tablet = wl_container_of (listener, tablet, focus_surface_destroy_listener);
+  meta_wayland_tablet_set_focus (tablet, NULL);
+}
+
 MetaWaylandTablet *
 meta_wayland_tablet_new (ClutterInputDevice       *device,
                          MetaWaylandTabletManager *manager)
@@ -48,9 +85,12 @@ meta_wayland_tablet_new (ClutterInputDevice       *device,
 
   tablet = g_slice_new0 (MetaWaylandTablet);
   wl_list_init (&tablet->resource_list);
+  wl_list_init (&tablet->focus_resource_list);
   tablet->device = device;
   tablet->manager = manager;
 
+  tablet->focus_surface_destroy_listener.notify = tablet_handle_focus_surface_destroy;
+
   tablet->cursor_renderer = meta_cursor_renderer_new ();
   meta_cursor_renderer_set_cursor (tablet->cursor_renderer, NULL);
 
@@ -62,6 +102,9 @@ meta_wayland_tablet_free (MetaWaylandTablet *tablet)
 {
   struct wl_resource *resource, *next;
 
+  meta_wayland_tablet_set_focus (tablet, NULL);
+  g_hash_table_destroy (tablet->tools);
+
   wl_resource_for_each_safe (resource, next, &tablet->resource_list)
     {
       wl_tablet_send_removed (resource);
@@ -72,10 +115,208 @@ meta_wayland_tablet_free (MetaWaylandTablet *tablet)
   g_slice_free (MetaWaylandTablet, tablet);
 }
 
+static struct wl_resource *
+meta_wayland_tablet_ensure_tool_resource_for_client (MetaWaylandTablet *tablet,
+                                                     struct wl_client  *client)
+{
+  struct wl_resource *tool_resource;
+
+  tool_resource = meta_wayland_tablet_tool_lookup_resource (tablet->current_tool,
+                                                            client);
+  if (!tool_resource)
+    {
+      meta_wayland_tablet_manager_notify_tool (tablet->manager, tablet,
+                                               tablet->current_tool, client);
+      tool_resource = meta_wayland_tablet_tool_lookup_resource (tablet->current_tool,
+                                                                client);
+    }
+
+  return tool_resource;
+}
+
+static void
+meta_wayland_tablet_set_focus (MetaWaylandTablet  *tablet,
+                               MetaWaylandSurface *surface)
+{
+  guint32 _time;
+
+  if (tablet->manager->wl_display == NULL)
+    return;
+
+  if (tablet->focus_surface == surface)
+    return;
+
+  _time = clutter_get_current_event_time ();
+
+  if (tablet->focus_surface != NULL)
+    {
+      struct wl_resource *resource;
+      struct wl_list *l;
+
+      l = &tablet->focus_resource_list;
+      if (!wl_list_empty (l))
+        {
+          wl_resource_for_each (resource, l)
+            {
+              wl_tablet_send_proximity_out (resource, _time);
+            }
+
+          move_resources (&tablet->resource_list, &tablet->focus_resource_list);
+        }
+
+      wl_list_remove (&tablet->focus_surface_destroy_listener.link);
+      tablet->focus_surface = NULL;
+    }
+
+  if (surface != NULL)
+    {
+      struct wl_resource *resource, *tool_resource;
+      struct wl_client *client;
+      struct wl_list *l;
+
+      tablet->focus_surface = surface;
+      client = wl_resource_get_client (tablet->focus_surface->resource);
+      wl_resource_add_destroy_listener (tablet->focus_surface->resource,
+                                        &tablet->focus_surface_destroy_listener);
+
+      move_resources_for_client (&tablet->focus_resource_list,
+                                 &tablet->resource_list, client);
+
+      tool_resource = meta_wayland_tablet_ensure_tool_resource_for_client (tablet, client);
+
+      l = &tablet->focus_resource_list;
+      if (!wl_list_empty (l))
+        {
+          struct wl_client *client = wl_resource_get_client (tablet->focus_surface->resource);
+          struct wl_display *display = wl_client_get_display (client);
+
+          tablet->proximity_serial = wl_display_next_serial (display);
+
+          wl_resource_for_each (resource, l)
+            {
+              wl_tablet_send_proximity_in (resource, tablet->proximity_serial, _time,
+                                           tool_resource, tablet->focus_surface->resource);
+            }
+        }
+    }
+}
+
+static void
+emit_proximity_in (MetaWaylandTablet  *tablet,
+                   struct wl_resource *resource)
+{
+  struct wl_resource *tool_resource;
+  struct wl_client *client;
+  guint32 _time;
+
+  if (!tablet->focus_surface || !tablet->current_tool)
+    return;
+
+  _time = clutter_get_current_event_time ();
+  client = wl_resource_get_client (resource);
+  tool_resource = meta_wayland_tablet_ensure_tool_resource_for_client (tablet, client);
+
+  wl_tablet_send_proximity_in (resource, tablet->proximity_serial, _time,
+                               tool_resource, tablet->focus_surface->resource);
+}
+
+static void
+sync_focus_surface (MetaWaylandTablet *tablet)
+{
+  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_set_focus (tablet, NULL);
+      break;
+
+    case META_EVENT_ROUTE_NORMAL:
+    case META_EVENT_ROUTE_WAYLAND_POPUP:
+      meta_wayland_tablet_set_focus (tablet, tablet->current);
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+}
+
+static void
+repick_for_event (MetaWaylandTablet  *tablet,
+                  const ClutterEvent *for_event)
+{
+  ClutterActor *actor = NULL;
+
+  actor = clutter_event_get_source (for_event);
+
+  if (META_IS_SURFACE_ACTOR_WAYLAND (actor))
+    tablet->current = meta_surface_actor_wayland_get_surface (META_SURFACE_ACTOR_WAYLAND (actor));
+  else
+    tablet->current = NULL;
+
+  sync_focus_surface (tablet);
+}
+
+static MetaWaylandTabletTool *
+meta_wayland_tablet_ensure_tool (MetaWaylandTablet      *tablet,
+                                 ClutterInputDeviceTool *device_tool)
+{
+  MetaWaylandTabletTool *tool;
+
+  tool = g_hash_table_lookup (tablet->tools, device_tool);
+
+  if (!tool)
+    {
+      tool = meta_wayland_tablet_tool_new (tablet->device, device_tool);
+      g_hash_table_insert (tablet->tools, device_tool, tool);
+    }
+
+  return tool;
+}
+
+static void
+meta_wayland_tablet_account_button (MetaWaylandTablet  *tablet,
+                                    const ClutterEvent *event)
+{
+  if (event->type == CLUTTER_BUTTON_PRESS)
+    tablet->buttons = g_slist_append (tablet->buttons,
+                                      GUINT_TO_POINTER (event->button.button));
+  else
+    tablet->buttons = g_slist_remove (tablet->buttons,
+                                      GUINT_TO_POINTER (event->button.button));
+}
+
 void
 meta_wayland_tablet_update (MetaWaylandTablet  *tablet,
                             const ClutterEvent *event)
 {
+  switch (event->type)
+    {
+    case CLUTTER_BUTTON_PRESS:
+    case CLUTTER_BUTTON_RELEASE:
+      meta_wayland_tablet_account_button (tablet, event);
+      break;
+    case CLUTTER_MOTION:
+      if (!tablet->buttons)
+        repick_for_event (tablet, event);
+      break;
+    case CLUTTER_PROXIMITY_IN:
+      {
+        ClutterInputDeviceTool *tool;
+
+        tool = clutter_event_get_device_tool (event);
+        tablet->current_tool = meta_wayland_tablet_ensure_tool (tablet, tool);
+        break;
+      }
+    case CLUTTER_PROXIMITY_OUT:
+      tablet->current_tool = NULL;
+      break;
+    default:
+      break;
+    }
 }
 
 static void
@@ -96,6 +337,15 @@ meta_wayland_tablet_handle_event (MetaWaylandTablet  *tablet,
 {
   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_set_focus (tablet, NULL);
+      break;
     case CLUTTER_MOTION:
       handle_motion_event (tablet, event);
       break;
@@ -144,7 +394,17 @@ meta_wayland_tablet_create_new_resource (MetaWaylandTablet  *tablet,
   wl_resource_set_implementation (resource, &tablet_interface,
                                   tablet, unbind_resource);
   wl_resource_set_user_data (resource, tablet);
-  wl_list_insert (&tablet->resource_list, wl_resource_get_link (resource));
+
+  if (tablet->focus_surface &&
+      wl_resource_get_client (tablet->focus_surface->resource) == client)
+    {
+      wl_list_insert (&tablet->focus_resource_list, wl_resource_get_link (resource));
+      emit_proximity_in (tablet, resource);
+    }
+  else
+    {
+      wl_list_insert (&tablet->resource_list, wl_resource_get_link (resource));
+    }
 
   return resource;
 }
diff --git a/src/wayland/meta-wayland-tablet.h b/src/wayland/meta-wayland-tablet.h
index 34bc399..6e6230f 100644
--- a/src/wayland/meta-wayland-tablet.h
+++ b/src/wayland/meta-wayland-tablet.h
@@ -28,17 +28,28 @@
 
 #include "meta-wayland-types.h"
 #include "meta-cursor-renderer.h"
+#include "meta-wayland-tablet-tool.h"
 
 struct _MetaWaylandTablet
 {
   MetaWaylandTabletManager *manager;
   ClutterInputDevice *device;
+  GHashTable *tools;
+
+  MetaWaylandTabletTool *current_tool;
 
   struct wl_list resource_list;
+  struct wl_list focus_resource_list;
+
+  MetaWaylandSurface *focus_surface;
+  struct wl_listener focus_surface_destroy_listener;
 
   MetaCursorRenderer *cursor_renderer;
 
   MetaWaylandSurface *current;
+  GSList *buttons;
+
+  guint32 proximity_serial;
 };
 
 MetaWaylandTablet * meta_wayland_tablet_new          (ClutterInputDevice       *device,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]