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.c280
1 files changed, 280 insertions, 0 deletions
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,