[clutter/fosdem-2012] test-way-surface: Add basic mouse support



commit 1311de82212c60f958c5139acdfcb9351bc4b13f
Author: Neil Roberts <neil linux intel com>
Date:   Mon Jan 9 14:23:04 2012 +0000

    test-way-surface: Add basic mouse support
    
    This adds a basic wl_input_device implementation which can convert
    Clutter mouse events to Wayland events. The implementation is
    contained in a separate file to make it easier to move into Mutter.

 tests/interactive/Makefile.am            |    2 +-
 tests/interactive/test-wayland-surface.c |   23 +++
 tests/interactive/tws-input.c            |  253 ++++++++++++++++++++++++++++++
 tests/interactive/tws-input.h            |   15 ++
 4 files changed, 292 insertions(+), 1 deletions(-)
---
diff --git a/tests/interactive/Makefile.am b/tests/interactive/Makefile.am
index c34408b..d2e1a53 100644
--- a/tests/interactive/Makefile.am
+++ b/tests/interactive/Makefile.am
@@ -69,7 +69,7 @@ test_interactive_SOURCES =
 if SUPPORT_WAYLAND_COMPOSITOR
 if HAVE_WAYLAND_EXTENSION_PROTOCOLS_DIR
 UNIT_TESTS += test-wayland-surface.c
-test_interactive_SOURCES += tws-compositor.h
+test_interactive_SOURCES += tws-compositor.h tws-input.c tws-input.h
 endif
 endif
 
diff --git a/tests/interactive/test-wayland-surface.c b/tests/interactive/test-wayland-surface.c
index b1a2dfe..acc8e48 100644
--- a/tests/interactive/test-wayland-surface.c
+++ b/tests/interactive/test-wayland-surface.c
@@ -19,6 +19,7 @@
 
 #include "xserver-server-protocol.h"
 #include "tws-compositor.h"
+#include "tws-input.h"
 
 typedef struct
 {
@@ -83,6 +84,8 @@ struct _TWSCompositor
   pid_t xwayland_pid;
   struct wl_client *xwayland_client;
   struct wl_resource *xserver_resource;
+
+  TwsInputDevice *input_device;
 };
 
 static int signal_pipe[2];
@@ -307,6 +310,7 @@ tws_surface_attach_buffer (struct wl_client *wayland_client,
       surface->actor = clutter_wayland_surface_new (&surface->wayland_surface);
       clutter_container_add_actor (CLUTTER_CONTAINER (compositor->stage),
                                    surface->actor);
+      clutter_actor_set_reactive (surface->actor, TRUE);
     }
 
   surface_actor = CLUTTER_WAYLAND_SURFACE (surface->actor);
@@ -1038,6 +1042,16 @@ signal_handler (GIOChannel *source,
   return TRUE;
 }
 
+static gboolean
+event_cb (ClutterActor *stage,
+          const ClutterEvent *event,
+          TWSCompositor *compositor)
+{
+  tws_input_device_handle_event (compositor->input_device, event);
+
+  return FALSE;
+}
+
 G_MODULE_EXPORT int
 test_wayland_surface_main (int argc, char **argv)
 {
@@ -1090,6 +1104,13 @@ test_wayland_surface_main (int argc, char **argv)
   g_signal_connect_after (compositor.stage, "paint",
                           G_CALLBACK (paint_finished_cb), &compositor);
 
+  compositor.input_device = tws_input_device_new (compositor.wayland_display);
+
+  g_signal_connect (compositor.stage,
+                    "event",
+                    G_CALLBACK (event_cb),
+                    &compositor);
+
   g_signal_connect (compositor.stage,
                     "destroy",
                     G_CALLBACK (clutter_main_quit),
@@ -1127,5 +1148,7 @@ test_wayland_surface_main (int argc, char **argv)
 
   stop_xwayland (&compositor);
 
+  /* FIXME: free the input device */
+
   return 0;
 }
diff --git a/tests/interactive/tws-input.c b/tests/interactive/tws-input.c
new file mode 100644
index 0000000..804d1d2
--- /dev/null
+++ b/tests/interactive/tws-input.c
@@ -0,0 +1,253 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <clutter/clutter.h>
+#include <clutter/wayland/clutter-wayland-compositor.h>
+#include <clutter/wayland/clutter-wayland-surface.h>
+#include <stdlib.h>
+#include "tws-input.h"
+#include "tws-compositor.h"
+
+struct _TwsInputDevice
+{
+  struct wl_input_device parent;
+
+  /* Last position of the pointer */
+  float pointer_x, pointer_y;
+
+  /* Position of the pointer within the surface */
+  int32_t pointer_sx, pointer_sy;
+};
+
+static void
+implicit_grab_motion (struct wl_grab *grab,
+                      uint32_t time,
+                      int32_t x,
+                      int32_t y)
+{
+  struct wl_resource *resource;
+
+  resource = grab->input_device->pointer_focus_resource;
+
+  if (resource)
+    {
+      TWSSurface *surface = (TWSSurface *) grab->input_device->pointer_focus;
+      float sx, sy;
+
+      clutter_actor_transform_stage_point (surface->actor,
+                                           x,
+                                           y,
+                                           &sx,
+                                           &sy);
+
+      wl_resource_post_event (resource, WL_INPUT_DEVICE_MOTION,
+                              time, x, y, (int32_t) sx, (int32_t) sy);
+    }
+}
+
+static void
+implicit_grab_button (struct wl_grab *grab,
+                      uint32_t time,
+                      int32_t button,
+                      int32_t state)
+{
+  struct wl_resource *resource;
+
+  resource = grab->input_device->pointer_focus_resource;
+
+  if (resource)
+    wl_resource_post_event (resource, WL_INPUT_DEVICE_BUTTON,
+                            time, button, state);
+}
+
+static void
+implicit_grab_end(struct wl_grab *grab, uint32_t time)
+{
+}
+
+static const struct wl_grab_interface implicit_grab_interface = {
+  implicit_grab_motion,
+  implicit_grab_button,
+  implicit_grab_end
+};
+
+static void
+input_device_attach (struct wl_client *client,
+                     struct wl_resource *resource,
+                     uint32_t time,
+                     struct wl_resource *buffer_resource,
+                     int32_t hotspot_x,
+                     int32_t hotspot_y)
+{
+}
+
+const static struct wl_input_device_interface
+input_device_interface =
+  {
+    input_device_attach
+  };
+
+static void
+unbind_input_device (struct wl_resource *resource)
+{
+  wl_list_remove (&resource->link);
+  free (resource);
+}
+
+static void
+bind_input_device (struct wl_client *client,
+                   void *data,
+                   uint32_t version,
+                   uint32_t id)
+{
+  struct wl_input_device *device = data;
+  struct wl_resource *resource;
+
+  resource = wl_client_add_object (client,
+                                   &wl_input_device_interface,
+                                   &input_device_interface,
+                                   id,
+                                   data);
+
+  wl_list_insert (&device->resource_list, &resource->link);
+
+  resource->destroy = unbind_input_device;
+}
+
+TwsInputDevice *
+tws_input_device_new (struct wl_display *display)
+{
+  TwsInputDevice *device = g_new (TwsInputDevice, 1);
+
+  wl_input_device_init (&device->parent);
+
+  device->parent.implicit_grab.interface = &implicit_grab_interface;
+
+  wl_display_add_global (display,
+                         &wl_input_device_interface,
+                         device,
+                         bind_input_device);
+
+  return device;
+}
+
+static void
+set_pointer_focus_for_event (TwsInputDevice *input_device,
+                             const ClutterEvent *event)
+{
+  struct wl_input_device *device =
+    (struct wl_input_device *) input_device;
+  struct wl_surface *surface;
+
+  clutter_event_get_coords (event,
+                            &input_device->pointer_x,
+                            &input_device->pointer_y);
+
+  if (CLUTTER_WAYLAND_IS_SURFACE (event->any.source))
+    {
+      ClutterWaylandSurface *surface_actor =
+        CLUTTER_WAYLAND_SURFACE (event->any.source);
+      float fsx, fsy;
+
+      surface = clutter_wayland_surface_get_surface (surface_actor);
+
+      clutter_actor_transform_stage_point (event->any.source,
+                                           input_device->pointer_x,
+                                           input_device->pointer_y,
+                                           &fsx, &fsy);
+      input_device->pointer_sx = fsx;
+      input_device->pointer_sy = fsy;
+    }
+  else
+    {
+      surface = NULL;
+      input_device->pointer_sx = input_device->pointer_x;
+      input_device->pointer_sy = input_device->pointer_y;
+    }
+
+  wl_input_device_set_pointer_focus (device,
+                                     surface,
+                                     event->any.time,
+                                     input_device->pointer_x,
+                                     input_device->pointer_y,
+                                     input_device->pointer_sx,
+                                     input_device->pointer_sy);
+}
+
+static void
+handle_motion_event (TwsInputDevice *input_device,
+                     const ClutterMotionEvent *event)
+{
+  struct wl_input_device *device =
+    (struct wl_input_device *) input_device;
+
+  if (device->grab)
+    device->grab->interface->motion (device->grab,
+                                     event->time,
+                                     event->x,
+                                     event->y);
+  else
+    {
+      set_pointer_focus_for_event (input_device, (const ClutterEvent *) event);
+
+      if (device->pointer_focus_resource)
+        wl_resource_post_event (device->pointer_focus_resource,
+                                WL_INPUT_DEVICE_MOTION,
+                                time,
+                                (int32_t) input_device->pointer_x,
+                                (int32_t) input_device->pointer_y,
+                                input_device->pointer_sx,
+                                input_device->pointer_sy);
+    }
+}
+
+static void
+handle_button_press_event (TwsInputDevice *input_device,
+                           const ClutterButtonEvent *event)
+{
+  struct wl_input_device *device =
+    (struct wl_input_device *) input_device;
+  struct wl_surface *surface = device->pointer_focus;
+  gboolean state = event->type == CLUTTER_BUTTON_PRESS;
+
+  if (state && surface && device->grab == NULL)
+    wl_input_device_start_grab (device,
+                                &device->implicit_grab,
+                                event->button,
+                                event->time);
+
+  if (device->grab)
+    device->grab->interface->button (device->grab,
+                                     event->time,
+                                     event->button,
+                                     state);
+
+  if (!state && device->grab && device->grab_button == event->button)
+    {
+      wl_input_device_end_grab (device, event->time);
+
+      set_pointer_focus_for_event (input_device, (const ClutterEvent *) event);
+    }
+}
+
+void
+tws_input_device_handle_event (TwsInputDevice *input_device,
+                               const ClutterEvent *event)
+{
+  switch (event->type)
+    {
+    case CLUTTER_MOTION:
+      handle_motion_event (input_device,
+                           (const ClutterMotionEvent *) event);
+      break;
+
+    case CLUTTER_BUTTON_PRESS:
+      handle_button_press_event (input_device,
+                                 (const ClutterButtonEvent *) event);
+      break;
+
+    default:
+      break;
+    }
+}
diff --git a/tests/interactive/tws-input.h b/tests/interactive/tws-input.h
new file mode 100644
index 0000000..efe05a9
--- /dev/null
+++ b/tests/interactive/tws-input.h
@@ -0,0 +1,15 @@
+#ifndef __TWS_INPUT_H__
+#define __TWS_INPUT_H__
+
+#include <wayland-server.h>
+
+typedef struct _TwsInputDevice TwsInputDevice;
+
+TwsInputDevice *
+tws_input_device_new (struct wl_display *display);
+
+void
+tws_input_device_handle_event (TwsInputDevice *input_device,
+                               const ClutterEvent *event);
+
+#endif /* __TWS_INPUT_H__ */



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