wayland: implement support for plugin modality

Calling XIGrabDevice has no effect under wayland, because the
xserver is getting events from us. Instead, we need to use our
own interfaces for grabs.
At the same time, we can simplify the public API, as plugins
should always listen for events using clutter.

https://bugzilla.gnome.org/show_bug.cgi?id=705917
This commit is contained in:
Giovanni Campagna 2013-08-13 16:51:33 +02:00
parent 59b274f12f
commit 7eb4bfbea3
5 changed files with 291 additions and 44 deletions

View File

@ -85,6 +85,8 @@
#include "window-private.h" /* to check window->hidden */ #include "window-private.h" /* to check window->hidden */
#include "display-private.h" /* for meta_display_lookup_x_window() */ #include "display-private.h" /* for meta_display_lookup_x_window() */
#include "meta-wayland-private.h" #include "meta-wayland-private.h"
#include "meta-wayland-pointer.h"
#include "meta-wayland-keyboard.h"
#include <X11/extensions/shape.h> #include <X11/extensions/shape.h>
#include <X11/extensions/Xcomposite.h> #include <X11/extensions/Xcomposite.h>
@ -424,34 +426,20 @@ meta_stage_is_focused (MetaScreen *screen)
return (screen->display->focus_type == META_FOCUS_STAGE); return (screen->display->focus_type == META_FOCUS_STAGE);
} }
gboolean static gboolean
meta_begin_modal_for_plugin (MetaScreen *screen, begin_modal_x11 (MetaScreen *screen,
MetaPlugin *plugin, MetaPlugin *plugin,
MetaModalOptions options, MetaModalOptions options,
guint32 timestamp) guint32 timestamp)
{ {
/* To some extent this duplicates code in meta_display_begin_grab_op(), but there MetaDisplay *display = meta_screen_get_display (screen);
* are significant differences in how we handle grabs that make it difficult to Display *xdpy = meta_display_get_xdisplay (display);
* merge the two. MetaCompScreen *info = meta_screen_get_compositor_data (screen);
*/ Window grab_window = clutter_x11_get_stage_window (CLUTTER_STAGE (info->stage));
MetaDisplay *display = meta_screen_get_display (screen); Cursor cursor = None;
Display *xdpy = meta_display_get_xdisplay (display); int result;
MetaCompositor *compositor = display->compositor; gboolean pointer_grabbed = FALSE;
ClutterStage *stage; gboolean keyboard_grabbed = FALSE;
Window grab_window;
Cursor cursor = None;
gboolean pointer_grabbed = FALSE;
gboolean keyboard_grabbed = FALSE;
int result;
stage = CLUTTER_STAGE (meta_get_stage_for_screen (screen));
if (!stage)
return FALSE;
grab_window = clutter_x11_get_stage_window (stage);
if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
return FALSE;
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0) if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
{ {
@ -501,14 +489,6 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
keyboard_grabbed = TRUE; keyboard_grabbed = TRUE;
} }
display->grab_op = META_GRAB_OP_COMPOSITOR;
display->grab_window = NULL;
display->grab_screen = screen;
display->grab_have_pointer = TRUE;
display->grab_have_keyboard = TRUE;
compositor->modal_plugin = plugin;
return TRUE; return TRUE;
fail: fail:
@ -520,6 +500,80 @@ meta_begin_modal_for_plugin (MetaScreen *screen,
return FALSE; return FALSE;
} }
static gboolean
begin_modal_wayland (MetaScreen *screen,
MetaPlugin *plugin,
MetaModalOptions options,
guint32 timestamp)
{
MetaWaylandCompositor *compositor;
gboolean pointer_grabbed = FALSE;
gboolean keyboard_grabbed = FALSE;
compositor = meta_wayland_compositor_get_default ();
if ((options & META_MODAL_POINTER_ALREADY_GRABBED) == 0)
{
if (!meta_wayland_pointer_begin_modal (&compositor->seat->pointer))
goto fail;
pointer_grabbed = TRUE;
}
if ((options & META_MODAL_KEYBOARD_ALREADY_GRABBED) == 0)
{
if (!meta_wayland_keyboard_begin_modal (&compositor->seat->keyboard,
timestamp))
goto fail;
keyboard_grabbed = TRUE;
}
return TRUE;
fail:
if (pointer_grabbed)
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
if (keyboard_grabbed)
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard, timestamp);
return FALSE;
}
gboolean
meta_begin_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin,
MetaModalOptions options,
guint32 timestamp)
{
/* To some extent this duplicates code in meta_display_begin_grab_op(), but there
* are significant differences in how we handle grabs that make it difficult to
* merge the two.
*/
MetaDisplay *display = meta_screen_get_display (screen);
MetaCompositor *compositor = display->compositor;
gboolean ok;
if (compositor->modal_plugin != NULL || display->grab_op != META_GRAB_OP_NONE)
return FALSE;
if (meta_is_wayland_compositor ())
ok = begin_modal_wayland (screen, plugin, options, timestamp);
else
ok = begin_modal_x11 (screen, plugin, options, timestamp);
if (!ok)
return FALSE;
display->grab_op = META_GRAB_OP_COMPOSITOR;
display->grab_window = NULL;
display->grab_screen = screen;
display->grab_have_pointer = TRUE;
display->grab_have_keyboard = TRUE;
compositor->modal_plugin = plugin;
return TRUE;
}
void void
meta_end_modal_for_plugin (MetaScreen *screen, meta_end_modal_for_plugin (MetaScreen *screen,
MetaPlugin *plugin, MetaPlugin *plugin,
@ -531,8 +585,19 @@ meta_end_modal_for_plugin (MetaScreen *screen,
g_return_if_fail (compositor->modal_plugin == plugin); g_return_if_fail (compositor->modal_plugin == plugin);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp); if (meta_is_wayland_compositor ())
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp); {
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
meta_wayland_pointer_end_modal (&compositor->seat->pointer);
meta_wayland_keyboard_end_modal (&compositor->seat->keyboard,
timestamp);
}
else
{
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_POINTER_ID, timestamp);
XIUngrabDevice (xdpy, META_VIRTUAL_CORE_KEYBOARD_ID, timestamp);
}
display->grab_op = META_GRAB_OP_NONE; display->grab_op = META_GRAB_OP_NONE;
display->grab_window = NULL; display->grab_window = NULL;

View File

@ -274,6 +274,29 @@ static const MetaWaylandKeyboardGrabInterface
default_grab_modifiers, default_grab_modifiers,
}; };
static void
modal_key (MetaWaylandKeyboardGrab *grab,
uint32_t time,
uint32_t key,
uint32_t state)
{
}
static void
modal_modifiers (MetaWaylandKeyboardGrab *grab,
uint32_t serial,
uint32_t mods_depressed,
uint32_t mods_latched,
uint32_t mods_locked,
uint32_t group)
{
}
static MetaWaylandKeyboardGrabInterface modal_grab = {
modal_key,
modal_modifiers,
};
gboolean gboolean
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard, meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
struct wl_display *display, struct wl_display *display,
@ -515,13 +538,29 @@ meta_wayland_keyboard_set_focus (MetaWaylandKeyboard *keyboard,
display = wl_client_get_display (client); display = wl_client_get_display (client);
serial = wl_display_next_serial (display); serial = wl_display_next_serial (display);
wl_keyboard_send_modifiers (resource, serial,
keyboard->modifier_state.mods_depressed, /* If we're in a modal grab, the client is focused but doesn't see
keyboard->modifier_state.mods_latched, modifiers or pressed keys (and fix that up when we exit the modal) */
keyboard->modifier_state.mods_locked, if (keyboard->grab->interface == &modal_grab)
keyboard->modifier_state.group); {
wl_keyboard_send_enter (resource, serial, surface->resource, struct wl_array empty;
&keyboard->keys); wl_array_init (&empty);
wl_keyboard_send_modifiers (resource, serial,
0, 0, 0, 0);
wl_keyboard_send_enter (resource, serial, surface->resource,
&empty);
}
else
{
wl_keyboard_send_modifiers (resource, serial,
keyboard->modifier_state.mods_depressed,
keyboard->modifier_state.mods_latched,
keyboard->modifier_state.mods_locked,
keyboard->modifier_state.group);
wl_keyboard_send_enter (resource, serial, surface->resource,
&keyboard->keys);
}
wl_resource_add_destroy_listener (resource, &keyboard->focus_listener); wl_resource_add_destroy_listener (resource, &keyboard->focus_listener);
keyboard->focus_serial = serial; keyboard->focus_serial = serial;
} }
@ -565,3 +604,72 @@ meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard)
wl_list_remove (&keyboard->focus_listener.link); wl_list_remove (&keyboard->focus_listener.link);
wl_array_release (&keyboard->keys); wl_array_release (&keyboard->keys);
} }
gboolean
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
guint32 timestamp)
{
MetaWaylandKeyboardGrab *grab;
uint32_t *end = (void *) ((char *) keyboard->keys.data +
keyboard->keys.size);
uint32_t *k;
uint32_t serial;
if (keyboard->grab != &keyboard->default_grab)
return FALSE;
if (keyboard->focus)
{
/* Fake key release events for the focused app */
serial = wl_display_next_serial (keyboard->display);
keyboard->grab->interface->modifiers (keyboard->grab,
serial,
0, 0, 0, 0);
for (k = keyboard->keys.data; k < end; k++)
keyboard->grab->interface->key (keyboard->grab,
timestamp,
*k, 0);
}
grab = g_slice_new0 (MetaWaylandKeyboardGrab);
grab->interface = &modal_grab;
meta_wayland_keyboard_start_grab (keyboard, grab);
return TRUE;
}
void
meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
guint32 timestamp)
{
MetaWaylandKeyboardGrab *grab;
uint32_t *end = (void *) ((char *) keyboard->keys.data +
keyboard->keys.size);
uint32_t *k;
uint32_t serial;
grab = keyboard->grab;
g_assert (grab->interface == &modal_grab);
meta_wayland_keyboard_end_grab (keyboard);
g_slice_free (MetaWaylandKeyboardGrab, grab);
if (keyboard->focus)
{
/* Fake key press events for the focused app */
serial = wl_display_next_serial (keyboard->display);
keyboard->grab->interface->modifiers (keyboard->grab,
serial,
keyboard->modifier_state.mods_depressed,
keyboard->modifier_state.mods_latched,
keyboard->modifier_state.mods_locked,
keyboard->modifier_state.group);
for (k = keyboard->keys.data; k < end; k++)
keyboard->grab->interface->key (keyboard->grab,
timestamp,
*k, 1);
}
}

View File

@ -70,6 +70,13 @@ meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *device,
void void
meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard); meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard);
gboolean
meta_wayland_keyboard_begin_modal (MetaWaylandKeyboard *keyboard,
guint32 timestamp);
void
meta_wayland_keyboard_end_modal (MetaWaylandKeyboard *keyboard,
guint32 timestamp);
void void
meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard); meta_wayland_keyboard_release (MetaWaylandKeyboard *keyboard);

View File

@ -262,3 +262,65 @@ meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
&pointer->current_listener); &pointer->current_listener);
pointer->current_listener.notify = current_surface_destroy; pointer->current_listener.notify = current_surface_destroy;
} }
static void
modal_focus (MetaWaylandPointerGrab *grab,
MetaWaylandSurface *surface,
wl_fixed_t x,
wl_fixed_t y)
{
}
static void
modal_motion (MetaWaylandPointerGrab *grab,
uint32_t time,
wl_fixed_t x,
wl_fixed_t y)
{
}
static void
modal_button (MetaWaylandPointerGrab *grab,
uint32_t time,
uint32_t button,
uint32_t state)
{
}
static MetaWaylandPointerGrabInterface modal_grab = {
modal_focus,
modal_motion,
modal_button
};
gboolean
meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer)
{
MetaWaylandPointerGrab *grab;
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));
grab = g_slice_new0 (MetaWaylandPointerGrab);
grab->interface = &modal_grab;
meta_wayland_pointer_start_grab (pointer, grab);
return TRUE;
}
void
meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer)
{
MetaWaylandPointerGrab *grab;
grab = pointer->grab;
g_assert (grab->interface == &modal_grab);
meta_wayland_pointer_end_grab (pointer);
g_slice_free (MetaWaylandPointerGrab, grab);
}

View File

@ -42,6 +42,11 @@ meta_wayland_pointer_start_grab (MetaWaylandPointer *pointer,
void void
meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer); meta_wayland_pointer_end_grab (MetaWaylandPointer *pointer);
gboolean
meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer);
void
meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer);
void void
meta_wayland_pointer_set_current (MetaWaylandPointer *pointer, meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
MetaWaylandSurface *surface); MetaWaylandSurface *surface);