wayland: heavily refactor pointer grabs

Grabs are now slice allocated structures that are handled by
whoever starts the grab. They contain a generic grab structure
with the interface and a backpointer to the MetaWaylandPointer.
The grab interface has been changed to pass full clutter events,
which allowed to remove the confusion between grab->focus and
pointer->focus. Invidual grabs are now required to keep their
focus, and choose whoever gets the events.

https://bugzilla.gnome.org/show_bug.cgi?id=707863
This commit is contained in:
Giovanni Campagna 2013-09-11 14:06:05 +02:00
parent 76e2455d1b
commit 776a86a65f
7 changed files with 378 additions and 422 deletions

View File

@ -151,42 +151,63 @@ static struct wl_data_source_interface data_source_interface = {
data_source_destroy
};
typedef struct {
MetaWaylandPointerGrab generic;
MetaWaylandSeat *seat;
struct wl_client *drag_client;
MetaWaylandSurface *drag_focus;
struct wl_resource *drag_focus_data_device;
struct wl_listener drag_focus_listener;
MetaWaylandSurface *drag_surface;
struct wl_listener drag_icon_listener;
MetaWaylandDataSource *drag_data_source;
struct wl_listener drag_data_source_listener;
} MetaWaylandDragGrab;
static void
destroy_drag_focus (struct wl_listener *listener, void *data)
{
MetaWaylandSeat *seat = wl_container_of (listener, seat, drag_focus_listener);
MetaWaylandDragGrab *grab = wl_container_of (listener, grab, drag_focus_listener);
seat->drag_focus_resource = NULL;
grab->drag_focus_data_device = NULL;
}
static void
drag_grab_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
wl_fixed_t x,
wl_fixed_t y)
MetaWaylandSurface *surface,
const ClutterEvent *event)
{
MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
MetaWaylandSeat *seat = drag_grab->seat;
struct wl_resource *resource, *offer = NULL;
struct wl_display *display;
guint32 serial;
wl_fixed_t sx, sy;
if (seat->drag_focus_resource)
if (drag_grab->drag_focus == surface)
return;
if (drag_grab->drag_focus_data_device)
{
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;
wl_data_device_send_leave (drag_grab->drag_focus_data_device);
wl_list_remove (&drag_grab->drag_focus_listener.link);
drag_grab->drag_focus_data_device = NULL;
drag_grab->drag_focus = NULL;
}
if (!surface)
return;
if (!seat->drag_data_source &&
wl_resource_get_client (surface->resource) != seat->drag_client)
if (!drag_grab->drag_data_source &&
wl_resource_get_client (surface->resource) != drag_grab->drag_client)
return;
resource =
wl_resource_find_for_client (&seat->drag_resource_list,
wl_resource_find_for_client (&seat->data_device_resource_list,
wl_resource_get_client (surface->resource));
if (!resource)
return;
@ -194,68 +215,73 @@ drag_grab_focus (MetaWaylandPointerGrab *grab,
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,
if (drag_grab->drag_data_source)
offer = meta_wayland_data_source_send_offer (drag_grab->drag_data_source,
resource);
meta_wayland_pointer_get_relative_coordinates (grab->pointer, surface, &sx, &sy);
wl_data_device_send_enter (resource, serial, surface->resource,
x, y, offer);
sx, sy, 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;
drag_grab->drag_focus = surface;
drag_grab->drag_focus_data_device = resource;
drag_grab->drag_focus_listener.notify = destroy_drag_focus;
wl_resource_add_destroy_listener (resource, &drag_grab->drag_focus_listener);
}
static void
drag_grab_motion (MetaWaylandPointerGrab *grab,
guint32 time, wl_fixed_t x, wl_fixed_t y)
const ClutterEvent *event)
{
MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
wl_fixed_t sx, sy;
if (seat->drag_focus_resource)
wl_data_device_send_motion (seat->drag_focus_resource, time, x, y);
if (drag_grab->drag_focus_data_device)
{
meta_wayland_pointer_get_relative_coordinates (grab->pointer,
drag_grab->drag_focus,
&sx, &sy);
wl_data_device_send_motion (drag_grab->drag_focus_data_device,
clutter_event_get_time (event),
sx, sy);
}
}
static void
data_device_end_drag_grab (MetaWaylandSeat *seat)
data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
{
if (seat->drag_surface)
if (drag_grab->drag_surface)
{
seat->drag_surface = NULL;
wl_signal_emit (&seat->drag_icon_signal, NULL);
wl_list_remove (&seat->drag_icon_listener.link);
drag_grab->drag_surface = NULL;
wl_list_remove (&drag_grab->drag_icon_listener.link);
}
drag_grab_focus (&seat->drag_grab, NULL,
wl_fixed_from_int (0), wl_fixed_from_int (0));
if (drag_grab->drag_data_source)
wl_list_remove (&drag_grab->drag_data_source_listener.link);
meta_wayland_pointer_end_grab (&seat->pointer);
drag_grab_focus (&drag_grab->generic, NULL, NULL);
seat->drag_data_source = NULL;
seat->drag_client = NULL;
meta_wayland_pointer_end_grab (drag_grab->generic.pointer);
g_slice_free (MetaWaylandDragGrab, drag_grab);
}
static void
drag_grab_button (MetaWaylandPointerGrab *grab,
guint32 time, guint32 button, guint32 state_w)
const ClutterEvent *event)
{
MetaWaylandSeat *seat = wl_container_of (grab, seat, drag_grab);
enum wl_pointer_button_state state = state_w;
MetaWaylandDragGrab *drag_grab = (MetaWaylandDragGrab*) grab;
MetaWaylandSeat *seat = drag_grab->seat;
ClutterEventType event_type = clutter_event_type (event);
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 (drag_grab->drag_focus_data_device &&
drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) &&
event_type == CLUTTER_BUTTON_RELEASE)
wl_data_device_send_drop (drag_grab->drag_focus_data_device);
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);
}
event_type == CLUTTER_BUTTON_RELEASE)
data_device_end_drag_grab (drag_grab);
}
static const MetaWaylandPointerGrabInterface drag_grab_interface = {
@ -267,19 +293,20 @@ static const MetaWaylandPointerGrabInterface drag_grab_interface = {
static void
destroy_data_device_source (struct wl_listener *listener, void *data)
{
MetaWaylandSeat *seat =
wl_container_of (listener, seat, drag_data_source_listener);
MetaWaylandDragGrab *drag_grab =
wl_container_of (listener, drag_grab, drag_data_source_listener);
data_device_end_drag_grab (seat);
drag_grab->drag_data_source = NULL;
data_device_end_drag_grab (drag_grab);
}
static void
destroy_data_device_icon (struct wl_listener *listener, void *data)
{
MetaWaylandSeat *seat =
wl_container_of (listener, seat, drag_icon_listener);
MetaWaylandDragGrab *drag_grab =
wl_container_of (listener, drag_grab, drag_data_source_listener);
seat->drag_surface = NULL;
drag_grab->drag_surface = NULL;
}
static void
@ -290,38 +317,40 @@ data_device_start_drag (struct wl_client *client,
struct wl_resource *icon_resource, guint32 serial)
{
MetaWaylandSeat *seat = wl_resource_get_user_data (resource);
MetaWaylandDragGrab *drag_grab;
/* 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;
if (seat->pointer.grab != &seat->pointer.default_grab)
return;
seat->drag_client = client;
seat->drag_data_source = NULL;
drag_grab = g_slice_new0 (MetaWaylandDragGrab);
drag_grab->generic.interface = &drag_grab_interface;
drag_grab->generic.pointer = &seat->pointer;
drag_grab->drag_client = client;
if (source_resource)
{
seat->drag_data_source = wl_resource_get_user_data (source_resource);
seat->drag_data_source_listener.notify = destroy_data_device_source;
drag_grab->drag_data_source = wl_resource_get_user_data (source_resource);
drag_grab->drag_data_source_listener.notify = destroy_data_device_source;
wl_resource_add_destroy_listener (source_resource,
&seat->drag_data_source_listener);
&drag_grab->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;
drag_grab->drag_surface = wl_resource_get_user_data (icon_resource);
drag_grab->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);
&drag_grab->drag_icon_listener);
}
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);
meta_wayland_pointer_set_focus (&seat->pointer, NULL);
meta_wayland_pointer_start_grab (&seat->pointer, (MetaWaylandPointerGrab*)drag_grab);
}
static void
@ -339,7 +368,7 @@ destroy_selection_data_source (struct wl_listener *listener, void *data)
if (focus)
{
data_device =
wl_resource_find_for_client (&seat->drag_resource_list,
wl_resource_find_for_client (&seat->data_device_resource_list,
wl_resource_get_client (focus));
if (data_device)
wl_data_device_send_selection (data_device, NULL);
@ -375,7 +404,7 @@ meta_wayland_seat_set_selection (MetaWaylandSeat *seat,
if (focus)
{
data_device =
wl_resource_find_for_client (&seat->drag_resource_list,
wl_resource_find_for_client (&seat->data_device_resource_list,
wl_resource_get_client (focus));
if (data_device && source)
{
@ -497,7 +526,7 @@ get_data_device (struct wl_client *client,
MIN (META_WL_DATA_DEVICE_VERSION,
wl_resource_get_version (manager_resource)), id);
wl_resource_set_implementation (resource, &data_device_interface, seat, unbind_data_device);
wl_list_insert (&seat->drag_resource_list, wl_resource_get_link (resource));
wl_list_insert (&seat->data_device_resource_list, wl_resource_get_link (resource));
}
static const struct wl_data_device_manager_interface manager_interface = {
@ -526,7 +555,7 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandSeat *seat)
if (!focus)
return;
data_device = wl_resource_find_for_client (&seat->drag_resource_list,
data_device = wl_resource_find_for_client (&seat->data_device_resource_list,
wl_resource_get_client (focus));
if (!data_device)
return;

View File

@ -45,6 +45,7 @@
#include <clutter/clutter.h>
#include <clutter/evdev/clutter-evdev.h>
#include <linux/input.h>
#include "meta-wayland-pointer.h"
#include "meta-wayland-private.h"
@ -73,51 +74,79 @@ lose_pointer_focus (struct wl_listener *listener, void *data)
static void
default_grab_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
wl_fixed_t x,
wl_fixed_t y)
MetaWaylandSurface *surface,
const ClutterEvent *event)
{
MetaWaylandPointer *pointer = grab->pointer;
if (pointer->button_count > 0)
return;
meta_wayland_pointer_set_focus (pointer, surface, x, y);
meta_wayland_pointer_set_focus (pointer, surface);
}
static void
default_grab_motion (MetaWaylandPointerGrab *grab,
uint32_t time, wl_fixed_t x, wl_fixed_t y)
const ClutterEvent *event)
{
struct wl_resource *resource;
resource = grab->pointer->focus_resource;
if (resource)
wl_pointer_send_motion (resource, time, x, y);
{
wl_fixed_t sx, sy;
meta_wayland_pointer_get_relative_coordinates (grab->pointer,
grab->pointer->focus,
&sx, &sy);
wl_pointer_send_motion (resource, clutter_event_get_time (event), sx, sy);
}
}
static void
default_grab_button (MetaWaylandPointerGrab *grab,
uint32_t time, uint32_t button, uint32_t state_w)
const ClutterEvent *event)
{
MetaWaylandPointer *pointer = grab->pointer;
struct wl_resource *resource;
uint32_t serial;
enum wl_pointer_button_state state = state_w;
ClutterEventType event_type;
event_type = clutter_event_type (event);
resource = pointer->focus_resource;
if (resource)
{
struct wl_client *client = wl_resource_get_client (resource);
struct wl_display *display = wl_client_get_display (client);
uint32_t button;
uint32_t serial;
button = clutter_event_get_button (event);
switch (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 = button + BTN_LEFT - 1;
break;
}
serial = wl_display_next_serial (display);
pointer->click_serial = serial;
wl_pointer_send_button (resource, serial, time, button, state_w);
wl_pointer_send_button (resource, serial,
clutter_event_get_time (event), button,
event_type == CLUTTER_BUTTON_PRESS ? 1 : 0);
}
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);
if (pointer->button_count == 0 && event_type == CLUTTER_BUTTON_RELEASE)
meta_wayland_pointer_set_focus (pointer, pointer->current);
}
static const MetaWaylandPointerGrabInterface default_pointer_grab_interface = {
@ -282,8 +311,7 @@ find_resource_for_surface (struct wl_list *list, MetaWaylandSurface *surface)
void
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface,
wl_fixed_t sx, wl_fixed_t sy)
MetaWaylandSurface *surface)
{
MetaWaylandSeat *seat = meta_wayland_pointer_get_seat (pointer);
MetaWaylandKeyboard *kbd = &seat->keyboard;
@ -306,7 +334,10 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
{
struct wl_client *client = wl_resource_get_client (resource);
struct wl_display *display = wl_client_get_display (client);
wl_fixed_t sx, sy;
serial = wl_display_next_serial (display);
if (kbd)
{
kr = find_resource_for_surface (&kbd->resource_list, surface);
@ -320,6 +351,8 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
kbd->modifier_state.group);
}
}
meta_wayland_pointer_get_relative_coordinates (pointer, surface, &sx, &sy);
wl_pointer_send_enter (resource, serial, surface->resource, sx, sy);
wl_resource_add_destroy_listener (resource, &pointer->focus_listener);
pointer->focus_serial = serial;
@ -327,8 +360,6 @@ meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
pointer->focus_resource = resource;
pointer->focus = surface;
pointer->default_grab.focus = surface;
wl_signal_emit (&pointer->focus_signal, pointer);
}
void
@ -342,8 +373,7 @@ meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
grab->pointer = pointer;
if (pointer->current)
interface->focus (pointer->grab, pointer->current,
pointer->current_x, pointer->current_y);
interface->focus (pointer->grab, pointer->current, NULL);
}
void
@ -353,8 +383,7 @@ meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer)
pointer->grab = &pointer->default_grab;
interface = pointer->grab->interface;
interface->focus (pointer->grab, pointer->current,
pointer->current_x, pointer->current_y);
interface->focus (pointer->grab, pointer->current, NULL);
}
static void
@ -386,24 +415,19 @@ meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
static void
modal_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
wl_fixed_t x,
wl_fixed_t y)
const ClutterEvent *event)
{
}
static void
modal_motion (MetaWaylandPointerGrab *grab,
uint32_t time,
wl_fixed_t x,
wl_fixed_t y)
const ClutterEvent *event)
{
}
static void
modal_button (MetaWaylandPointerGrab *grab,
uint32_t time,
uint32_t button,
uint32_t state)
const ClutterEvent *event)
{
}
@ -421,9 +445,7 @@ meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer)
if (pointer->grab != &pointer->default_grab)
return FALSE;
meta_wayland_pointer_set_focus (pointer, NULL,
wl_fixed_from_int (0),
wl_fixed_from_int (0));
meta_wayland_pointer_set_focus (pointer, NULL);
grab = g_slice_new0 (MetaWaylandPointerGrab);
grab->interface = &modal_grab;
@ -459,56 +481,61 @@ meta_wayland_pointer_destroy_focus (MetaWaylandPointer *pointer)
we have button down, and the clients would be confused if the
pointer enters the surface.
*/
meta_wayland_pointer_set_focus (pointer, NULL, 0, 0);
meta_wayland_pointer_set_focus (pointer, NULL);
}
}
typedef struct {
MetaWaylandPointerGrab generic;
MetaWaylandSurface *popup;
struct wl_listener popup_destroy_listener;
} MetaWaylandPopupGrab;
static void
popup_grab_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
wl_fixed_t x,
wl_fixed_t y)
const ClutterEvent *event)
{
MetaWaylandPopupGrab *popup_grab = (MetaWaylandPopupGrab*)grab;
/* Popup grabs are in owner-events mode (ie, events for the same client
are reported as normal) */
if (wl_resource_get_client (surface->resource) ==
wl_resource_get_client (grab->focus->resource))
default_grab_focus (grab, surface, x, y);
wl_resource_get_client (popup_grab->popup->resource))
default_grab_focus (grab, surface, event);
else
meta_wayland_pointer_set_focus (grab->pointer, NULL, 0, 0);
meta_wayland_pointer_set_focus (grab->pointer, NULL);
}
static void
popup_grab_motion (MetaWaylandPointerGrab *grab,
uint32_t time,
wl_fixed_t x,
wl_fixed_t y)
const ClutterEvent *event)
{
default_grab_motion (grab, time, x, y);
default_grab_motion (grab, event);
}
static void
popup_grab_button (MetaWaylandPointerGrab *grab,
uint32_t time,
uint32_t button,
uint32_t state)
const ClutterEvent *event)
{
MetaWaylandPopupGrab *popup_grab = (MetaWaylandPopupGrab*)grab;
MetaWaylandPointer *pointer = grab->pointer;
if (pointer->focus_resource)
{
/* This is ensured by popup_grab_focus */
g_assert (wl_resource_get_client (pointer->focus_resource) ==
wl_resource_get_client (grab->focus->resource));
wl_resource_get_client (popup_grab->popup->resource));
default_grab_button (grab, time, button, state);
default_grab_button (grab, event);
}
else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
else if (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE &&
pointer->button_count == 0)
meta_wayland_pointer_end_popup_grab (grab->pointer);
}
static MetaWaylandPointerGrabInterface popup_grab = {
static MetaWaylandPointerGrabInterface popup_grab_interface = {
popup_grab_focus,
popup_grab_motion,
popup_grab_button
@ -517,50 +544,75 @@ static MetaWaylandPointerGrabInterface popup_grab = {
static void
meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer)
{
MetaWaylandPointerGrab *grab;
MetaWaylandPopupGrab *popup_grab;
grab = pointer->grab;
popup_grab = (MetaWaylandPopupGrab*)pointer->grab;
g_assert (grab->interface == &popup_grab);
g_assert (popup_grab->generic.interface == &popup_grab_interface);
if (grab->focus)
if (popup_grab->popup)
{
wl_shell_surface_send_popup_done (grab->focus->shell_surface->resource);
wl_list_remove (&grab->focus_destroy_listener.link);
wl_shell_surface_send_popup_done (popup_grab->popup->shell_surface->resource);
wl_list_remove (&popup_grab->popup_destroy_listener.link);
}
meta_wayland_pointer_end_grab (pointer);
g_slice_free (MetaWaylandPointerGrab, grab);
g_slice_free (MetaWaylandPopupGrab, popup_grab);
}
static void
on_popup_surface_destroy (struct wl_listener *listener,
void *data)
{
MetaWaylandPointerGrab *grab =
wl_container_of (listener, grab, focus_destroy_listener);
MetaWaylandPopupGrab *grab =
wl_container_of (listener, grab, popup_destroy_listener);
grab->focus = NULL;
meta_wayland_pointer_end_popup_grab (grab->pointer);
grab->popup = NULL;
meta_wayland_pointer_end_popup_grab (grab->generic.pointer);
}
gboolean
meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface)
{
MetaWaylandPointerGrab *grab;
MetaWaylandPopupGrab *grab;
if (pointer->grab != &pointer->default_grab)
if (pointer->grab != &pointer->default_grab &&
pointer->grab->interface != &popup_grab_interface)
return FALSE;
grab = g_slice_new0 (MetaWaylandPointerGrab);
grab->interface = &popup_grab;
grab->pointer = pointer;
grab->focus = surface;
grab = g_slice_new0 (MetaWaylandPopupGrab);
grab->generic.interface = &popup_grab_interface;
grab->generic.pointer = pointer;
grab->popup = surface;
grab->focus_destroy_listener.notify = on_popup_surface_destroy;
wl_resource_add_destroy_listener (surface->resource, &grab->focus_destroy_listener);
grab->popup_destroy_listener.notify = on_popup_surface_destroy;
wl_resource_add_destroy_listener (surface->resource, &grab->popup_destroy_listener);
meta_wayland_pointer_start_grab (pointer, grab);
meta_wayland_pointer_start_grab (pointer, (MetaWaylandPointerGrab*)grab);
return TRUE;
}
void
meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface,
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 (pointer->x),
wl_fixed_to_double (pointer->y),
&xf, &yf);
}
*sx = wl_fixed_from_double (xf);
*sy = wl_fixed_from_double (yf);
}

View File

@ -28,22 +28,19 @@
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);
void (*focus) (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
const ClutterEvent *event);
void (*motion) (MetaWaylandPointerGrab *grab,
const ClutterEvent *event);
void (*button) (MetaWaylandPointerGrab *grab,
const ClutterEvent *event);
};
struct _MetaWaylandPointerGrab
{
const MetaWaylandPointerGrabInterface *interface;
MetaWaylandPointer *pointer;
MetaWaylandSurface *focus;
wl_fixed_t x, y;
struct wl_listener focus_destroy_listener;
};
struct _MetaWaylandPointer
@ -59,6 +56,7 @@ struct _MetaWaylandPointer
MetaWaylandPointerGrab *grab;
MetaWaylandPointerGrab default_grab;
wl_fixed_t grab_x, grab_y;
wl_fixed_t focus_x, focus_y;
guint32 grab_button;
guint32 grab_serial;
guint32 grab_time;
@ -80,10 +78,7 @@ meta_wayland_pointer_release (MetaWaylandPointer *pointer);
void
meta_wayland_pointer_set_focus (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface,
wl_fixed_t sx,
wl_fixed_t sy);
MetaWaylandSurface *surface);
void
meta_wayland_pointer_destroy_focus (MetaWaylandPointer *pointer);
@ -107,4 +102,10 @@ void
meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface);
void
meta_wayland_pointer_get_relative_coordinates (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface,
wl_fixed_t *x,
wl_fixed_t *y);
#endif /* __META_WAYLAND_POINTER_H__ */

View File

@ -47,31 +47,6 @@ 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)
{
@ -173,19 +148,7 @@ seat_get_pointer (struct wl_client *client,
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);
}
meta_wayland_pointer_set_focus (&seat->pointer, seat->pointer.focus);
}
static void
@ -209,8 +172,7 @@ seat_get_keyboard (struct wl_client *client,
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_keyboard_set_focus (&seat->keyboard, seat->keyboard.focus);
meta_wayland_data_device_set_keyboard_focus (seat);
}
}
@ -273,8 +235,7 @@ meta_wayland_seat_new (struct wl_display *display,
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);
wl_list_init (&seat->data_device_resource_list);
meta_wayland_pointer_init (&seat->pointer, is_native);
@ -295,7 +256,7 @@ meta_wayland_seat_new (struct wl_display *display,
}
static void
notify_motion (MetaWaylandSeat *seat,
notify_motion (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
MetaWaylandPointer *pointer = &seat->pointer;
@ -305,61 +266,40 @@ notify_motion (MetaWaylandSeat *seat,
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));
meta_wayland_seat_repick (seat, event);
pointer->grab->interface->motion (pointer->grab,
clutter_event_get_time (event),
pointer->grab->x,
pointer->grab->y);
pointer->grab->interface->motion (pointer->grab, event);
}
static void
handle_motion_event (MetaWaylandSeat *seat,
const ClutterMotionEvent *event)
handle_motion_event (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
notify_motion (seat, (const ClutterEvent *) event);
notify_motion (seat, event);
}
static void
handle_button_event (MetaWaylandSeat *seat,
const ClutterButtonEvent *event)
handle_button_event (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
MetaWaylandPointer *pointer = &seat->pointer;
gboolean state = event->type == CLUTTER_BUTTON_PRESS;
uint32_t button;
MetaWaylandSurface *surface;
notify_motion (seat, (const ClutterEvent *) event);
notify_motion (seat, 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;
}
/* FIXME: synth a XI2 event and handle in display.c */
if (state && pointer->button_count == 1)
{
MetaWaylandSurface *surface = pointer->current;
button = clutter_event_get_button (event);
pointer->grab_button = button;
pointer->grab_time = event->time;
pointer->grab_time = clutter_event_get_time (event);
pointer->grab_x = pointer->x;
pointer->grab_y = pointer->y;
if (button == BTN_LEFT &&
/* FIXME: synth a XI2 event and handle in display.c */
surface = pointer->current;
if (button == CLUTTER_BUTTON_PRIMARY &&
surface &&
surface->window &&
surface->window->client_type == META_WINDOW_CLIENT_TYPE_WAYLAND)
@ -368,22 +308,22 @@ handle_button_event (MetaWaylandSeat *seat,
}
}
pointer->grab->interface->button (pointer->grab, event->time, button, state);
pointer->grab->interface->button (pointer->grab, event);
if (pointer->button_count == 1)
pointer->grab_serial = wl_display_get_serial (seat->display);
}
static void
handle_scroll_event (MetaWaylandSeat *seat,
const ClutterScrollEvent *event)
handle_scroll_event (MetaWaylandSeat *seat,
const ClutterEvent *event)
{
enum wl_pointer_axis axis;
wl_fixed_t value;
notify_motion (seat, (const ClutterEvent *) event);
notify_motion (seat, event);
switch (event->direction)
switch (clutter_event_get_scroll_direction (event))
{
case CLUTTER_SCROLL_UP:
axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
@ -411,7 +351,7 @@ handle_scroll_event (MetaWaylandSeat *seat,
if (seat->pointer.focus_resource)
wl_pointer_send_axis (seat->pointer.focus_resource,
event->time,
clutter_event_get_time (event),
axis,
value);
}
@ -447,14 +387,12 @@ meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
switch (event->type)
{
case CLUTTER_MOTION:
handle_motion_event (seat,
(const ClutterMotionEvent *) event);
handle_motion_event (seat, event);
break;
case CLUTTER_BUTTON_PRESS:
case CLUTTER_BUTTON_RELEASE:
handle_button_event (seat,
(const ClutterButtonEvent *) event);
handle_button_event (seat, event);
break;
case CLUTTER_KEY_PRESS:
@ -463,7 +401,7 @@ meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
(const ClutterKeyEvent *) event);
case CLUTTER_SCROLL:
handle_scroll_event (seat, (const ClutterScrollEvent *) event);
handle_scroll_event (seat, event);
break;
default:
@ -493,14 +431,18 @@ update_pointer_position_for_actor (MetaWaylandPointer *pointer,
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)
meta_wayland_seat_repick (MetaWaylandSeat *seat,
const ClutterEvent *for_event)
{
ClutterActor *actor = NULL;
MetaWaylandPointer *pointer = &seat->pointer;
MetaWaylandSurface *surface = NULL;
if (actor == NULL && seat->current_stage)
if (for_event)
{
actor = clutter_event_get_source (for_event);
}
else if (seat->current_stage)
{
ClutterStage *stage = CLUTTER_STAGE (seat->current_stage);
actor = clutter_stage_get_actor_at_pos (stage,
@ -538,16 +480,8 @@ meta_wayland_seat_repick (MetaWaylandSeat *seat,
const MetaWaylandPointerGrabInterface *interface =
pointer->grab->interface;
interface->focus (pointer->grab,
surface,
pointer->current_x, pointer->current_y);
surface, for_event);
}
if (pointer->grab->focus)
transform_stage_point_fixed (pointer->grab->focus,
pointer->x,
pointer->y,
&pointer->grab->x,
&pointer->grab->y);
}
void

View File

@ -61,18 +61,7 @@ struct _MetaWaylandSeat
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;
struct wl_list data_device_resource_list;
MetaWaylandPointer pointer;
MetaWaylandKeyboard keyboard;
@ -95,9 +84,8 @@ meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
const ClutterEvent *event);
void
meta_wayland_seat_repick (MetaWaylandSeat *seat,
uint32_t time,
ClutterActor *actor);
meta_wayland_seat_repick (MetaWaylandSeat *seat,
const ClutterEvent *for_event);
void
meta_wayland_seat_update_sprite (MetaWaylandSeat *seat);

View File

@ -407,7 +407,6 @@ meta_wayland_surface_free (MetaWaylandSurface *surface)
meta_wayland_pointer_destroy_focus (&compositor->seat->pointer);
g_assert (surface != compositor->seat->pointer.focus);
g_assert (surface != compositor->seat->pointer.grab->focus);
}
if (compositor->implicit_grab_surface == surface)
@ -493,58 +492,118 @@ shell_surface_pong (struct wl_client *client,
{
}
typedef struct _MetaWaylandGrab
typedef struct
{
MetaWaylandPointerGrab grab;
MetaWaylandSurfaceExtension *shell_surface;
struct wl_listener shell_surface_destroy_listener;
MetaWaylandPointer *pointer;
} MetaWaylandGrab;
typedef struct _MetaWaylandMoveGrab
{
MetaWaylandGrab base;
wl_fixed_t dx, dy;
MetaWaylandPointerGrab generic;
MetaWaylandSurface *surface;
struct wl_listener surface_destroy_listener;
wl_fixed_t dx, dy;
} MetaWaylandMoveGrab;
static void
destroy_shell_surface_grab_listener (struct wl_listener *listener,
void *data)
end_move_grab (MetaWaylandMoveGrab *move_grab)
{
MetaWaylandGrab *grab = wl_container_of (listener, grab,
shell_surface_destroy_listener);
grab->shell_surface = NULL;
if (move_grab->surface)
{
move_grab->surface = NULL;
wl_list_remove (&move_grab->surface_destroy_listener.link);
}
/* XXX: Could we perhaps just stop the grab here so we don't have
* to consider grab->shell_surface becoming NULL in grab interface
* callbacks? */
meta_wayland_pointer_end_grab (move_grab->generic.pointer);
g_slice_free (MetaWaylandMoveGrab, move_grab);
}
typedef enum _GrabCursor
static void
move_grab_lose_surface (struct wl_listener *listener, void *data)
{
GRAB_CURSOR_MOVE,
} GrabCursor;
MetaWaylandMoveGrab *move_grab =
wl_container_of (listener, move_grab, surface_destroy_listener);
move_grab->surface = NULL;
end_move_grab (move_grab);
}
static void
grab_pointer (MetaWaylandGrab *grab,
const MetaWaylandPointerGrabInterface *interface,
MetaWaylandSurfaceExtension *shell_surface,
MetaWaylandPointer *pointer,
GrabCursor cursor)
move_grab_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
const ClutterEvent *event)
{
/* TODO: popup_grab_end (pointer); */
}
grab->grab.interface = interface;
grab->shell_surface = shell_surface;
grab->shell_surface_destroy_listener.notify =
destroy_shell_surface_grab_listener;
wl_resource_add_destroy_listener (shell_surface->resource,
&grab->shell_surface_destroy_listener);
static void
move_grab_motion (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
MetaWaylandMoveGrab *move_grab = (MetaWaylandMoveGrab *)grab;
MetaWaylandPointer *pointer = grab->pointer;
grab->pointer = pointer;
grab->grab.focus = shell_surface->surface;
meta_window_move (move_grab->surface->window,
TRUE,
wl_fixed_to_int (pointer->x + move_grab->dx),
wl_fixed_to_int (pointer->y + move_grab->dy));
}
meta_wayland_pointer_start_grab (pointer, &grab->grab);
static void
move_grab_button (MetaWaylandPointerGrab *grab,
const ClutterEvent *event)
{
MetaWaylandMoveGrab *move_grab = (MetaWaylandMoveGrab *)grab;
MetaWaylandPointer *pointer = grab->pointer;
if (pointer->button_count == 0 &&
clutter_event_type (event) == CLUTTER_BUTTON_RELEASE)
end_move_grab (move_grab);
}
static const MetaWaylandPointerGrabInterface move_grab_interface = {
move_grab_focus,
move_grab_motion,
move_grab_button,
};
static void
shell_surface_move (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *seat_resource,
guint32 serial)
{
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
MetaWindow *window;
MetaWaylandMoveGrab *move_grab;
MetaRectangle rect;
if (seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
seat->pointer.focus != shell_surface->surface)
return;
window = shell_surface->surface->window;
if (!window)
return;
/* small hack, this should be handled by window->shaken_loose when we
move everything to display.c */
if (window->fullscreen)
meta_window_unmake_fullscreen (window);
move_grab = g_slice_new (MetaWaylandMoveGrab);
meta_window_get_input_rect (shell_surface->surface->window,
&rect);
move_grab->generic.interface = &move_grab_interface;
move_grab->generic.pointer = &seat->pointer;
move_grab->surface = shell_surface->surface;
move_grab->surface_destroy_listener.notify = move_grab_lose_surface;
wl_resource_add_destroy_listener (shell_surface->surface->resource,
&move_grab->surface_destroy_listener);
move_grab->dx = wl_fixed_from_int (rect.x) - seat->pointer.grab_x;
move_grab->dy = wl_fixed_from_int (rect.y) - seat->pointer.grab_y;
meta_wayland_pointer_start_grab (&seat->pointer, (MetaWaylandPointerGrab*)move_grab);
/* TODO: send_grab_cursor (cursor); */
@ -557,112 +616,7 @@ grab_pointer (MetaWaylandGrab *grab,
* XXX: For now we just focus the surface directly associated with
* the grab.
*/
meta_wayland_pointer_set_focus (pointer,
grab->shell_surface->surface,
wl_fixed_from_int (0),
wl_fixed_from_int (0));
}
static void
release_pointer (MetaWaylandGrab *grab)
{
if (grab->shell_surface)
wl_list_remove (&grab->shell_surface_destroy_listener.link);
meta_wayland_pointer_end_grab (grab->pointer);
}
static void
noop_grab_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
wl_fixed_t x,
wl_fixed_t y)
{
grab->focus = NULL;
}
static void
move_grab_motion (MetaWaylandPointerGrab *grab,
uint32_t time,
wl_fixed_t x,
wl_fixed_t y)
{
MetaWaylandMoveGrab *move = (MetaWaylandMoveGrab *)grab;
MetaWaylandPointer *pointer = move->base.pointer;
MetaWaylandSurfaceExtension *shell_surface = move->base.shell_surface;
if (!shell_surface)
return;
meta_window_move (shell_surface->surface->window,
TRUE,
wl_fixed_to_int (pointer->x + move->dx),
wl_fixed_to_int (pointer->y + move->dy));
}
static void
move_grab_button (MetaWaylandPointerGrab *pointer_grab,
uint32_t time,
uint32_t button,
uint32_t state_w)
{
MetaWaylandGrab *grab =
wl_container_of (pointer_grab, grab, grab);
MetaWaylandMoveGrab *move = (MetaWaylandMoveGrab *)grab;
MetaWaylandPointer *pointer = grab->pointer;
enum wl_pointer_button_state state = state_w;
if (pointer->button_count == 0 && state == WL_POINTER_BUTTON_STATE_RELEASED)
{
release_pointer (grab);
g_slice_free (MetaWaylandMoveGrab, move);
}
}
static const MetaWaylandPointerGrabInterface move_grab_interface = {
noop_grab_focus,
move_grab_motion,
move_grab_button,
};
static void
start_surface_move (MetaWaylandSurfaceExtension *shell_surface,
MetaWaylandSeat *seat)
{
MetaWaylandMoveGrab *move;
MetaRectangle rect;
g_return_if_fail (shell_surface != NULL);
/* TODO: check if the surface is fullscreen when we support fullscreen */
move = g_slice_new (MetaWaylandMoveGrab);
meta_window_get_input_rect (shell_surface->surface->window,
&rect);
move->dx = wl_fixed_from_int (rect.x) - seat->pointer.grab_x;
move->dy = wl_fixed_from_int (rect.y) - seat->pointer.grab_y;
grab_pointer (&move->base, &move_grab_interface, shell_surface,
&seat->pointer, GRAB_CURSOR_MOVE);
}
static void
shell_surface_move (struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *seat_resource,
guint32 serial)
{
MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
if (seat->pointer.button_count == 0 ||
seat->pointer.grab_serial != serial ||
seat->pointer.focus != shell_surface->surface)
return;
start_surface_move (shell_surface, seat);
meta_wayland_pointer_set_focus (&seat->pointer, shell_surface->surface);
}
static void

View File

@ -219,9 +219,7 @@ meta_wayland_compositor_set_input_focus (MetaWaylandCompositor *compositor,
void
meta_wayland_compositor_repick (MetaWaylandCompositor *compositor)
{
meta_wayland_seat_repick (compositor->seat,
get_time (),
NULL);
meta_wayland_seat_repick (compositor->seat, NULL);
}
static void