[mutter/wip/wayland-kms: 3/15] wayland: Add basic mouse input support
- From: Neil Roberts <nroberts src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter/wip/wayland-kms: 3/15] wayland: Add basic mouse input support
- Date: Wed, 18 Jul 2012 16:05:14 +0000 (UTC)
commit 23aebbb1977ccc4ec5739bce765c21243b827a93
Author: Neil Roberts <neil linux intel com>
Date: Wed Jan 11 18:33:13 2012 +0000
wayland: Add basic mouse input support
This copies the basic mouse support from the test-wayland-surface demo
in the Clutter source. It adds a basic wl_input_device implementation
which can convert Clutter mouse events to Wayland events. For this to
work all of the wayland surface actors need to be made reactive.
src/Makefile.am | 4 +-
src/core/display-private.h | 3 +
src/core/display.c | 36 ++++-
src/wayland/meta-wayland-input-device.c | 242 +++++++++++++++++++++++++++++++
src/wayland/meta-wayland-input-device.h | 37 +++++
src/wayland/meta-wayland-private.h | 13 ++
src/wayland/meta-wayland.c | 122 ++++++++++++++++
7 files changed, 448 insertions(+), 9 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 11b08e3..9982c08 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -168,7 +168,9 @@ libmutter_la_SOURCES = \
if HAVE_WAYLAND
libmutter_la_SOURCES += \
wayland/meta-wayland.c \
- wayland/meta-wayland-private.h
+ wayland/meta-wayland-private.h \
+ wayland/meta-wayland-input-device.h \
+ wayland/meta-wayland-input-device.c
endif
libmutter_la_LDFLAGS = -no-undefined
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 6db1b64..bbe561b 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -444,4 +444,7 @@ void meta_display_overlay_key_activate (MetaDisplay *display);
/* In above-tab-keycode.c */
guint meta_display_get_above_tab_keycode (MetaDisplay *display);
+gboolean meta_display_handle_event (MetaDisplay *display,
+ XEvent *event);
+
#endif
diff --git a/src/core/display.c b/src/core/display.c
index d84bde9..0d18ed1 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -1623,9 +1623,8 @@ handle_net_restack_window (MetaDisplay* display,
/**
* event_callback:
+ * @display: The MetaDisplay that events are coming from
* @event: The event that just happened
- * @data: The #MetaDisplay that events are coming from, cast to a gpointer
- * so that it can be sent to a callback
*
* This is the most important function in the whole program. It is the heart,
* it is the nexus, it is the Grand Central Station of Mutter's world.
@@ -1635,20 +1634,17 @@ handle_net_restack_window (MetaDisplay* display,
* busy around here. Most of this function is a ginormous switch statement
* dealing with all the kinds of events that might turn up.
*/
-static gboolean
-event_callback (XEvent *event,
- gpointer data)
+gboolean
+meta_display_handle_event (MetaDisplay *display,
+ XEvent *event)
{
MetaWindow *window;
MetaWindow *property_for_window;
- MetaDisplay *display;
Window modified;
gboolean frame_was_receiver;
gboolean bypass_compositor;
gboolean filter_out_event;
- display = data;
-
#ifdef WITH_VERBOSE_MODE
if (dump_events)
meta_spew_event (display, event);
@@ -2733,6 +2729,30 @@ event_callback (XEvent *event,
return filter_out_event;
}
+static gboolean
+event_callback (XEvent *event,
+ gpointer data)
+{
+ MetaDisplay *display = data;
+
+ /* Under Wayland we want to filter out mouse motion events so we can
+ synthesize them from the Clutter events instead. This is
+ necessary because the position in the mouse events is passed to
+ the X server relative to the position of the surface. The X
+ server then translates these back to screen coordinates based on
+ the window position. If we rely on this translatation when
+ dragging a window around then the window will jump around
+ erratically because of the lag between updating the window
+ position from the surface position. Instead we bypass the
+ translation altogether by directly using the Clutter events */
+#ifdef HAVE_WAYLAND
+ if (event->type == MotionNotify)
+ return FALSE;
+#endif
+
+ return meta_display_handle_event (display, event);
+}
+
/* Return the window this has to do with, if any, rather
* than the frame or root window that was selecting
* for substructure
diff --git a/src/wayland/meta-wayland-input-device.c b/src/wayland/meta-wayland-input-device.c
new file mode 100644
index 0000000..89dcd55
--- /dev/null
+++ b/src/wayland/meta-wayland-input-device.c
@@ -0,0 +1,242 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <clutter/clutter.h>
+#include <clutter/wayland/clutter-wayland-compositor.h>
+#include <clutter/wayland/clutter-wayland-surface.h>
+#include <stdlib.h>
+#include <linux/input.h>
+#include "meta-wayland-input-device.h"
+#include "meta-wayland-private.h"
+
+struct _MetaWaylandInputDevice
+{
+ struct wl_input_device parent;
+
+ ClutterActor *stage;
+};
+
+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;
+}
+
+MetaWaylandInputDevice *
+meta_wayland_input_device_new (struct wl_display *display,
+ ClutterActor *stage)
+{
+ MetaWaylandInputDevice *device = g_new (MetaWaylandInputDevice, 1);
+
+ wl_input_device_init (&device->parent);
+ device->stage = stage;
+
+ wl_display_add_global (display,
+ &wl_input_device_interface,
+ device,
+ bind_input_device);
+
+ return device;
+}
+
+static void
+handle_motion_event (MetaWaylandInputDevice *input_device,
+ const ClutterMotionEvent *event)
+{
+ struct wl_input_device *device =
+ (struct wl_input_device *) input_device;
+
+ device->x = event->x;
+ device->y = event->y;
+
+ meta_wayland_input_device_repick (input_device,
+ event->time,
+ event->source);
+
+ device->grab->interface->motion (device->grab,
+ event->time,
+ device->grab->x,
+ device->grab->y);
+}
+
+static void
+handle_button_event (MetaWaylandInputDevice *input_device,
+ const ClutterButtonEvent *event)
+{
+ struct wl_input_device *device =
+ (struct wl_input_device *) input_device;
+ gboolean state = event->type == CLUTTER_BUTTON_PRESS;
+ uint32_t button;
+
+ switch (event->button)
+ {
+ /* The evdev input right and middle button numbers are swapped
+ relative to how Clutter numbers them */
+ case 2:
+ button = BTN_MIDDLE;
+ break;
+
+ case 3:
+ button = BTN_RIGHT;
+ break;
+
+ default:
+ button = event->button + BTN_LEFT - 1;
+ break;
+ }
+
+ if (state)
+ {
+ if (device->button_count == 0)
+ {
+ device->grab_button = button;
+ device->grab_time = event->time;
+ device->grab_x = device->x;
+ device->grab_y = device->y;
+ }
+
+ device->button_count++;
+ }
+ else
+ device->button_count--;
+
+ device->grab->interface->button (device->grab, event->time, button, state);
+}
+
+void
+meta_wayland_input_device_handle_event (MetaWaylandInputDevice *input_device,
+ const ClutterEvent *event)
+{
+ switch (event->type)
+ {
+ case CLUTTER_MOTION:
+ handle_motion_event (input_device,
+ (const ClutterMotionEvent *) event);
+ break;
+
+ case CLUTTER_BUTTON_PRESS:
+ case CLUTTER_BUTTON_RELEASE:
+ handle_button_event (input_device,
+ (const ClutterButtonEvent *) event);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* The actor argument can be NULL in which case a Clutter pick will be
+ performed to determine the right actor. An actor should only be
+ passed if the repick is being performed due to an event in which
+ case Clutter will have already performed a pick so we can avoid
+ redundantly doing another one */
+void
+meta_wayland_input_device_repick (MetaWaylandInputDevice *device,
+ uint32_t time,
+ ClutterActor *actor)
+{
+ struct wl_input_device *input_device = (struct wl_input_device *) device;
+ struct wl_surface *surface;
+ MetaWaylandSurface *focus;
+
+ if (actor == NULL)
+ {
+ ClutterStage *stage = CLUTTER_STAGE (device->stage);
+ actor = clutter_stage_get_actor_at_pos (stage,
+ CLUTTER_PICK_REACTIVE,
+ input_device->x, input_device->y);
+ }
+
+ if (CLUTTER_WAYLAND_IS_SURFACE (actor))
+ {
+ ClutterWaylandSurface *wl_surface = CLUTTER_WAYLAND_SURFACE (actor);
+ float ax, ay;
+
+ clutter_actor_transform_stage_point (actor,
+ input_device->x, input_device->y,
+ &ax, &ay);
+ input_device->current_x = ax;
+ input_device->current_y = ay;
+
+ surface = clutter_wayland_surface_get_surface (wl_surface);
+ }
+ else
+ surface = NULL;
+
+ if (surface != input_device->current)
+ {
+ const struct wl_grab_interface *interface = input_device->grab->interface;
+ interface->focus (input_device->grab, time, surface,
+ input_device->current_x, input_device->current_y);
+ input_device->current = surface;
+ }
+
+ focus = (MetaWaylandSurface *) input_device->grab->focus;
+ if (focus)
+ {
+ float ax, ay;
+
+ clutter_actor_transform_stage_point (focus->actor,
+ input_device->x, input_device->y,
+ &ax, &ay);
+ input_device->grab->x = ax;
+ input_device->grab->y = ay;
+ }
+}
diff --git a/src/wayland/meta-wayland-input-device.h b/src/wayland/meta-wayland-input-device.h
new file mode 100644
index 0000000..91315cc
--- /dev/null
+++ b/src/wayland/meta-wayland-input-device.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef META_WAYLAND_INPUT_H
+#define META_WAYLAND_INPUT_H
+
+#include <wayland-server.h>
+
+typedef struct _MetaWaylandInputDevice MetaWaylandInputDevice;
+
+MetaWaylandInputDevice *meta_wayland_input_device_new (struct wl_display *display,
+ ClutterActor *stage);
+
+void meta_wayland_input_device_handle_event (MetaWaylandInputDevice *input_device,
+ const ClutterEvent *event);
+
+void meta_wayland_input_device_repick (MetaWaylandInputDevice *input_device,
+ uint32_t time,
+ ClutterActor *actor);
+
+#endif /* META_WAYLAND_INPUT_H */
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index d0c5412..0e4e2ec 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -27,6 +27,7 @@
#include <glib.h>
#include "window-private.h"
+#include "meta-wayland-input-device.h"
typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
@@ -120,6 +121,16 @@ struct _MetaWaylandCompositor
struct wl_client *xwayland_client;
struct wl_resource *xserver_resource;
GHashTable *window_surfaces;
+
+ MetaWaylandInputDevice *input_device;
+
+ /* This surface is only used to keep drag of the implicit grab when
+ synthesizing XEvents for Mutter */
+ struct wl_surface *implicit_grab_surface;
+ /* Button that was pressed to initiate an implicit grab. The
+ implicit grab will only be released when this button is
+ released */
+ guint32 implicit_grab_button;
};
void meta_wayland_init (void);
@@ -133,4 +144,6 @@ void meta_wayland_handle_sig_child (void);
MetaWaylandSurface *meta_wayland_lookup_surface_for_xid (guint32 xid);
+void meta_wayland_compositor_repick (MetaWaylandCompositor *compositor);
+
#endif /* META_WAYLAND_PRIVATE_H */
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 6b47ea0..38173d0 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -285,6 +285,7 @@ meta_wayland_surface_attach_buffer (struct wl_client *wayland_client,
if (surface->actor)
{
surface_actor = CLUTTER_WAYLAND_SURFACE (surface->actor);
+ clutter_actor_set_reactive (surface->actor, TRUE);
if (!clutter_wayland_surface_attach_buffer (surface_actor, wayland_buffer,
NULL))
g_warning ("Failed to attach buffer to ClutterWaylandSurface");
@@ -350,6 +351,16 @@ const struct wl_surface_interface meta_wayland_surface_interface = {
meta_wayland_surface_frame
};
+/* This should be called whenever the window stacking changes to
+ update the current position on all of the input devices */
+void
+meta_wayland_compositor_repick (MetaWaylandCompositor *compositor)
+{
+ meta_wayland_input_device_repick (compositor->input_device,
+ get_time (),
+ NULL);
+}
+
static void
surface_actor_destroyed_cb (void *user_data,
GObject *old_object)
@@ -383,6 +394,12 @@ meta_wayland_surface_free (MetaWaylandSurface *surface)
}
g_slice_free (MetaWaylandSurface, surface);
+
+ meta_wayland_compositor_repick (compositor);
+
+ if (compositor->implicit_grab_surface == (struct wl_surface *) surface)
+ compositor->implicit_grab_surface =
+ ((struct wl_input_device *) compositor->input_device)->current;
}
static void
@@ -1124,6 +1141,105 @@ stage_destroy_cb (void)
meta_quit (META_EXIT_SUCCESS);
}
+static gboolean
+event_cb (ClutterActor *stage,
+ const ClutterEvent *event,
+ MetaWaylandCompositor *compositor)
+{
+ struct wl_input_device *device =
+ (struct wl_input_device *) compositor->input_device;
+ MetaWaylandSurface *surface;
+ MetaDisplay *display;
+ XMotionEvent xevent;
+
+ meta_wayland_input_device_handle_event (compositor->input_device, event);
+
+ display = meta_get_display ();
+ if (!display)
+ return FALSE;
+
+ /* We want to synthesize X events for mouse motion events so that we
+ don't have to rely on the X server's window position being
+ synched with the surface positoin. See the comment in
+ event_callback() in display.c */
+
+ switch (event->type)
+ {
+ case CLUTTER_BUTTON_PRESS:
+ if (compositor->implicit_grab_surface == NULL)
+ {
+ compositor->implicit_grab_button = event->button.button;
+ compositor->implicit_grab_surface = device->current;
+ }
+ return FALSE;
+
+ case CLUTTER_BUTTON_RELEASE:
+ if (event->type == CLUTTER_BUTTON_RELEASE &&
+ compositor->implicit_grab_surface &&
+ event->button.button == compositor->implicit_grab_button)
+ compositor->implicit_grab_surface = NULL;
+ return FALSE;
+
+ case CLUTTER_MOTION:
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ xevent.type = MotionNotify;
+ xevent.is_hint = NotifyNormal;
+ xevent.same_screen = TRUE;
+ xevent.serial = 0;
+ xevent.send_event = False;
+ xevent.display = display->xdisplay;
+ xevent.root = DefaultRootWindow (display->xdisplay);
+
+ if (compositor->implicit_grab_surface)
+ surface = (MetaWaylandSurface *) compositor->implicit_grab_surface;
+ else
+ surface = (MetaWaylandSurface *) device->current;
+
+ if (surface == (MetaWaylandSurface *) device->current)
+ {
+ xevent.x = device->current_x;
+ xevent.y = device->current_y;
+ }
+ else if (surface)
+ {
+ float ax, ay;
+
+ clutter_actor_transform_stage_point (surface->actor,
+ device->x, device->y,
+ &ax, &ay);
+ xevent.x = ax;
+ xevent.y = ay;
+ }
+ else
+ {
+ xevent.x = device->x;
+ xevent.y = device->y;
+ }
+
+ if (surface && surface->xid != None)
+ xevent.window = surface->xid;
+ else
+ xevent.window = xevent.root;
+
+ /* Mutter doesn't really know about the sub-windows. This assumes it
+ doesn't care either */
+ xevent.subwindow = xevent.window;
+ xevent.time = event->any.time;
+ xevent.x_root = device->x;
+ xevent.y_root = device->y;
+ /* The Clutter state flags exactly match the X values */
+ xevent.state = clutter_event_get_state (event);
+
+ meta_display_handle_event (display, (XEvent *) &xevent);
+
+ return FALSE;
+}
+
void
meta_wayland_init (void)
{
@@ -1177,6 +1293,12 @@ meta_wayland_init (void)
G_CALLBACK (paint_finished_cb), compositor);
g_signal_connect (compositor->stage, "destroy",
G_CALLBACK (stage_destroy_cb), NULL);
+ g_signal_connect (compositor->stage, "event",
+ G_CALLBACK (event_cb), compositor);
+
+ compositor->input_device =
+ meta_wayland_input_device_new (compositor->wayland_display,
+ compositor->stage);
meta_wayland_compositor_create_output (compositor, 0, 0, 1024, 600, 222, 125);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]