summaryrefslogtreecommitdiff
path: root/src/wayland/meta-wayland.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/wayland/meta-wayland.c')
-rw-r--r--src/wayland/meta-wayland.c233
1 files changed, 233 insertions, 0 deletions
diff --git a/src/wayland/meta-wayland.c b/src/wayland/meta-wayland.c
index 5f481867d..673189d20 100644
--- a/src/wayland/meta-wayland.c
+++ b/src/wayland/meta-wayland.c
@@ -44,6 +44,7 @@
#include "meta-wayland-private.h"
#include "meta-window-actor-private.h"
+#include "meta-wayland-seat.h"
#include "display-private.h"
#include "window-private.h"
#include <meta/types.h>
@@ -316,6 +317,8 @@ meta_wayland_surface_commit (struct wl_client *client,
{
surface_actor = CLUTTER_WAYLAND_SURFACE (surface->actor);
+ clutter_actor_set_reactive (surface->actor, TRUE);
+
if (!clutter_wayland_surface_attach_buffer (surface_actor,
buffer,
&error))
@@ -381,6 +384,33 @@ const struct wl_surface_interface meta_wayland_surface_interface = {
meta_wayland_surface_set_buffer_transform
};
+void
+meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
+ MetaWindow *window)
+{
+ struct wl_surface *surface = NULL;
+
+ if (window)
+ {
+ MetaWindowActor *window_actor =
+ META_WINDOW_ACTOR (meta_window_get_compositor_private (window));
+ ClutterActor *shaped_texture =
+ meta_window_actor_get_shaped_texture (window_actor);
+
+ if (CLUTTER_WAYLAND_IS_SURFACE (shaped_texture))
+ {
+ ClutterWaylandSurface *surface_actor =
+ CLUTTER_WAYLAND_SURFACE (shaped_texture);
+
+ surface = clutter_wayland_surface_get_surface (surface_actor);
+ }
+ }
+
+ wl_keyboard_set_focus (((struct wl_seat *) compositor->seat)->keyboard,
+ surface);
+ wl_data_device_set_keyboard_focus ((struct wl_seat *) compositor->seat);
+}
+
static void
surface_actor_destroyed_cb (void *user_data,
GObject *old_object)
@@ -391,6 +421,14 @@ surface_actor_destroyed_cb (void *user_data,
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)
{
@@ -425,6 +463,12 @@ 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 == (struct wl_surface *) surface)
+ compositor->implicit_grab_surface =
+ ((struct wl_seat *) compositor->seat)->pointer->current;
}
static void
@@ -1281,10 +1325,180 @@ stage_destroy_cb (void)
meta_quit (META_EXIT_SUCCESS);
}
+static gboolean
+event_cb (ClutterActor *stage,
+ const ClutterEvent *event,
+ MetaWaylandCompositor *compositor)
+{
+ struct wl_seat *seat = (struct wl_seat *) compositor->seat;
+ struct wl_pointer *pointer = seat->pointer;
+ MetaWaylandSurface *surface;
+ MetaDisplay *display;
+ XMotionEvent xevent;
+
+ 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)
+ {
+ MetaWaylandSurface *surface = (MetaWaylandSurface *) pointer->current;
+
+ /* Only focus surfaces that wouldn't be handled by the
+ corresponding X events */
+ if (surface && surface->xid == 0)
+ {
+ wl_keyboard_set_focus (seat->keyboard, &surface->wayland_surface);
+ wl_data_device_set_keyboard_focus (seat);
+ }
+ }
+
+ 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 = 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:
+ 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 *) pointer->current;
+
+ if (surface == (MetaWaylandSurface *) pointer->current)
+ {
+ xevent.x = pointer->current_x;
+ xevent.y = pointer->current_y;
+ }
+ else if (surface)
+ {
+ float ax, ay;
+
+ clutter_actor_transform_stage_point (surface->actor,
+ pointer->x, pointer->y,
+ &ax, &ay);
+ xevent.x = ax;
+ xevent.y = ay;
+ }
+ else
+ {
+ xevent.x = pointer->x;
+ xevent.y = pointer->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 = pointer->x;
+ xevent.y_root = pointer->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;
+}
+
+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));
@@ -1332,6 +1546,25 @@ meta_wayland_init (void)
g_signal_connect (compositor->stage, "destroy",
G_CALLBACK (stage_destroy_cb), NULL);
+ wl_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_display_add_global (compositor->wayland_display, &wl_shell_interface,