summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am10
-rw-r--r--src/compositor/meta-window-actor.c3
-rw-r--r--src/core/display-private.h3
-rw-r--r--src/core/display.c49
-rw-r--r--src/wayland/meta-wayland-data-device.c548
-rw-r--r--src/wayland/meta-wayland-data-device.h42
-rw-r--r--src/wayland/meta-wayland-keyboard.c512
-rw-r--r--src/wayland/meta-wayland-keyboard.h75
-rw-r--r--src/wayland/meta-wayland-pointer.c260
-rw-r--r--src/wayland/meta-wayland-pointer.h49
-rw-r--r--src/wayland/meta-wayland-private.h203
-rw-r--r--src/wayland/meta-wayland-seat.c503
-rw-r--r--src/wayland/meta-wayland-seat.h47
-rw-r--r--src/wayland/meta-wayland.c280
14 files changed, 2568 insertions, 16 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index e25d4a8ee..a323a207e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -179,7 +179,15 @@ libmutter_la_SOURCES += \
wayland/meta-wayland.c \
wayland/meta-wayland-private.h \
wayland/meta-xwayland-private.h \
- wayland/meta-xwayland.c
+ wayland/meta-xwayland.c \
+ wayland/meta-wayland-data-device.c \
+ wayland/meta-wayland-data-device.h \
+ wayland/meta-wayland-keyboard.c \
+ wayland/meta-wayland-keyboard.h \
+ wayland/meta-wayland-pointer.c \
+ wayland/meta-wayland-pointer.h \
+ wayland/meta-wayland-seat.c \
+ wayland/meta-wayland-seat.h
endif
libmutter_la_LDFLAGS = -no-undefined
diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c
index 54f6838aa..c905fbd77 100644
--- a/src/compositor/meta-window-actor.c
+++ b/src/compositor/meta-window-actor.c
@@ -380,6 +380,9 @@ meta_window_actor_constructed (GObject *object)
clutter_actor_add_child (CLUTTER_ACTOR (self), priv->actor);
+ if (meta_is_wayland_compositor ())
+ clutter_actor_set_reactive (priv->actor, TRUE);
+
/*
* Since we are holding a pointer to this actor independently of the
* ClutterContainer internals, and provide a public API to access it,
diff --git a/src/core/display-private.h b/src/core/display-private.h
index 86284fe10..2ca9c6759 100644
--- a/src/core/display-private.h
+++ b/src/core/display-private.h
@@ -467,6 +467,9 @@ gboolean meta_display_modifiers_accelerator_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);
+
#ifdef HAVE_XI23
gboolean meta_display_process_barrier_event (MetaDisplay *display,
XIBarrierEvent *event);
diff --git a/src/core/display.c b/src/core/display.c
index 5e19f1439..53693685d 100644
--- a/src/core/display.c
+++ b/src/core/display.c
@@ -2137,10 +2137,9 @@ handle_window_focus_event (MetaDisplay *display,
}
/**
- * event_callback:
+ * meta_display_handle_event:
+ * @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.
@@ -2150,21 +2149,18 @@ handle_window_focus_event (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;
XIEvent *input_event;
- display = data;
-
#ifdef WITH_VERBOSE_MODE
if (dump_events)
meta_spew_event (display, event);
@@ -2655,6 +2651,15 @@ event_callback (XEvent *event,
}
break;
case XI_FocusIn:
+#ifdef HAVE_WAYLAND
+ if (meta_is_wayland_compositor ())
+ {
+ MetaWaylandCompositor *compositor =
+ meta_wayland_compositor_get_default ();
+ meta_wayland_compositor_set_input_focus (compositor, window);
+ }
+#endif
+ /* fall through */
case XI_FocusOut:
/* libXi does not properly copy the serial to the XIEnterEvent, so pull it
* from the parent XAnyEvent.
@@ -3202,6 +3207,32 @@ 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 (meta_is_wayland_compositor () &&
+ event->type == GenericEvent &&
+ event->xcookie.evtype == XI_Motion)
+ 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-data-device.c b/src/wayland/meta-wayland-data-device.c
new file mode 100644
index 000000000..d976352df
--- /dev/null
+++ b/src/wayland/meta-wayland-data-device.c
@@ -0,0 +1,548 @@
+/*
+ * Copyright © 2011 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/* The file is based on src/data-device.c from Weston */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include "meta-wayland-data-device.h"
+#include "meta-wayland-seat.h"
+#include "meta-wayland-pointer.h"
+
+static void
+data_offer_accept (struct wl_client *client,
+ struct wl_resource *resource,
+ guint32 serial,
+ const char *mime_type)
+{
+ MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
+
+ /* FIXME: Check that client is currently focused by the input
+ * device that is currently dragging this data source. Should
+ * this be a wl_data_device request? */
+
+ if (offer->source)
+ offer->source->accept (offer->source, serial, mime_type);
+}
+
+static void
+data_offer_receive (struct wl_client *client, struct wl_resource *resource,
+ const char *mime_type, int32_t fd)
+{
+ MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
+
+ if (offer->source)
+ offer->source->send (offer->source, mime_type, fd);
+ else
+ close (fd);
+}
+
+static void
+data_offer_destroy (struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static const struct wl_data_offer_interface data_offer_interface = {
+ data_offer_accept,
+ data_offer_receive,
+ data_offer_destroy,
+};
+
+static void
+destroy_data_offer (struct wl_resource *resource)
+{
+ MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
+
+ if (offer->source)
+ wl_list_remove (&offer->source_destroy_listener.link);
+ free (offer);
+}
+
+static void
+destroy_offer_data_source (struct wl_listener *listener, void *data)
+{
+ MetaWaylandDataOffer *offer;
+
+ offer = wl_container_of (listener, offer, source_destroy_listener);
+
+ offer->source = NULL;
+}
+
+static struct wl_resource *
+meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
+ struct wl_resource *target)
+{
+ MetaWaylandDataOffer *offer;
+ char **p;
+
+ offer = malloc (sizeof *offer);
+ if (offer == NULL)
+ return NULL;
+
+ offer->source = source;
+ offer->source_destroy_listener.notify = destroy_offer_data_source;
+
+ offer->resource = wl_client_add_object (wl_resource_get_client (target),
+ &wl_data_offer_interface,
+ &data_offer_interface,
+ 0,
+ offer);
+ wl_resource_set_destructor (offer->resource, destroy_data_offer);
+ wl_resource_add_destroy_listener (source->resource,
+ &offer->source_destroy_listener);
+
+ wl_data_device_send_data_offer (target, offer->resource);
+
+ wl_array_for_each (p, &source->mime_types)
+ wl_data_offer_send_offer (offer->resource, *p);
+
+ return offer->resource;
+}
+
+static void
+data_source_offer (struct wl_client *client,
+ struct wl_resource *resource, const char *type)
+{
+ MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
+ char **p;
+
+ p = wl_array_add (&source->mime_types, sizeof *p);
+ if (p)
+ *p = strdup (type);
+ if (!p || !*p)
+ wl_resource_post_no_memory (resource);
+}
+
+static void
+data_source_destroy (struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy (resource);
+}
+
+static struct wl_data_source_interface data_source_interface = {
+ data_source_offer,
+ data_source_destroy
+};
+
+static void
+destroy_drag_focus (struct wl_listener *listener, void *data)
+{
+ MetaWaylandSeat *seat = wl_container_of (listener, seat, drag_focus_listener);
+
+ seat->drag_focus_resource = NULL;
+}
+
+static void
+drag_grab_focus (MetaWaylandPointerGrab *grab,
+ MetaWaylandSurface *surface,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
+ struct wl_resource *resource, *offer = NULL;
+ struct wl_display *display;
+ guint32 serial;
+
+ if (seat->drag_focus_resource)
+ {
+ wl_data_device_send_leave (seat->drag_focus_resource);
+ wl_list_remove (&seat->drag_focus_listener.link);
+ seat->drag_focus_resource = NULL;
+ seat->drag_focus = NULL;
+ }
+
+ if (!surface)
+ return;
+
+ if (!seat->drag_data_source &&
+ wl_resource_get_client (surface->resource) != seat->drag_client)
+ return;
+
+ resource =
+ wl_resource_find_for_client (&seat->drag_resource_list,
+ wl_resource_get_client (surface->resource));
+ if (!resource)
+ return;
+
+ display = wl_client_get_display (wl_resource_get_client (resource));
+ serial = wl_display_next_serial (display);
+
+ if (seat->drag_data_source)
+ offer = meta_wayland_data_source_send_offer (seat->drag_data_source,
+ resource);
+
+ wl_data_device_send_enter (resource, serial, surface->resource,
+ x, y, offer);
+
+ seat->drag_focus = surface;
+ seat->drag_focus_listener.notify = destroy_drag_focus;
+ wl_resource_add_destroy_listener (resource, &seat->drag_focus_listener);
+ seat->drag_focus_resource = resource;
+ grab->focus = surface;
+}
+
+static void
+drag_grab_motion (MetaWaylandPointerGrab *grab,
+ guint32 time, wl_fixed_t x, wl_fixed_t y)
+{
+ MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
+
+ if (seat->drag_focus_resource)
+ wl_data_device_send_motion (seat->drag_focus_resource, time, x, y);
+}
+
+static void
+data_device_end_drag_grab (MetaWaylandSeat *seat)
+{
+ if (seat->drag_surface)
+ {
+ seat->drag_surface = NULL;
+ wl_signal_emit (&seat->drag_icon_signal, NULL);
+ wl_list_remove (&seat->drag_icon_listener.link);
+ }
+
+ drag_grab_focus (&seat->drag_grab, NULL,
+ wl_fixed_from_int (0), wl_fixed_from_int (0));
+
+ meta_wayland_pointer_end_grab (&seat->pointer);
+
+ seat->drag_data_source = NULL;
+ seat->drag_client = NULL;
+}
+
+static void
+drag_grab_button (MetaWaylandPointerGrab *grab,
+ guint32 time, guint32 button, guint32 state_w)
+{
+ MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
+ enum wl_pointer_button_state state = state_w;
+
+ if (seat->drag_focus_resource &&
+ seat->pointer.grab_button == button &&
+ state == WL_POINTER_BUTTON_STATE_RELEASED)
+ wl_data_device_send_drop (seat->drag_focus_resource);
+
+ if (seat->pointer.button_count == 0 &&
+ state == WL_POINTER_BUTTON_STATE_RELEASED)
+ {
+ if (seat->drag_data_source)
+ wl_list_remove (&seat->drag_data_source_listener.link);
+ data_device_end_drag_grab (seat);
+ }
+}
+
+static const MetaWaylandPointerGrabInterface drag_grab_interface = {
+ drag_grab_focus,
+ drag_grab_motion,
+ drag_grab_button,
+};
+
+static void
+destroy_data_device_source (struct wl_listener *listener, void *data)
+{
+ MetaWaylandSeat *seat =
+ wl_container_of (listener, seat, drag_data_source_listener);
+
+ data_device_end_drag_grab (seat);
+}
+
+static void
+destroy_data_device_icon (struct wl_listener *listener, void *data)
+{
+ MetaWaylandSeat *seat =
+ wl_container_of (listener, seat, drag_icon_listener);
+
+ seat->drag_surface = NULL;
+}
+
+static void
+data_device_start_drag (struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *source_resource,
+ struct wl_resource *origin_resource,
+ struct wl_resource *icon_resource, guint32 serial)
+{
+ MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
+
+ /* FIXME: Check that client has implicit grab on the origin
+ * surface that matches the given time. */
+
+ /* FIXME: Check that the data source type array isn't empty. */
+
+ seat->drag_grab.interface = &drag_grab_interface;
+
+ seat->drag_client = client;
+ seat->drag_data_source = NULL;
+
+ if (source_resource)
+ {
+ seat->drag_data_source = wl_resource_get_user_data (source_resource);
+ seat->drag_data_source_listener.notify = destroy_data_device_source;
+ wl_resource_add_destroy_listener (source_resource,
+ &seat->drag_data_source_listener);
+ }
+
+ if (icon_resource)
+ {
+ seat->drag_surface = wl_resource_get_user_data (icon_resource);
+ seat->drag_icon_listener.notify = destroy_data_device_icon;
+ wl_resource_add_destroy_listener (icon_resource,
+ &seat->drag_icon_listener);
+ wl_signal_emit (&seat->drag_icon_signal, icon_resource);
+ }
+
+ meta_wayland_pointer_set_focus (&seat->pointer, NULL,
+ wl_fixed_from_int (0),
+ wl_fixed_from_int (0));
+ meta_wayland_pointer_start_grab (&seat->pointer, &seat->drag_grab);
+}
+
+static void
+destroy_selection_data_source (struct wl_listener *listener, void *data)
+{
+ MetaWaylandSeat *seat =
+ wl_container_of (listener, seat, selection_data_source_listener);
+ struct wl_resource *data_device;
+ struct wl_resource *focus = NULL;
+
+ seat->selection_data_source = NULL;
+
+ focus = seat->keyboard.focus_resource;
+
+ if (focus)
+ {
+ data_device =
+ wl_resource_find_for_client (&seat->drag_resource_list,
+ wl_resource_get_client (focus));
+ if (data_device)
+ wl_data_device_send_selection (data_device, NULL);
+ }
+
+ wl_signal_emit (&seat->selection_signal, seat);
+}
+
+void
+meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
+ MetaWaylandDataSource *source,
+ guint32 serial)
+{
+ struct wl_resource *data_device, *offer;
+ struct wl_resource *focus = NULL;
+
+ if (seat->selection_data_source &&
+ seat->selection_serial - serial < UINT32_MAX / 2)
+ return;
+
+ if (seat->selection_data_source)
+ {
+ seat->selection_data_source->cancel (seat->selection_data_source);
+ wl_list_remove (&seat->selection_data_source_listener.link);
+ seat->selection_data_source = NULL;
+ }
+
+ seat->selection_data_source = source;
+ seat->selection_serial = serial;
+
+ focus = seat->keyboard.focus_resource;
+
+ if (focus)
+ {
+ data_device =
+ wl_resource_find_for_client (&seat->drag_resource_list,
+ wl_resource_get_client (focus));
+ if (data_device && source)
+ {
+ offer =
+ meta_wayland_data_source_send_offer (seat->selection_data_source,
+ data_device);
+ wl_data_device_send_selection (data_device, offer);
+ }
+ else if (data_device)
+ {
+ wl_data_device_send_selection (data_device, NULL);
+ }
+ }
+
+ wl_signal_emit (&seat->selection_signal, seat);
+
+ if (source)
+ {
+ seat->selection_data_source_listener.notify =
+ destroy_selection_data_source;
+ wl_resource_add_destroy_listener (source->resource,
+ &seat->selection_data_source_listener);
+ }
+}
+
+static void
+data_device_set_selection (struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *source_resource,
+ guint32 serial)
+{
+ if (!source_resource)
+ return;
+
+ /* FIXME: Store serial and check against incoming serial here. */
+ meta_wayland_seat_set_selection (wl_resource_get_user_data (resource),
+ wl_resource_get_user_data (source_resource),
+ serial);
+}
+
+static const struct wl_data_device_interface data_device_interface = {
+ data_device_start_drag,
+ data_device_set_selection,
+};
+
+static void
+destroy_data_source (struct wl_resource *resource)
+{
+ MetaWaylandDataSource *source = wl_container_of (resource, source, resource);
+ char **p;
+
+ wl_array_for_each (p, &source->mime_types) free (*p);
+
+ wl_array_release (&source->mime_types);
+}
+
+static void
+client_source_accept (MetaWaylandDataSource *source,
+ guint32 time, const char *mime_type)
+{
+ wl_data_source_send_target (source->resource, mime_type);
+}
+
+static void
+client_source_send (MetaWaylandDataSource *source,
+ const char *mime_type, int32_t fd)
+{
+ wl_data_source_send_send (source->resource, mime_type, fd);
+ close (fd);
+}
+
+static void
+client_source_cancel (MetaWaylandDataSource *source)
+{
+ wl_data_source_send_cancelled (source->resource);
+}
+
+static void
+create_data_source (struct wl_client *client,
+ struct wl_resource *resource, guint32 id)
+{
+ MetaWaylandDataSource *source;
+
+ source = malloc (sizeof *source);
+ if (source == NULL)
+ {
+ wl_resource_post_no_memory (resource);
+ return;
+ }
+
+ source->resource = wl_client_add_object (client,
+ &wl_data_source_interface,
+ &data_source_interface,
+ id,
+ source);
+ wl_resource_set_destructor (source->resource, destroy_data_source);
+
+ source->accept = client_source_accept;
+ source->send = client_source_send;
+ source->cancel = client_source_cancel;
+
+ wl_array_init (&source->mime_types);
+}
+
+static void
+unbind_data_device (struct wl_resource *resource)
+{
+ wl_list_remove (wl_resource_get_link (resource));
+}
+
+static void
+get_data_device (struct wl_client *client,
+ struct wl_resource *manager_resource,
+ guint32 id, struct wl_resource *seat_resource)
+{
+ MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
+ struct wl_resource *resource;
+
+ resource = wl_client_add_object (client, &wl_data_device_interface,
+ &data_device_interface, id, seat);
+
+ wl_list_insert (&seat->drag_resource_list, wl_resource_get_link (resource));
+ wl_resource_set_destructor (resource, unbind_data_device);
+}
+
+static const struct wl_data_device_manager_interface manager_interface = {
+ create_data_source,
+ get_data_device
+};
+
+static void
+bind_manager (struct wl_client *client,
+ void *data, guint32 version, guint32 id)
+{
+ wl_client_add_object (client, &wl_data_device_manager_interface,
+ &manager_interface, id, NULL);
+}
+
+void
+meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat)
+{
+ struct wl_resource *data_device, *focus, *offer;
+ MetaWaylandDataSource *source;
+
+ focus = seat->keyboard.focus_resource;
+ if (!focus)
+ return;
+
+ data_device = wl_resource_find_for_client (&seat->drag_resource_list,
+ wl_resource_get_client (focus));
+ if (!data_device)
+ return;
+
+ source = seat->selection_data_source;
+ if (source)
+ {
+ offer = meta_wayland_data_source_send_offer (source, data_device);
+ wl_data_device_send_selection (data_device, offer);
+ }
+}
+
+int
+meta_wayland_data_device_manager_init (struct wl_display *display)
+{
+ if (wl_display_add_global (display,
+ &wl_data_device_manager_interface,
+ NULL, bind_manager) == NULL)
+ return -1;
+
+ return 0;
+}
diff --git a/src/wayland/meta-wayland-data-device.h b/src/wayland/meta-wayland-data-device.h
new file mode 100644
index 000000000..58635531c
--- /dev/null
+++ b/src/wayland/meta-wayland-data-device.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef __META_WAYLAND_DATA_DEVICE_H__
+#define __META_WAYLAND_DATA_DEVICE_H__
+
+#include <wayland-server.h>
+
+#include "meta-wayland-seat.h"
+
+void
+meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat);
+
+int
+meta_wayland_data_device_manager_init (struct wl_display *display);
+
+void
+meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
+ MetaWaylandDataSource *source,
+ uint32_t serial);
+
+
+#endif /* __META_WAYLAND_DATA_DEVICE_H__ */
diff --git a/src/wayland/meta-wayland-keyboard.c b/src/wayland/meta-wayland-keyboard.c
new file mode 100644
index 000000000..c43de914e
--- /dev/null
+++ b/src/wayland/meta-wayland-keyboard.c
@@ -0,0 +1,512 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2013 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.
+ */
+
+/*
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* The file is based on src/input.c from Weston */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include <glib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "meta-wayland-keyboard.h"
+
+static MetaWaylandSeat *
+meta_wayland_keyboard_get_seat (MetaWaylandKeyboard *keyboard)
+{
+ MetaWaylandSeat *seat = wl_container_of (keyboard, seat, keyboard);
+
+ return seat;
+}
+
+static int
+create_anonymous_file (off_t size,
+ GError **error)
+{
+ static const char template[] = "mutter-shared-XXXXXX";
+ char *path;
+ int fd, flags;
+
+ fd = g_file_open_tmp (template, &path, error);
+
+ if (fd == -1)
+ return -1;
+
+ unlink (path);
+ g_free (path);
+
+ flags = fcntl (fd, F_GETFD);
+ if (flags == -1)
+ goto err;
+
+ if (fcntl (fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+ goto err;
+
+ if (ftruncate (fd, size) < 0)
+ goto err;
+
+ return fd;
+
+ err:
+ g_set_error_literal (error,
+ G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ strerror (errno));
+ close (fd);
+
+ return -1;
+}
+
+static gboolean
+meta_wayland_xkb_info_new_keymap (MetaWaylandXkbInfo *xkb_info)
+{
+ GError *error = NULL;
+ char *keymap_str;
+
+ xkb_info->shift_mod =
+ xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_SHIFT);
+ xkb_info->caps_mod =
+ xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CAPS);
+ xkb_info->ctrl_mod =
+ xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_CTRL);
+ xkb_info->alt_mod =
+ xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_ALT);
+ xkb_info->mod2_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod2");
+ xkb_info->mod3_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod3");
+ xkb_info->super_mod =
+ xkb_map_mod_get_index (xkb_info->keymap, XKB_MOD_NAME_LOGO);
+ xkb_info->mod5_mod = xkb_map_mod_get_index (xkb_info->keymap, "Mod5");
+
+ keymap_str = xkb_map_get_as_string (xkb_info->keymap);
+ if (keymap_str == NULL)
+ {
+ g_warning ("failed to get string version of keymap\n");
+ return FALSE;
+ }
+ xkb_info->keymap_size = strlen (keymap_str) + 1;
+
+ xkb_info->keymap_fd = create_anonymous_file (xkb_info->keymap_size, &error);
+ if (xkb_info->keymap_fd < 0)
+ {
+ g_warning ("creating a keymap file for %lu bytes failed: %s\n",
+ (unsigned long) xkb_info->keymap_size,
+ error->message);
+ g_clear_error (&error);
+ goto err_keymap_str;
+ }
+
+ xkb_info->keymap_area = mmap (NULL, xkb_info->keymap_size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED, xkb_info->keymap_fd, 0);
+ if (xkb_info->keymap_area == MAP_FAILED)
+ {
+ g_warning ("failed to mmap() %lu bytes\n",
+ (unsigned long) xkb_info->keymap_size);
+ goto err_dev_zero;
+ }
+ strcpy (xkb_info->keymap_area, keymap_str);
+ free (keymap_str);
+
+ return TRUE;
+
+err_dev_zero:
+ close (xkb_info->keymap_fd);
+ xkb_info->keymap_fd = -1;
+err_keymap_str:
+ free (keymap_str);
+ return FALSE;
+}
+
+static gboolean
+meta_wayland_keyboard_build_global_keymap (struct xkb_context *xkb_context,
+ struct xkb_rule_names *xkb_names,
+ MetaWaylandXkbInfo *xkb_info)
+{
+ xkb_info->keymap = xkb_map_new_from_names (xkb_context,
+ xkb_names,
+ 0 /* flags */);
+ if (xkb_info->keymap == NULL)
+ {
+ g_warning ("failed to compile global XKB keymap\n"
+ " tried rules %s, model %s, layout %s, variant %s, "
+ "options %s\n",
+ xkb_names->rules,
+ xkb_names->model,
+ xkb_names->layout,
+ xkb_names->variant,
+ xkb_names->options);
+ return FALSE;
+ }
+
+ if (!meta_wayland_xkb_info_new_keymap (xkb_info))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+lose_keyboard_focus (struct wl_listener *listener, void *data)
+{
+ MetaWaylandKeyboard *keyboard =
+ wl_container_of (listener, keyboard, focus_listener);
+
+ keyboard->focus_resource = NULL;
+}
+
+static void
+default_grab_key (MetaWaylandKeyboardGrab *grab,
+ uint32_t time, uint32_t key, uint32_t state)
+{
+ MetaWaylandKeyboard *keyboard = grab->keyboard;
+ struct wl_resource *resource;
+ uint32_t serial;
+
+ resource = keyboard->focus_resource;
+ if (resource)
+ {
+ struct wl_client *client = wl_resource_get_client (resource);
+ struct wl_display *display = wl_client_get_display (client);
+ serial = wl_display_next_serial (display);
+ wl_keyboard_send_key (resource, serial, time, key, state);
+ }
+}
+
+static struct wl_resource *
+find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface)
+{
+ struct wl_client *client;
+
+ if (!surface)
+ return NULL;
+
+ if (!surface->resource)
+ return NULL;
+
+ client = wl_resource_get_client (surface->resource);
+
+ return wl_resource_find_for_client (list, client);
+}
+
+static void
+default_grab_modifiers (MetaWaylandKeyboardGrab *grab, uint32_t serial,
+ uint32_t mods_depressed, uint32_t mods_latched,
+ uint32_t mods_locked, uint32_t group)
+{
+ MetaWaylandKeyboard *keyboard = grab->keyboard;
+ MetaWaylandSeat *seat = meta_wayland_keyboard_get_seat (keyboard);
+ MetaWaylandPointer *pointer = &seat->pointer;
+ struct wl_resource *resource, *pr;
+
+ resource = keyboard->focus_resource;
+ if (!resource)
+ return;
+
+ wl_keyboard_send_modifiers (resource, serial, mods_depressed,
+ mods_latched, mods_locked, group);
+
+ if (pointer && pointer->focus && pointer->focus != keyboard->focus)
+ {
+ pr = find_resource_for_surface (&keyboard->resource_list,
+ pointer->focus);
+ if (pr)
+ {
+ wl_keyboard_send_modifiers (pr,
+ serial,
+ keyboard->modifiers.mods_depressed,
+ keyboard->modifiers.mods_latched,
+ keyboard->modifiers.mods_locked,
+ keyboard->modifiers.group);
+ }
+ }
+}
+
+static const MetaWaylandKeyboardGrabInterface
+ default_keyboard_grab_interface = {
+ default_grab_key,
+ default_grab_modifiers,
+};
+
+gboolean
+meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
+ struct wl_display *display)
+{
+ memset (keyboard, 0, sizeof *keyboard);
+
+ wl_list_init (&keyboard->resource_list);
+ wl_array_init (&keyboard->keys);
+ keyboard->focus_listener.notify = lose_keyboard_focus;
+ keyboard->default_grab.interface = &default_keyboard_grab_interface;
+ keyboard->default_grab.keyboard = keyboard;
+ keyboard->grab = &keyboard->default_grab;
+ wl_signal_init (&keyboard->focus_signal);
+
+ keyboard->display = display;
+
+ keyboard->xkb_context = xkb_context_new (0 /* flags */);
+
+ meta_wayland_keyboard_build_global_keymap (keyboard->xkb_context,
+ &keyboard->xkb_names,
+ &keyboard->xkb_info);
+
+ return TRUE;
+}
+
+static void
+meta_wayland_xkb_info_destroy (MetaWaylandXkbInfo *xkb_info)
+{
+ if (xkb_info->keymap)
+ xkb_map_unref (xkb_info->keymap);
+
+ if (xkb_info->keymap_area)
+ munmap (xkb_info->keymap_area, xkb_info->keymap_size);
+ if (xkb_info->keymap_fd >= 0)
+ close (xkb_info->keymap_fd);
+}
+
+static void
+set_modifiers (MetaWaylandKeyboard *keyboard,
+ guint32 serial,
+ ClutterModifierType modifier_state)
+{
+ MetaWaylandKeyboardGrab *grab = keyboard->grab;
+ uint32_t depressed_mods = 0;
+ uint32_t locked_mods = 0;
+
+ if (keyboard->last_modifier_state == modifier_state)
+ return;
+
+ if ((modifier_state & CLUTTER_SHIFT_MASK) &&
+ keyboard->xkb_info.shift_mod != XKB_MOD_INVALID)
+ depressed_mods |= (1 << keyboard->xkb_info.shift_mod);
+
+ if ((modifier_state & CLUTTER_LOCK_MASK) &&
+ keyboard->xkb_info.caps_mod != XKB_MOD_INVALID)
+ locked_mods |= (1 << keyboard->xkb_info.caps_mod);
+
+ if ((modifier_state & CLUTTER_CONTROL_MASK) &&
+ keyboard->xkb_info.ctrl_mod != XKB_MOD_INVALID)
+ depressed_mods |= (1 << keyboard->xkb_info.ctrl_mod);
+
+ if ((modifier_state & CLUTTER_MOD1_MASK) &&
+ keyboard->xkb_info.alt_mod != XKB_MOD_INVALID)
+ depressed_mods |= (1 << keyboard->xkb_info.alt_mod);
+
+ if ((modifier_state & CLUTTER_MOD2_MASK) &&
+ keyboard->xkb_info.mod2_mod != XKB_MOD_INVALID)
+ depressed_mods |= (1 << keyboard->xkb_info.mod2_mod);
+
+ if ((modifier_state & CLUTTER_MOD3_MASK) &&
+ keyboard->xkb_info.mod3_mod != XKB_MOD_INVALID)
+ depressed_mods |= (1 << keyboard->xkb_info.mod3_mod);
+
+ if ((modifier_state & CLUTTER_SUPER_MASK) &&
+ keyboard->xkb_info.super_mod != XKB_MOD_INVALID)
+ depressed_mods |= (1 << keyboard->xkb_info.super_mod);
+
+ if ((modifier_state & CLUTTER_MOD5_MASK) &&
+ keyboard->xkb_info.mod5_mod != XKB_MOD_INVALID)
+ depressed_mods |= (1 << keyboard->xkb_info.mod5_mod);
+
+ keyboard->last_modifier_state = modifier_state;
+
+ grab->interface->modifiers (grab,
+ serial,
+ depressed_mods,
+ 0, /* latched_modes */
+ locked_mods,
+ 0 /* group */);
+}
+
+void
+meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
+ const ClutterKeyEvent *event)
+{
+ gboolean state = event->type == CLUTTER_KEY_PRESS;
+ guint evdev_code;
+ uint32_t serial;
+
+ /* We can't do anything with the event if we can't get an evdev
+ keycode for it */
+ if (event->device == NULL ||
+ !clutter_input_device_keycode_to_evdev (event->device,
+ event->hardware_keycode,
+ &evdev_code))
+ return;
+
+ /* We want to ignore events that are sent because of auto-repeat. In
+ the Clutter event stream these appear as a single key press
+ event. We can detect that because the key will already have been
+ pressed */
+ if (state)
+ {
+ uint32_t *end = (void *) ((char *) keyboard->keys.data +
+ keyboard->keys.size);
+ uint32_t *k;
+
+ /* Ignore the event if the key is already down */
+ for (k = keyboard->keys.data; k < end; k++)
+ if (*k == evdev_code)
+ return;
+
+ /* Otherwise add the key to the list of pressed keys */
+ k = wl_array_add (&keyboard->keys, sizeof (*k));
+ *k = evdev_code;
+ }
+ else
+ {
+ uint32_t *end = (void *) ((char *) keyboard->keys.data +
+ keyboard->keys.size);
+ uint32_t *k;
+
+ /* Remove the key from the array */
+ for (k = keyboard->keys.data; k < end; k++)
+ if (*k == evdev_code)
+ {
+ *k = *(end - 1);
+ keyboard->keys.size -= sizeof (*k);
+
+ goto found;
+ }
+
+ g_warning ("unexpected key release event for key 0x%x", evdev_code);
+
+ found:
+ (void) 0;
+ }
+
+ serial = wl_display_next_serial (keyboard->display);
+
+ set_modifiers (keyboard, serial, event->modifier_state);
+
+ keyboard->grab->interface->key (keyboard->grab,
+ event->time,
+ evdev_code,
+ state);
+}
+
+void
+meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
+ MetaWaylandSurface *surface)
+{
+ struct wl_resource *resource;
+ uint32_t serial;
+
+ if (keyboard->focus_resource && keyboard->focus != surface)
+ {
+ struct wl_display *display;
+ struct wl_client *client;
+
+ resource = keyboard->focus_resource;
+ client = wl_resource_get_client (resource);
+ display = wl_client_get_display (client);
+ serial = wl_display_next_serial (display);
+ wl_keyboard_send_leave (resource, serial, keyboard->focus->resource);
+ wl_list_remove (&keyboard->focus_listener.link);
+ }
+
+ resource = find_resource_for_surface (&keyboard->resource_list, surface);
+ if (resource &&
+ (keyboard->focus != surface || keyboard->focus_resource != resource))
+ {
+ struct wl_client *client = wl_resource_get_client (resource);
+ struct wl_display *display;
+
+ display = wl_client_get_display (client);
+ serial = wl_display_next_serial (display);
+ wl_keyboard_send_modifiers (resource, serial,
+ keyboard->modifiers.mods_depressed,
+ keyboard->modifiers.mods_latched,
+ keyboard->modifiers.mods_locked,
+ keyboard->modifiers.group);
+ wl_keyboard_send_enter (resource, serial, surface->resource,
+ &keyboard->keys);
+ wl_resource_add_destroy_listener (resource, &keyboard->focus_listener);
+ keyboard->focus_serial = serial;
+ }
+
+ keyboard->focus_resource = resource;
+ keyboard->focus = surface;
+ wl_signal_emit (&keyboard->focus_signal, keyboard);
+}
+
+void
+meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *keyboard,
+ MetaWaylandKeyboardGrab *grab)
+{
+ keyboard->grab = grab;
+ grab->keyboard = keyboard;
+
+ /* XXX focus? */
+}
+
+void
+meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard)
+{
+ keyboard->grab = &keyboard->default_grab;
+}
+
+void
+meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
+{
+ g_free ((char *) keyboard->xkb_names.rules);
+ g_free ((char *) keyboard->xkb_names.model);
+ g_free ((char *) keyboard->xkb_names.layout);
+ g_free ((char *) keyboard->xkb_names.variant);
+ g_free ((char *) keyboard->xkb_names.options);
+
+ meta_wayland_xkb_info_destroy (&keyboard->xkb_info);
+ xkb_context_unref (keyboard->xkb_context);
+
+ /* XXX: What about keyboard->resource_list? */
+ if (keyboard->focus_resource)
+ wl_list_remove (&keyboard->focus_listener.link);
+ wl_array_release (&keyboard->keys);
+}
diff --git a/src/wayland/meta-wayland-keyboard.h b/src/wayland/meta-wayland-keyboard.h
new file mode 100644
index 000000000..fd0d0b3c0
--- /dev/null
+++ b/src/wayland/meta-wayland-keyboard.h
@@ -0,0 +1,75 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2013 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.
+ */
+
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission. The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef __META_WAYLAND_KEYBOARD_H__
+#define __META_WAYLAND_KEYBOARD_H__
+
+#include <clutter/clutter.h>
+#include <wayland-server.h>
+
+#include "meta-wayland-seat.h"
+
+gboolean
+meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
+ struct wl_display *display);
+
+void
+meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
+ const ClutterKeyEvent *event);
+
+void
+meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
+ MetaWaylandSurface *surface);
+
+void
+meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *device,
+ MetaWaylandKeyboardGrab *grab);
+
+void
+meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard);
+
+void
+meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard);
+
+#endif /* __META_WAYLAND_KEYBOARD_H__ */
diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c
new file mode 100644
index 000000000..52a81ad7e
--- /dev/null
+++ b/src/wayland/meta-wayland-pointer.c
@@ -0,0 +1,260 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+/* The file is based on src/input.c from Weston */
+
+#include "config.h"
+
+#include "meta-wayland-pointer.h"
+
+static MetaWaylandSeat *
+meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer)
+{
+ MetaWaylandSeat *seat = wl_container_of (pointer, seat, pointer);
+
+ return seat;
+}
+
+static void
+lose_pointer_focus (struct wl_listener *listener, void *data)
+{
+ MetaWaylandPointer *pointer =
+ wl_container_of (listener, pointer, focus_listener);
+
+ pointer->focus_resource = NULL;
+}
+
+static void
+default_grab_focus (MetaWaylandPointerGrab *grab,
+ MetaWaylandSurface *surface,
+ wl_fixed_t x,
+ wl_fixed_t y)
+{
+ MetaWaylandPointer *pointer = grab->pointer;
+
+ if (pointer->button_count > 0)
+ return;
+
+ meta_wayland_pointer_set_focus (pointer, surface, x, y);
+}
+
+static void
+default_grab_motion (MetaWaylandPointerGrab *grab,
+ uint32_t time, wl_fixed_t x, wl_fixed_t y)
+{
+ struct wl_resource *resource;
+
+ resource = grab->pointer->focus_resource;
+ if (resource)
+ wl_pointer_send_motion (resource, time, x, y);
+}
+
+static void
+default_grab_button (MetaWaylandPointerGrab *grab,
+ uint32_t time, uint32_t button, uint32_t state_w)
+{
+ MetaWaylandPointer *pointer = grab->pointer;
+ struct wl_resource *resource;
+ uint32_t serial;
+ enum wl_pointer_button_state state = state_w;
+
+ resource = pointer->focus_resource;
+ if (resource)
+ {
+ struct wl_client *client = wl_resource_get_client (resource);
+ struct wl_display *display = wl_client_get_display (client);
+ serial = wl_display_next_serial (display);
+ wl_pointer_send_button (resource, serial, time, button, state_w);
+ }
+
+ if (pointer->button_count == 0 && state == WL_POINTER_BUTTON_STATE_RELEASED)
+ meta_wayland_pointer_set_focus (pointer, pointer->current,
+ pointer->current_x, pointer->current_y);
+}
+
+static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
+ default_grab_focus,
+ default_grab_motion,
+ default_grab_button
+};
+
+void
+meta_wayland_pointer_init (MetaWaylandPointer *pointer)
+{
+ memset (pointer, 0, sizeof *pointer);
+ wl_list_init (&pointer->resource_list);
+ pointer->focus_listener.notify = lose_pointer_focus;
+ pointer->default_grab.interface = &default_pointer_grab_interface;
+ pointer->default_grab.pointer = pointer;
+ pointer->grab = &pointer->default_grab;
+ wl_signal_init (&pointer->focus_signal);
+
+ /* FIXME: Pick better co-ords. */
+ pointer->x = wl_fixed_from_int (100);
+ pointer->y = wl_fixed_from_int (100);
+}
+
+void
+meta_wayland_pointer_release (MetaWaylandPointer *pointer)
+{
+ /* XXX: What about pointer->resource_list? */
+ if (pointer->focus_resource)
+ wl_list_remove (&pointer->focus_listener.link);
+}
+
+static struct wl_resource *
+find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface)
+{
+ struct wl_client *client;
+
+ if (!surface)
+ return NULL;
+
+ if (!surface->resource)
+ return NULL;
+
+ client = wl_resource_get_client (surface->resource);
+
+ return wl_resource_find_for_client (list, client);
+}
+
+void
+meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
+ MetaWaylandSurface *surface,
+ wl_fixed_t sx, wl_fixed_t sy)
+{
+ MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer);
+ MetaWaylandKeyboard *kbd = &seat->keyboard;
+ struct wl_resource *resource, *kr;
+ uint32_t serial;
+
+ resource = pointer->focus_resource;
+ if (resource && pointer->focus != surface)
+ {
+ struct wl_client *client = wl_resource_get_client (resource);
+ struct wl_display *display = wl_client_get_display (client);
+ serial = wl_display_next_serial (display);
+ wl_pointer_send_leave (resource, serial, pointer->focus->resource);
+ wl_list_remove (&pointer->focus_listener.link);
+ }
+
+ resource = find_resource_for_surface (&pointer->resource_list, surface);
+ if (resource &&
+ (pointer->focus != surface || pointer->focus_resource != resource))
+ {
+ struct wl_client *client = wl_resource_get_client (resource);
+ struct wl_display *display = wl_client_get_display (client);
+ serial = wl_display_next_serial (display);
+ if (kbd)
+ {
+ kr = find_resource_for_surface (&kbd->resource_list, surface);
+ if (kr)
+ {
+ wl_keyboard_send_modifiers (kr,
+ serial,
+ kbd->modifiers.mods_depressed,
+ kbd->modifiers.mods_latched,
+ kbd->modifiers.mods_locked,
+ kbd->modifiers.group);
+ }
+ }
+ wl_pointer_send_enter (resource, serial, surface->resource, sx, sy);
+ wl_resource_add_destroy_listener (resource, &pointer->focus_listener);
+ pointer->focus_serial = serial;
+ }
+
+ pointer->focus_resource = resource;
+ pointer->focus = surface;
+ pointer->default_grab.focus = surface;
+ wl_signal_emit (&pointer->focus_signal, pointer);
+}
+
+void
+meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
+ MetaWaylandPointerGrab *grab)
+{
+ const MetaWaylandPointerGrabInterface *interface;
+
+ pointer->grab = grab;
+ interface = pointer->grab->interface;
+ grab->pointer = pointer;
+
+ if (pointer->current)
+ interface->focus (pointer->grab, pointer->current,
+ pointer->current_x, pointer->current_y);
+}
+
+void
+meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer)
+{
+ const MetaWaylandPointerGrabInterface *interface;
+
+ pointer->grab = &pointer->default_grab;
+ interface = pointer->grab->interface;
+ interface->focus (pointer->grab, pointer->current,
+ pointer->current_x, pointer->current_y);
+}
+
+static void
+current_surface_destroy (struct wl_listener *listener, void *data)
+{
+ MetaWaylandPointer *pointer =
+ wl_container_of (listener, pointer, current_listener);
+
+ pointer->current = NULL;
+}
+
+void
+meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
+ MetaWaylandSurface *surface)
+{
+ if (pointer->current)
+ wl_list_remove (&pointer->current_listener.link);
+
+ pointer->current = surface;
+
+ if (!surface)
+ return;
+
+ wl_resource_add_destroy_listener (surface->resource,
+ &pointer->current_listener);
+ pointer->current_listener.notify = current_surface_destroy;
+}
diff --git a/src/wayland/meta-wayland-pointer.h b/src/wayland/meta-wayland-pointer.h
new file mode 100644
index 000000000..a1e5f3854
--- /dev/null
+++ b/src/wayland/meta-wayland-pointer.h
@@ -0,0 +1,49 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __META_WAYLAND_POINTER_H__
+#define __META_WAYLAND_POINTER_H__
+
+#include <wayland-server.h>
+
+#include "meta-wayland-seat.h"
+
+void
+meta_wayland_pointer_init (MetaWaylandPointer *pointer);
+
+void
+meta_wayland_pointer_release (MetaWaylandPointer *pointer);
+
+void
+meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
+ MetaWaylandSurface *surface,
+ wl_fixed_t sx,
+ wl_fixed_t sy);
+void
+meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
+ MetaWaylandPointerGrab *grab);
+
+void
+meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer);
+
+void
+meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
+ MetaWaylandSurface *surface);
+
+#endif /* __META_WAYLAND_POINTER_H__ */
diff --git a/src/wayland/meta-wayland-private.h b/src/wayland/meta-wayland-private.h
index 59cc6d678..c33f7f943 100644
--- a/src/wayland/meta-wayland-private.h
+++ b/src/wayland/meta-wayland-private.h
@@ -21,7 +21,7 @@
#define META_WAYLAND_PRIVATE_H
#include <wayland-server.h>
-
+#include <xkbcommon/xkbcommon.h>
#include <clutter/clutter.h>
#include <glib.h>
@@ -31,6 +31,16 @@
typedef struct _MetaWaylandCompositor MetaWaylandCompositor;
+typedef struct _MetaWaylandSeat MetaWaylandSeat;
+typedef struct _MetaWaylandPointer MetaWaylandPointer;
+typedef struct _MetaWaylandPointerGrab MetaWaylandPointerGrab;
+typedef struct _MetaWaylandPointerGrabInterface MetaWaylandPointerGrabInterface;
+typedef struct _MetaWaylandKeyboard MetaWaylandKeyboard;
+typedef struct _MetaWaylandKeyboardGrab MetaWaylandKeyboardGrab;
+typedef struct _MetaWaylandKeyboardGrabInterface MetaWaylandKeyboardGrabInterface;
+typedef struct _MetaWaylandDataOffer MetaWaylandDataOffer;
+typedef struct _MetaWaylandDataSource MetaWaylandDataSource;
+
typedef struct
{
struct wl_resource *resource;
@@ -155,17 +165,198 @@ struct _MetaWaylandCompositor
struct wl_client *xwayland_client;
struct wl_resource *xserver_resource;
GHashTable *window_surfaces;
+
+ MetaWaylandSeat *seat;
+
+ /* This surface is only used to keep drag of the implicit grab when
+ synthesizing XEvents for Mutter */
+ MetaWaylandSurface *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;
+};
+
+struct _MetaWaylandPointerGrabInterface
+{
+ void (*focus) (MetaWaylandPointerGrab * grab,
+ MetaWaylandSurface * surface, wl_fixed_t x, wl_fixed_t y);
+ void (*motion) (MetaWaylandPointerGrab * grab,
+ uint32_t time, wl_fixed_t x, wl_fixed_t y);
+ void (*button) (MetaWaylandPointerGrab * grab,
+ uint32_t time, uint32_t button, uint32_t state);
+};
+
+struct _MetaWaylandPointerGrab
+{
+ const MetaWaylandPointerGrabInterface *interface;
+ MetaWaylandPointer *pointer;
+ MetaWaylandSurface *focus;
+ wl_fixed_t x, y;
+};
+
+struct _MetaWaylandPointer
+{
+ struct wl_list resource_list;
+ MetaWaylandSurface *focus;
+ struct wl_resource *focus_resource;
+ struct wl_listener focus_listener;
+ guint32 focus_serial;
+ struct wl_signal focus_signal;
+
+ MetaWaylandPointerGrab *grab;
+ MetaWaylandPointerGrab default_grab;
+ wl_fixed_t grab_x, grab_y;
+ guint32 grab_button;
+ guint32 grab_serial;
+ guint32 grab_time;
+
+ wl_fixed_t x, y;
+ MetaWaylandSurface *current;
+ struct wl_listener current_listener;
+ wl_fixed_t current_x, current_y;
+
+ guint32 button_count;
};
-void meta_wayland_init (void);
-void meta_wayland_finalize (void);
+struct _MetaWaylandKeyboardGrabInterface
+{
+ void (*key) (MetaWaylandKeyboardGrab * grab, uint32_t time,
+ uint32_t key, uint32_t state);
+ void (*modifiers) (MetaWaylandKeyboardGrab * grab, uint32_t serial,
+ uint32_t mods_depressed, uint32_t mods_latched,
+ uint32_t mods_locked, uint32_t group);
+};
+
+struct _MetaWaylandKeyboardGrab
+{
+ const MetaWaylandKeyboardGrabInterface *interface;
+ MetaWaylandKeyboard *keyboard;
+ MetaWaylandSurface *focus;
+ uint32_t key;
+};
+
+typedef struct
+{
+ struct xkb_keymap *keymap;
+ int keymap_fd;
+ size_t keymap_size;
+ char *keymap_area;
+ xkb_mod_index_t shift_mod;
+ xkb_mod_index_t caps_mod;
+ xkb_mod_index_t ctrl_mod;
+ xkb_mod_index_t alt_mod;
+ xkb_mod_index_t mod2_mod;
+ xkb_mod_index_t mod3_mod;
+ xkb_mod_index_t super_mod;
+ xkb_mod_index_t mod5_mod;
+} MetaWaylandXkbInfo;
+
+struct _MetaWaylandKeyboard
+{
+ struct wl_list resource_list;
+ MetaWaylandSurface *focus;
+ struct wl_resource *focus_resource;
+ struct wl_listener focus_listener;
+ uint32_t focus_serial;
+ struct wl_signal focus_signal;
+
+ MetaWaylandKeyboardGrab *grab;
+ MetaWaylandKeyboardGrab default_grab;
+ uint32_t grab_key;
+ uint32_t grab_serial;
+ uint32_t grab_time;
+
+ struct wl_array keys;
+
+ struct
+ {
+ uint32_t mods_depressed;
+ uint32_t mods_latched;
+ uint32_t mods_locked;
+ uint32_t group;
+ } modifiers;
+
+ struct wl_display *display;
+
+ struct xkb_context *xkb_context;
+
+ MetaWaylandXkbInfo xkb_info;
+ struct xkb_rule_names xkb_names;
+
+ MetaWaylandKeyboardGrab input_method_grab;
+ struct wl_resource *input_method_resource;
+
+ ClutterModifierType last_modifier_state;
+};
+
+struct _MetaWaylandDataOffer
+{
+ struct wl_resource *resource;
+ MetaWaylandDataSource *source;
+ struct wl_listener source_destroy_listener;
+};
+
+struct _MetaWaylandDataSource
+{
+ struct wl_resource *resource;
+ struct wl_array mime_types;
+
+ void (*accept) (MetaWaylandDataSource * source,
+ uint32_t serial, const char *mime_type);
+ void (*send) (MetaWaylandDataSource * source,
+ const char *mime_type, int32_t fd);
+ void (*cancel) (MetaWaylandDataSource * source);
+};
+
+struct _MetaWaylandSeat
+{
+ struct wl_list base_resource_list;
+ struct wl_signal destroy_signal;
+
+ uint32_t selection_serial;
+ MetaWaylandDataSource *selection_data_source;
+ struct wl_listener selection_data_source_listener;
+ struct wl_signal selection_signal;
+
+ struct wl_list drag_resource_list;
+ struct wl_client *drag_client;
+ MetaWaylandDataSource *drag_data_source;
+ struct wl_listener drag_data_source_listener;
+ MetaWaylandSurface *drag_focus;
+ struct wl_resource *drag_focus_resource;
+ struct wl_listener drag_focus_listener;
+ MetaWaylandPointerGrab drag_grab;
+ MetaWaylandSurface *drag_surface;
+ struct wl_listener drag_icon_listener;
+ struct wl_signal drag_icon_signal;
+
+ MetaWaylandPointer pointer;
+ MetaWaylandKeyboard keyboard;
+
+ struct wl_display *display;
+
+ MetaWaylandSurface *sprite;
+ int hotspot_x, hotspot_y;
+ struct wl_listener sprite_destroy_listener;
+
+ ClutterActor *current_stage;
+};
+
+void meta_wayland_init (void);
+void meta_wayland_finalize (void);
/* We maintain a singleton MetaWaylandCompositor which can be got at via this
* API after meta_wayland_init() has been called. */
-MetaWaylandCompositor *meta_wayland_compositor_get_default (void);
+MetaWaylandCompositor *meta_wayland_compositor_get_default (void);
+
+void meta_wayland_handle_sig_child (void);
+
+MetaWaylandSurface *meta_wayland_lookup_surface_for_xid (guint32 xid);
-void meta_wayland_handle_sig_child (void);
+void meta_wayland_compositor_repick (MetaWaylandCompositor *compositor);
-MetaWaylandSurface *meta_wayland_lookup_surface_for_xid (guint32 xid);
+void meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
+ MetaWindow *window);
#endif /* META_WAYLAND_PRIVATE_H */
diff --git a/src/wayland/meta-wayland-seat.c b/src/wayland/meta-wayland-seat.c
new file mode 100644
index 000000000..fb78d0920
--- /dev/null
+++ b/src/wayland/meta-wayland-seat.c
@@ -0,0 +1,503 @@
+/*
+ * Wayland Support
+ *
+ * Copyright (C) 2013 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 <linux/input.h>
+#include <stdlib.h>
+#include <string.h>
+#include "meta-wayland-seat.h"
+#include "meta-wayland-private.h"
+#include "meta-wayland-keyboard.h"
+#include "meta-wayland-pointer.h"
+#include "meta-wayland-data-device.h"
+#include "meta-window-actor-private.h"
+#include "meta/meta-shaped-texture.h"
+
+#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int (10)
+
+static void
+unbind_resource (struct wl_resource *resource)
+{
+ wl_list_remove (wl_resource_get_link (resource));
+}
+
+static void
+transform_stage_point_fixed (MetaWaylandSurface *surface,
+ wl_fixed_t x,
+ wl_fixed_t y,
+ wl_fixed_t *sx,
+ wl_fixed_t *sy)
+{
+ float xf = 0.0f, yf = 0.0f;
+
+ if (surface->window)
+ {
+ ClutterActor *actor =
+ CLUTTER_ACTOR (meta_window_get_compositor_private (surface->window));
+
+ if (actor)
+ clutter_actor_transform_stage_point (actor,
+ wl_fixed_to_double (x),
+ wl_fixed_to_double (y),
+ &xf, &yf);
+ }
+
+ *sx = wl_fixed_from_double (xf);
+ *sy = wl_fixed_from_double (yf);
+}
+
+static void
+pointer_unmap_sprite (MetaWaylandSeat *seat)
+{
+ if (seat->sprite)
+ {
+ if (seat->sprite->window)
+ {
+ GObject *window_actor_object =
+ meta_window_get_compositor_private (seat->sprite->window);
+ ClutterActor *window_actor = CLUTTER_ACTOR (window_actor_object);
+
+ if (window_actor)
+ clutter_actor_hide (window_actor);
+ }
+
+ wl_list_remove (&seat->sprite_destroy_listener.link);
+ seat->sprite = NULL;
+ }
+}
+
+static void
+pointer_set_cursor (struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t serial,
+ struct wl_resource *surface_resource,
+ int32_t x, int32_t y)
+{
+ MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
+ MetaWaylandSurface *surface;
+
+ surface = (surface_resource ?
+ wl_resource_get_user_data (surface_resource) :
+ NULL);
+
+ if (seat->pointer.focus == NULL)
+ return;
+ if (wl_resource_get_client (seat->pointer.focus->resource) != client)
+ return;
+ if (seat->pointer.focus_serial - serial > G_MAXUINT32 / 2)
+ return;
+
+ pointer_unmap_sprite (seat);
+
+ if (!surface)
+ return;
+
+ wl_resource_add_destroy_listener (surface->resource,
+ &seat->sprite_destroy_listener);
+
+ seat->sprite = surface;
+ seat->hotspot_x = x;
+ seat->hotspot_y = y;
+}
+
+static const struct wl_pointer_interface
+pointer_interface =
+ {
+ pointer_set_cursor
+ };
+
+static void
+seat_get_pointer (struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id)
+{
+ MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
+ struct wl_resource *cr;
+
+ cr = wl_client_add_object (client, &wl_pointer_interface,
+ &pointer_interface, id, seat);
+ wl_list_insert (&seat->pointer.resource_list, wl_resource_get_link (cr));
+ wl_resource_set_destructor (cr, unbind_resource);
+
+ if (seat->pointer.focus &&
+ wl_resource_get_client (seat->pointer.focus->resource) == client)
+ {
+ MetaWaylandSurface *surface;
+ wl_fixed_t sx, sy;
+
+ surface = (MetaWaylandSurface *) seat->pointer.focus;
+ transform_stage_point_fixed (surface,
+ seat->pointer.x,
+ seat->pointer.y,
+ &sx, &sy);
+ meta_wayland_pointer_set_focus (&seat->pointer,
+ seat->pointer.focus,
+ sx, sy);
+ }
+}
+
+static void
+seat_get_keyboard (struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id)
+{
+ MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
+ struct wl_resource *cr;
+
+ cr = wl_client_add_object (client, &wl_keyboard_interface, NULL, id, seat);
+ wl_list_insert (&seat->keyboard.resource_list, wl_resource_get_link (cr));
+ wl_resource_set_destructor (cr, unbind_resource);
+
+ wl_keyboard_send_keymap (cr,
+ WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+ seat->keyboard.xkb_info.keymap_fd,
+ seat->keyboard.xkb_info.keymap_size);
+
+ if (seat->keyboard.focus &&
+ wl_resource_get_client (seat->keyboard.focus->resource) == client)
+ {
+ meta_wayland_keyboard_set_focus (&seat->keyboard,
+ seat->keyboard.focus);
+ meta_wayland_data_device_set_keyboard_focus (seat);
+ }
+}
+
+static void
+seat_get_touch (struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id)
+{
+ /* Touch not supported */
+}
+
+static const struct wl_seat_interface
+seat_interface =
+ {
+ seat_get_pointer,
+ seat_get_keyboard,
+ seat_get_touch
+ };
+
+static void
+bind_seat (struct wl_client *client,
+ void *data,
+ guint32 version,
+ guint32 id)
+{
+ MetaWaylandSeat *seat = data;
+ struct wl_resource *resource;
+
+ resource = wl_client_add_object (client,
+ &wl_seat_interface,
+ &seat_interface,
+ id,
+ data);
+ wl_list_insert (&seat->base_resource_list, wl_resource_get_link (resource));
+ wl_resource_set_destructor (resource, unbind_resource);
+
+ wl_seat_send_capabilities (resource,
+ WL_SEAT_CAPABILITY_POINTER |
+ WL_SEAT_CAPABILITY_KEYBOARD);
+}
+
+static void
+pointer_handle_sprite_destroy (struct wl_listener *listener, void *data)
+{
+ MetaWaylandSeat *seat =
+ wl_container_of (listener, seat, sprite_destroy_listener);
+
+ seat->sprite = NULL;
+}
+
+MetaWaylandSeat *
+meta_wayland_seat_new (struct wl_display *display)
+{
+ MetaWaylandSeat *seat = g_new0 (MetaWaylandSeat, 1);
+
+ wl_signal_init (&seat->destroy_signal);
+
+ seat->selection_data_source = NULL;
+ wl_list_init (&seat->base_resource_list);
+ wl_signal_init (&seat->selection_signal);
+ wl_list_init (&seat->drag_resource_list);
+ wl_signal_init (&seat->drag_icon_signal);
+
+ meta_wayland_pointer_init (&seat->pointer);
+
+ meta_wayland_keyboard_init (&seat->keyboard, display);
+
+ seat->display = display;
+
+ seat->current_stage = 0;
+
+ seat->sprite = NULL;
+ seat->sprite_destroy_listener.notify = pointer_handle_sprite_destroy;
+ seat->hotspot_x = 16;
+ seat->hotspot_y = 16;
+
+ wl_display_add_global (display, &wl_seat_interface, seat, bind_seat);
+
+ return seat;
+}
+
+static void
+notify_motion (MetaWaylandSeat *seat,
+ const ClutterEvent *event)
+{
+ MetaWaylandPointer *pointer = &seat->pointer;
+ float x, y;
+
+ clutter_event_get_coords (event, &x, &y);
+ pointer->x = wl_fixed_from_double (x);
+ pointer->y = wl_fixed_from_double (y);
+
+ meta_wayland_seat_repick (seat,
+ clutter_event_get_time (event),
+ clutter_event_get_source (event));
+
+ pointer->grab->interface->motion (pointer->grab,
+ clutter_event_get_time (event),
+ pointer->grab->x,
+ pointer->grab->y);
+}
+
+static void
+handle_motion_event (MetaWaylandSeat *seat,
+ const ClutterMotionEvent *event)
+{
+ notify_motion (seat, (const ClutterEvent *) event);
+}
+
+static void
+handle_button_event (MetaWaylandSeat *seat,
+ const ClutterButtonEvent *event)
+{
+ MetaWaylandPointer *pointer = &seat->pointer;
+ gboolean state = event->type == CLUTTER_BUTTON_PRESS;
+ uint32_t button;
+
+ notify_motion (seat, (const ClutterEvent *) event);
+
+ 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 (pointer->button_count == 0)
+ {
+ pointer->grab_button = button;
+ pointer->grab_time = event->time;
+ pointer->grab_x = pointer->x;
+ pointer->grab_y = pointer->y;
+ }
+
+ pointer->button_count++;
+ }
+ else
+ pointer->button_count--;
+
+ pointer->grab->interface->button (pointer->grab, event->time, button, state);
+
+ if (pointer->button_count == 1)
+ pointer->grab_serial = wl_display_get_serial (seat->display);
+}
+
+static void
+handle_scroll_event (MetaWaylandSeat *seat,
+ const ClutterScrollEvent *event)
+{
+ enum wl_pointer_axis axis;
+ wl_fixed_t value;
+
+ notify_motion (seat, (const ClutterEvent *) event);
+
+ switch (event->direction)
+ {
+ case CLUTTER_SCROLL_UP:
+ axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
+ value = -DEFAULT_AXIS_STEP_DISTANCE;
+ break;
+
+ case CLUTTER_SCROLL_DOWN:
+ axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
+ value = DEFAULT_AXIS_STEP_DISTANCE;
+ break;
+
+ case CLUTTER_SCROLL_LEFT:
+ axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
+ value = -DEFAULT_AXIS_STEP_DISTANCE;
+ break;
+
+ case CLUTTER_SCROLL_RIGHT:
+ axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
+ value = DEFAULT_AXIS_STEP_DISTANCE;
+ break;
+
+ default:
+ return;
+ }
+
+ if (seat->pointer.focus_resource)
+ wl_pointer_send_axis (seat->pointer.focus_resource,
+ event->time,
+ axis,
+ value);
+}
+
+void
+meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
+ const ClutterEvent *event)
+{
+ switch (event->type)
+ {
+ case CLUTTER_MOTION:
+ handle_motion_event (seat,
+ (const ClutterMotionEvent *) event);
+ break;
+
+ case CLUTTER_BUTTON_PRESS:
+ case CLUTTER_BUTTON_RELEASE:
+ handle_button_event (seat,
+ (const ClutterButtonEvent *) event);
+ break;
+
+ case CLUTTER_KEY_PRESS:
+ case CLUTTER_KEY_RELEASE:
+ meta_wayland_keyboard_handle_event (&seat->keyboard,
+ (const ClutterKeyEvent *) event);
+ break;
+
+ case CLUTTER_SCROLL:
+ handle_scroll_event (seat, (const ClutterScrollEvent *) event);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+update_pointer_position_for_actor (MetaWaylandPointer *pointer,
+ ClutterActor *actor)
+{
+ float ax, ay;
+
+ clutter_actor_transform_stage_point (actor,
+ wl_fixed_to_double (pointer->x),
+ wl_fixed_to_double (pointer->y),
+ &ax, &ay);
+ pointer->current_x = wl_fixed_from_double (ax);
+ pointer->current_y = wl_fixed_from_double (ay);
+}
+
+/* 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_seat_repick (MetaWaylandSeat *seat,
+ uint32_t time,
+ ClutterActor *actor)
+{
+ MetaWaylandPointer *pointer = &seat->pointer;
+ MetaWaylandSurface *surface = NULL;
+
+ if (actor == NULL && seat->current_stage)
+ {
+ ClutterStage *stage = CLUTTER_STAGE (seat->current_stage);
+ actor = clutter_stage_get_actor_at_pos (stage,
+ CLUTTER_PICK_REACTIVE,
+ wl_fixed_to_double (pointer->x),
+ wl_fixed_to_double (pointer->y));
+ }
+
+ if (actor)
+ seat->current_stage = clutter_actor_get_stage (actor);
+ else
+ seat->current_stage = NULL;
+
+ if (META_IS_WINDOW_ACTOR (actor))
+ {
+ MetaWindow *window =
+ meta_window_actor_get_meta_window (META_WINDOW_ACTOR (actor));
+
+ update_pointer_position_for_actor (pointer, actor);
+
+ surface = window->surface;
+ }
+ else if (META_IS_SHAPED_TEXTURE (actor))
+ {
+ MetaShapedTexture *shaped_texture = META_SHAPED_TEXTURE (actor);
+
+ update_pointer_position_for_actor (pointer, actor);
+
+ surface = meta_shaped_texture_get_wayland_surface (shaped_texture);
+ }
+
+ if (surface != pointer->current)
+ {
+ const MetaWaylandPointerGrabInterface *interface =
+ pointer->grab->interface;
+ interface->focus (pointer->grab,
+ surface,
+ pointer->current_x, pointer->current_y);
+ pointer->current = surface;
+ }
+
+ if (pointer->grab->focus)
+ transform_stage_point_fixed (pointer->grab->focus,
+ pointer->x,
+ pointer->y,
+ &pointer->grab->x,
+ &pointer->grab->y);
+}
+
+void
+meta_wayland_seat_free (MetaWaylandSeat *seat)
+{
+ pointer_unmap_sprite (seat);
+
+ meta_wayland_pointer_release (&seat->pointer);
+ meta_wayland_keyboard_release (&seat->keyboard);
+
+ wl_signal_emit (&seat->destroy_signal, seat);
+
+ g_slice_free (MetaWaylandSeat, seat);
+}
diff --git a/src/wayland/meta-wayland-seat.h b/src/wayland/meta-wayland-seat.h
new file mode 100644
index 000000000..ee567785e
--- /dev/null
+++ b/src/wayland/meta-wayland-seat.h
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+#ifndef __META_WAYLAND_SEAT_H__
+#define __META_WAYLAND_SEAT_H__
+
+#include <wayland-server.h>
+#include <xkbcommon/xkbcommon.h>
+#include <clutter/clutter.h>
+#include <glib.h>
+
+#include "meta-wayland-private.h"
+
+MetaWaylandSeat *
+meta_wayland_seat_new (struct wl_display *display);
+
+void
+meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
+ const ClutterEvent *event);
+
+void
+meta_wayland_seat_repick (MetaWaylandSeat *seat,
+ uint32_t time,
+ ClutterActor *actor);
+
+void
+meta_wayland_seat_free (MetaWaylandSeat *seat);
+
+#endif /* __META_WAYLAND_SEAT_H__ */
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 437406818..c364de0e4 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -40,6 +40,9 @@
#include "meta-wayland-private.h"
#include "meta-xwayland-private.h"
#include "meta-window-actor-private.h"
+#include "meta-wayland-seat.h"
+#include "meta-wayland-keyboard.h"
+#include "meta-wayland-data-device.h"
#include "display-private.h"
#include "window-private.h"
#include <meta/types.h>
@@ -414,6 +417,17 @@ const struct wl_surface_interface meta_wayland_surface_interface = {
meta_wayland_surface_set_buffer_scale
};
+void
+meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
+ MetaWindow *window)
+{
+ MetaWaylandSurface *surface = window ? window->surface : NULL;
+
+ meta_wayland_keyboard_set_focus (&compositor->seat->keyboard,
+ surface);
+ meta_wayland_data_device_set_keyboard_focus (compositor->seat);
+}
+
static void
window_destroyed_cb (void *user_data, GObject *old_object)
{
@@ -422,6 +436,14 @@ window_destroyed_cb (void *user_data, GObject *old_object)
surface->window = NULL;
}
+void
+meta_wayland_compositor_repick (MetaWaylandCompositor *compositor)
+{
+ meta_wayland_seat_repick (compositor->seat,
+ get_time (),
+ NULL);
+}
+
static void
meta_wayland_surface_free (MetaWaylandSurface *surface)
{
@@ -457,6 +479,11 @@ meta_wayland_surface_free (MetaWaylandSurface *surface)
wl_resource_destroy (cb->resource);
g_slice_free (MetaWaylandSurface, surface);
+
+ meta_wayland_compositor_repick (compositor);
+
+ if (compositor->implicit_grab_surface == surface)
+ compositor->implicit_grab_surface = compositor->seat->pointer.current;
}
static void
@@ -962,6 +989,14 @@ xserver_set_window_id (struct wl_client *client,
g_object_weak_ref (G_OBJECT (surface->window),
window_destroyed_cb,
surface);
+
+ /* If the window is already meant to have focus then the
+ * original attempt to call this in response to the FocusIn
+ * event will have been lost because there was no surface
+ * yet. */
+ if (window->has_focus)
+ meta_wayland_compositor_set_input_focus (compositor, window);
+
}
#warning "FIXME: Handle surface destroy and remove window_surfaces mapping"
}
@@ -1022,10 +1057,236 @@ stage_destroy_cb (void)
meta_quit (META_EXIT_SUCCESS);
}
+#define N_BUTTONS 5
+
+static void
+synthesize_motion_event (MetaWaylandCompositor *compositor,
+ const ClutterEvent *event)
+{
+ /* 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 position. See the comment in
+ event_callback() in display.c */
+ MetaWaylandSeat *seat = compositor->seat;
+ MetaWaylandPointer *pointer = &seat->pointer;
+ MetaWaylandSurface *surface;
+ XGenericEventCookie generic_event;
+ XIDeviceEvent device_event;
+ unsigned char button_mask[(N_BUTTONS + 7) / 8] = { 0 };
+ MetaDisplay *display = meta_get_display ();
+ ClutterModifierType state;
+ int i;
+
+ generic_event.type = GenericEvent;
+ generic_event.serial = 0;
+ generic_event.send_event = False;
+ generic_event.display = display->xdisplay;
+ generic_event.extension = display->xinput_opcode;
+ generic_event.evtype = XI_Motion;
+ /* Mutter assumes the data for the event is already retrieved by GDK
+ * so we don't need the cookie */
+ generic_event.cookie = 0;
+ generic_event.data = &device_event;
+
+ memcpy (&device_event, &generic_event, sizeof (XGenericEvent));
+
+ device_event.time = clutter_event_get_time (event);
+ device_event.deviceid = clutter_event_get_device_id (event);
+ device_event.sourceid = 0; /* not used, not sure what this should be */
+ device_event.detail = 0;
+ device_event.root = DefaultRootWindow (display->xdisplay);
+ device_event.flags = 0 /* not used for motion events */;
+
+ if (compositor->implicit_grab_surface)
+ surface = compositor->implicit_grab_surface;
+ else
+ surface = pointer->current;
+
+ if (surface == pointer->current)
+ {
+ device_event.event_x = wl_fixed_to_int (pointer->current_x);
+ device_event.event_y = wl_fixed_to_int (pointer->current_y);
+ }
+ else if (surface && surface->window)
+ {
+ ClutterActor *window_actor =
+ CLUTTER_ACTOR (meta_window_get_compositor_private (surface->window));
+
+ if (window_actor)
+ {
+ float ax, ay;
+
+ clutter_actor_transform_stage_point (window_actor,
+ wl_fixed_to_double (pointer->x),
+ wl_fixed_to_double (pointer->y),
+ &ax, &ay);
+
+ device_event.event_x = ax;
+ device_event.event_y = ay;
+ }
+ else
+ {
+ device_event.event_x = wl_fixed_to_double (pointer->x);
+ device_event.event_y = wl_fixed_to_double (pointer->y);
+ }
+ }
+ else
+ {
+ device_event.event_x = wl_fixed_to_double (pointer->x);
+ device_event.event_y = wl_fixed_to_double (pointer->y);
+ }
+
+ if (surface && surface->xid != None)
+ device_event.event = surface->xid;
+ else
+ device_event.event = device_event.root;
+
+ /* Mutter doesn't really know about the sub-windows. This assumes it
+ doesn't care either */
+ device_event.child = device_event.event;
+ device_event.root_x = wl_fixed_to_double (pointer->x);
+ device_event.root_y = wl_fixed_to_double (pointer->y);
+
+ state = clutter_event_get_state (event);
+
+ for (i = 0; i < N_BUTTONS; i++)
+ if ((state & (CLUTTER_BUTTON1_MASK << i)))
+ XISetMask (button_mask, i + 1);
+ device_event.buttons.mask_len = N_BUTTONS + 1;
+ device_event.buttons.mask = button_mask;
+
+ device_event.valuators.mask_len = 0;
+ device_event.valuators.mask = NULL;
+ device_event.valuators.values = NULL;
+
+ memset (&device_event.mods, 0, sizeof (device_event.mods));
+ device_event.mods.effective =
+ state & (CLUTTER_MODIFIER_MASK &
+ ~(((CLUTTER_BUTTON1_MASK << N_BUTTONS) - 1) ^
+ (CLUTTER_BUTTON1_MASK - 1)));
+
+ memset (&device_event.group, 0, sizeof (device_event.group));
+
+ meta_display_handle_event (display, (XEvent *) &generic_event);
+}
+
+static gboolean
+event_cb (ClutterActor *stage,
+ const ClutterEvent *event,
+ MetaWaylandCompositor *compositor)
+{
+ MetaWaylandSeat *seat = compositor->seat;
+ MetaWaylandPointer *pointer = &seat->pointer;
+ MetaWaylandSurface *surface;
+ MetaDisplay *display;
+
+ meta_wayland_seat_handle_event (compositor->seat, event);
+
+ /* HACK: for now, the surfaces from Wayland clients aren't
+ integrated into Mutter's stacking and Mutter won't give them
+ focus on mouse clicks. As a hack to work around this we can just
+ give them input focus on mouse clicks so we can at least test the
+ keyboard support */
+ if (event->type == CLUTTER_BUTTON_PRESS)
+ {
+ surface = pointer->current;
+
+ /* Only focus surfaces that wouldn't be handled by the
+ corresponding X events */
+ if (surface && surface->xid == 0)
+ {
+ meta_wayland_keyboard_set_focus (&seat->keyboard, surface);
+ meta_wayland_data_device_set_keyboard_focus (seat);
+ }
+ }
+
+ display = meta_get_display ();
+ if (!display)
+ return FALSE;
+
+ switch (event->type)
+ {
+ case CLUTTER_BUTTON_PRESS:
+ if (compositor->implicit_grab_surface == NULL)
+ {
+ compositor->implicit_grab_button = event->button.button;
+ compositor->implicit_grab_surface = pointer->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:
+ synthesize_motion_event (compositor, event);
+ return FALSE;
+
+ default:
+ return FALSE;
+ }
+}
+
+static gboolean
+event_emission_hook_cb (GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data)
+{
+ MetaWaylandCompositor *compositor = data;
+ ClutterActor *actor;
+ ClutterEvent *event;
+
+ g_return_val_if_fail (n_param_values == 2, FALSE);
+
+ actor = g_value_get_object (param_values + 0);
+ event = g_value_get_boxed (param_values + 1);
+
+ if (actor == NULL)
+ return TRUE /* stay connected */;
+
+ /* If this event belongs to the corresponding grab for this event
+ * type then the captured-event signal won't be emitted so we have
+ * to manually forward it on */
+
+ switch (event->type)
+ {
+ /* Pointer events */
+ case CLUTTER_MOTION:
+ case CLUTTER_ENTER:
+ case CLUTTER_LEAVE:
+ case CLUTTER_BUTTON_PRESS:
+ case CLUTTER_BUTTON_RELEASE:
+ case CLUTTER_SCROLL:
+ if (actor == clutter_get_pointer_grab ())
+ event_cb (clutter_actor_get_stage (actor),
+ event,
+ compositor);
+ break;
+
+ /* Keyboard events */
+ case CLUTTER_KEY_PRESS:
+ case CLUTTER_KEY_RELEASE:
+ if (actor == clutter_get_keyboard_grab ())
+ event_cb (clutter_actor_get_stage (actor),
+ event,
+ compositor);
+
+ default:
+ break;
+ }
+
+ return TRUE /* stay connected */;
+}
+
void
meta_wayland_init (void)
{
MetaWaylandCompositor *compositor = &_meta_wayland_compositor;
+ guint event_signal;
memset (compositor, 0, sizeof (MetaWaylandCompositor));
@@ -1072,6 +1333,25 @@ meta_wayland_init (void)
g_signal_connect (compositor->stage, "destroy",
G_CALLBACK (stage_destroy_cb), NULL);
+ meta_wayland_data_device_manager_init (compositor->wayland_display);
+
+ compositor->seat = meta_wayland_seat_new (compositor->wayland_display);
+
+ g_signal_connect (compositor->stage,
+ "captured-event",
+ G_CALLBACK (event_cb),
+ compositor);
+ /* If something sets a grab on an actor then the captured event
+ * signal won't get emitted but we still want to see these events so
+ * we can update the cursor position. To make sure we see all events
+ * we also install an emission hook on the event signal */
+ event_signal = g_signal_lookup ("event", CLUTTER_TYPE_STAGE);
+ g_signal_add_emission_hook (event_signal,
+ 0 /* detail */,
+ event_emission_hook_cb,
+ compositor, /* hook_data */
+ NULL /* data_destroy */);
+
meta_wayland_compositor_create_output (compositor, 0, 0, 1024, 600, 222, 125);
if (wl_global_create (compositor->wayland_display,