diff options
Diffstat (limited to 'src/wayland/meta-wayland.c')
-rw-r--r-- | src/wayland/meta-wayland.c | 233 |
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, |