wayland: implement support for popup surfaces
Popup surfaces are mapped into override_redirect surfaces of a DROPDOWN_MENU type, with the addition of a special pointer grab. https://bugzilla.gnome.org/show_bug.cgi?id=707863
This commit is contained in:
parent
81d9797544
commit
76e2455d1b
@ -678,7 +678,9 @@ void meta_window_update_layer (MetaWindow *window);
|
|||||||
|
|
||||||
void meta_window_recalc_features (MetaWindow *window);
|
void meta_window_recalc_features (MetaWindow *window);
|
||||||
|
|
||||||
|
/* recalc_window_type is x11 only, wayland does its thing and then calls type_changed */
|
||||||
void meta_window_recalc_window_type (MetaWindow *window);
|
void meta_window_recalc_window_type (MetaWindow *window);
|
||||||
|
void meta_window_type_changed (MetaWindow *window);
|
||||||
|
|
||||||
void meta_window_stack_just_below (MetaWindow *window,
|
void meta_window_stack_just_below (MetaWindow *window,
|
||||||
MetaWindow *below_this_one);
|
MetaWindow *below_this_one);
|
||||||
|
@ -1049,16 +1049,6 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
|
|
||||||
if (client_type == META_WINDOW_CLIENT_TYPE_X11)
|
if (client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||||
{
|
{
|
||||||
if (window->override_redirect)
|
|
||||||
{
|
|
||||||
window->decorated = FALSE;
|
|
||||||
window->always_sticky = TRUE;
|
|
||||||
window->has_close_func = FALSE;
|
|
||||||
window->has_shade_func = FALSE;
|
|
||||||
window->has_move_func = FALSE;
|
|
||||||
window->has_resize_func = FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
meta_display_register_x_window (display, &window->xwindow, window);
|
meta_display_register_x_window (display, &window->xwindow, window);
|
||||||
meta_window_update_shape_region_x11 (window);
|
meta_window_update_shape_region_x11 (window);
|
||||||
meta_window_update_input_region_x11 (window);
|
meta_window_update_input_region_x11 (window);
|
||||||
@ -1077,6 +1067,16 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
else
|
else
|
||||||
meta_wayland_surface_set_initial_state (window->surface, window);
|
meta_wayland_surface_set_initial_state (window->surface, window);
|
||||||
|
|
||||||
|
if (window->override_redirect)
|
||||||
|
{
|
||||||
|
window->decorated = FALSE;
|
||||||
|
window->always_sticky = TRUE;
|
||||||
|
window->has_close_func = FALSE;
|
||||||
|
window->has_shade_func = FALSE;
|
||||||
|
window->has_move_func = FALSE;
|
||||||
|
window->has_resize_func = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
if (!window->override_redirect &&
|
if (!window->override_redirect &&
|
||||||
client_type == META_WINDOW_CLIENT_TYPE_X11)
|
client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||||
{
|
{
|
||||||
@ -1085,6 +1085,7 @@ meta_window_new_shared (MetaDisplay *display,
|
|||||||
meta_window_update_role (window);
|
meta_window_update_role (window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||||
meta_window_update_net_wm_type (window);
|
meta_window_update_net_wm_type (window);
|
||||||
|
|
||||||
if (!window->override_redirect)
|
if (!window->override_redirect)
|
||||||
@ -8549,7 +8550,12 @@ recalc_window_type (MetaWindow *window)
|
|||||||
window->type, window->desc, old_type);
|
window->type, window->desc, old_type);
|
||||||
|
|
||||||
if (old_type != window->type)
|
if (old_type != window->type)
|
||||||
{
|
meta_window_type_changed (window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
meta_window_type_changed (MetaWindow *window)
|
||||||
|
{
|
||||||
gboolean old_decorated = window->decorated;
|
gboolean old_decorated = window->decorated;
|
||||||
GObject *object = G_OBJECT (window);
|
GObject *object = G_OBJECT (window);
|
||||||
|
|
||||||
@ -8578,7 +8584,6 @@ recalc_window_type (MetaWindow *window)
|
|||||||
g_object_notify (object, "window-type");
|
g_object_notify (object, "window-type");
|
||||||
|
|
||||||
g_object_thaw_notify (object);
|
g_object_thaw_notify (object);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -8676,7 +8681,10 @@ recalc_window_features (MetaWindow *window)
|
|||||||
old_always_sticky = window->always_sticky;
|
old_always_sticky = window->always_sticky;
|
||||||
|
|
||||||
/* Use MWM hints initially */
|
/* Use MWM hints initially */
|
||||||
|
if (window->client_type == META_WINDOW_CLIENT_TYPE_X11)
|
||||||
window->decorated = window->mwm_decorated;
|
window->decorated = window->mwm_decorated;
|
||||||
|
else
|
||||||
|
window->decorated = FALSE;
|
||||||
window->border_only = window->mwm_border_only;
|
window->border_only = window->mwm_border_only;
|
||||||
window->has_close_func = window->mwm_has_close_func;
|
window->has_close_func = window->mwm_has_close_func;
|
||||||
window->has_minimize_func = window->mwm_has_minimize_func;
|
window->has_minimize_func = window->mwm_has_minimize_func;
|
||||||
|
@ -51,6 +51,8 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
static void meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer);
|
||||||
|
|
||||||
static MetaWaylandSeat *
|
static MetaWaylandSeat *
|
||||||
meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer)
|
meta_wayland_pointer_get_seat (MetaWaylandPointer *pointer)
|
||||||
{
|
{
|
||||||
@ -109,6 +111,7 @@ default_grab_button (MetaWaylandPointerGrab *grab,
|
|||||||
struct wl_client *client = wl_resource_get_client (resource);
|
struct wl_client *client = wl_resource_get_client (resource);
|
||||||
struct wl_display *display = wl_client_get_display (client);
|
struct wl_display *display = wl_client_get_display (client);
|
||||||
serial = wl_display_next_serial (display);
|
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, time, button, state_w);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -459,3 +462,105 @@ meta_wayland_pointer_destroy_focus (MetaWaylandPointer *pointer)
|
|||||||
meta_wayland_pointer_set_focus (pointer, NULL, 0, 0);
|
meta_wayland_pointer_set_focus (pointer, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
popup_grab_focus (MetaWaylandPointerGrab *grab,
|
||||||
|
MetaWaylandSurface *surface,
|
||||||
|
wl_fixed_t x,
|
||||||
|
wl_fixed_t y)
|
||||||
|
{
|
||||||
|
/* 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);
|
||||||
|
else
|
||||||
|
meta_wayland_pointer_set_focus (grab->pointer, NULL, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
popup_grab_motion (MetaWaylandPointerGrab *grab,
|
||||||
|
uint32_t time,
|
||||||
|
wl_fixed_t x,
|
||||||
|
wl_fixed_t y)
|
||||||
|
{
|
||||||
|
default_grab_motion (grab, time, x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
popup_grab_button (MetaWaylandPointerGrab *grab,
|
||||||
|
uint32_t time,
|
||||||
|
uint32_t button,
|
||||||
|
uint32_t state)
|
||||||
|
{
|
||||||
|
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));
|
||||||
|
|
||||||
|
default_grab_button (grab, time, button, state);
|
||||||
|
}
|
||||||
|
else if (state == WL_POINTER_BUTTON_STATE_RELEASED &&
|
||||||
|
pointer->button_count == 0)
|
||||||
|
meta_wayland_pointer_end_popup_grab (grab->pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MetaWaylandPointerGrabInterface popup_grab = {
|
||||||
|
popup_grab_focus,
|
||||||
|
popup_grab_motion,
|
||||||
|
popup_grab_button
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerGrab *grab;
|
||||||
|
|
||||||
|
grab = pointer->grab;
|
||||||
|
|
||||||
|
g_assert (grab->interface == &popup_grab);
|
||||||
|
|
||||||
|
if (grab->focus)
|
||||||
|
{
|
||||||
|
wl_shell_surface_send_popup_done (grab->focus->shell_surface->resource);
|
||||||
|
wl_list_remove (&grab->focus_destroy_listener.link);
|
||||||
|
}
|
||||||
|
|
||||||
|
meta_wayland_pointer_end_grab (pointer);
|
||||||
|
g_slice_free (MetaWaylandPointerGrab, grab);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_popup_surface_destroy (struct wl_listener *listener,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerGrab *grab =
|
||||||
|
wl_container_of (listener, grab, focus_destroy_listener);
|
||||||
|
|
||||||
|
grab->focus = NULL;
|
||||||
|
meta_wayland_pointer_end_popup_grab (grab->pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
|
||||||
|
MetaWaylandSurface *surface)
|
||||||
|
{
|
||||||
|
MetaWaylandPointerGrab *grab;
|
||||||
|
|
||||||
|
if (pointer->grab != &pointer->default_grab)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
grab = g_slice_new0 (MetaWaylandPointerGrab);
|
||||||
|
grab->interface = &popup_grab;
|
||||||
|
grab->pointer = pointer;
|
||||||
|
grab->focus = surface;
|
||||||
|
|
||||||
|
grab->focus_destroy_listener.notify = on_popup_surface_destroy;
|
||||||
|
wl_resource_add_destroy_listener (surface->resource, &grab->focus_destroy_listener);
|
||||||
|
|
||||||
|
meta_wayland_pointer_start_grab (pointer, grab);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
@ -42,6 +42,8 @@ struct _MetaWaylandPointerGrab
|
|||||||
MetaWaylandPointer *pointer;
|
MetaWaylandPointer *pointer;
|
||||||
MetaWaylandSurface *focus;
|
MetaWaylandSurface *focus;
|
||||||
wl_fixed_t x, y;
|
wl_fixed_t x, y;
|
||||||
|
|
||||||
|
struct wl_listener focus_destroy_listener;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MetaWaylandPointer
|
struct _MetaWaylandPointer
|
||||||
@ -51,6 +53,7 @@ struct _MetaWaylandPointer
|
|||||||
struct wl_resource *focus_resource;
|
struct wl_resource *focus_resource;
|
||||||
struct wl_listener focus_listener;
|
struct wl_listener focus_listener;
|
||||||
guint32 focus_serial;
|
guint32 focus_serial;
|
||||||
|
guint32 click_serial;
|
||||||
struct wl_signal focus_signal;
|
struct wl_signal focus_signal;
|
||||||
|
|
||||||
MetaWaylandPointerGrab *grab;
|
MetaWaylandPointerGrab *grab;
|
||||||
@ -96,6 +99,10 @@ meta_wayland_pointer_begin_modal (MetaWaylandPointer *pointer);
|
|||||||
void
|
void
|
||||||
meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer);
|
meta_wayland_pointer_end_modal (MetaWaylandPointer *pointer);
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
|
||||||
|
MetaWaylandSurface *popup);
|
||||||
|
|
||||||
void
|
void
|
||||||
meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
|
meta_wayland_pointer_set_current (MetaWaylandPointer *pointer,
|
||||||
MetaWaylandSurface *surface);
|
MetaWaylandSurface *surface);
|
||||||
|
@ -758,13 +758,38 @@ shell_surface_set_fullscreen (struct wl_client *client,
|
|||||||
static void
|
static void
|
||||||
shell_surface_set_popup (struct wl_client *client,
|
shell_surface_set_popup (struct wl_client *client,
|
||||||
struct wl_resource *resource,
|
struct wl_resource *resource,
|
||||||
struct wl_resource *seat,
|
struct wl_resource *seat_resource,
|
||||||
guint32 serial,
|
guint32 serial,
|
||||||
struct wl_resource *parent,
|
struct wl_resource *parent,
|
||||||
gint32 x,
|
gint32 x,
|
||||||
gint32 y,
|
gint32 y,
|
||||||
guint32 flags)
|
guint32 flags)
|
||||||
{
|
{
|
||||||
|
MetaWaylandSurfaceExtension *shell_surface = wl_resource_get_user_data (resource);
|
||||||
|
MetaWaylandSurface *surface = shell_surface->surface;
|
||||||
|
MetaWaylandCompositor *compositor = surface->compositor;
|
||||||
|
MetaWaylandSeat *seat = compositor->seat;
|
||||||
|
|
||||||
|
if (serial < seat->pointer.click_serial)
|
||||||
|
{
|
||||||
|
/* stale request */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (surface->window)
|
||||||
|
{
|
||||||
|
meta_warning ("Client set_popup() on an already visible window, this is not supported\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ensure_initial_state (surface);
|
||||||
|
|
||||||
|
surface->initial_state->initial_type = META_WAYLAND_SURFACE_POPUP;
|
||||||
|
surface->initial_state->transient_for = parent;
|
||||||
|
surface->initial_state->x = x;
|
||||||
|
surface->initial_state->y = y;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1060,10 +1085,14 @@ meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
|
|||||||
MetaWindow *window)
|
MetaWindow *window)
|
||||||
{
|
{
|
||||||
MetaWaylandSurfaceInitialState *initial = surface->initial_state;
|
MetaWaylandSurfaceInitialState *initial = surface->initial_state;
|
||||||
|
MetaWaylandCompositor *compositor = surface->compositor;
|
||||||
|
MetaWaylandSeat *seat = compositor->seat;
|
||||||
|
|
||||||
if (initial == NULL)
|
if (initial == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
window->type = META_WINDOW_NORMAL;
|
||||||
|
|
||||||
/* Note that we poke at the bits directly here, because we're
|
/* Note that we poke at the bits directly here, because we're
|
||||||
in the middle of meta_window_new_shared() */
|
in the middle of meta_window_new_shared() */
|
||||||
switch (initial->initial_type)
|
switch (initial->initial_type)
|
||||||
@ -1076,6 +1105,15 @@ meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
|
|||||||
case META_WAYLAND_SURFACE_MAXIMIZED:
|
case META_WAYLAND_SURFACE_MAXIMIZED:
|
||||||
window->maximized_horizontally = window->maximized_vertically = TRUE;
|
window->maximized_horizontally = window->maximized_vertically = TRUE;
|
||||||
break;
|
break;
|
||||||
|
case META_WAYLAND_SURFACE_POPUP:
|
||||||
|
window->override_redirect = TRUE;
|
||||||
|
window->type = META_WINDOW_DROPDOWN_MENU;
|
||||||
|
window->mapped = TRUE;
|
||||||
|
window->showing_for_first_time = FALSE;
|
||||||
|
window->placed = TRUE;
|
||||||
|
if (!meta_wayland_pointer_start_popup_grab (&seat->pointer, surface))
|
||||||
|
wl_shell_surface_send_popup_done (surface->shell_surface->resource);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
}
|
}
|
||||||
@ -1083,8 +1121,18 @@ meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
|
|||||||
if (initial->transient_for)
|
if (initial->transient_for)
|
||||||
{
|
{
|
||||||
MetaWaylandSurface *parent = wl_resource_get_user_data (initial->transient_for);
|
MetaWaylandSurface *parent = wl_resource_get_user_data (initial->transient_for);
|
||||||
if (parent)
|
if (parent && parent->window)
|
||||||
|
{
|
||||||
window->transient_for = g_object_ref (parent->window);
|
window->transient_for = g_object_ref (parent->window);
|
||||||
|
|
||||||
|
if (initial->initial_type == META_WAYLAND_SURFACE_POPUP)
|
||||||
|
{
|
||||||
|
window->rect.x = parent->window->rect.x + initial->x;
|
||||||
|
window->rect.y = parent->window->rect.y + initial->y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window->type = META_WINDOW_DIALOG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (initial->title)
|
if (initial->title)
|
||||||
@ -1101,6 +1149,8 @@ meta_wayland_surface_set_initial_state (MetaWaylandSurface *surface,
|
|||||||
initial->gtk_application_object_path,
|
initial->gtk_application_object_path,
|
||||||
initial->gtk_window_object_path);
|
initial->gtk_window_object_path);
|
||||||
|
|
||||||
|
meta_window_type_changed (window);
|
||||||
|
|
||||||
free_initial_state (initial);
|
free_initial_state (initial);
|
||||||
surface->initial_state = NULL;
|
surface->initial_state = NULL;
|
||||||
}
|
}
|
||||||
|
@ -69,13 +69,15 @@ typedef struct
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
META_WAYLAND_SURFACE_TOPLEVEL = 0,
|
META_WAYLAND_SURFACE_TOPLEVEL = 0,
|
||||||
META_WAYLAND_SURFACE_MAXIMIZED,
|
META_WAYLAND_SURFACE_MAXIMIZED,
|
||||||
META_WAYLAND_SURFACE_FULLSCREEN
|
META_WAYLAND_SURFACE_FULLSCREEN,
|
||||||
|
META_WAYLAND_SURFACE_POPUP,
|
||||||
} MetaWaylandSurfaceType;
|
} MetaWaylandSurfaceType;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
MetaWaylandSurfaceType initial_type;
|
MetaWaylandSurfaceType initial_type;
|
||||||
struct wl_resource *transient_for;
|
struct wl_resource *transient_for;
|
||||||
|
int x, y;
|
||||||
|
|
||||||
char *title;
|
char *title;
|
||||||
char *wm_class;
|
char *wm_class;
|
||||||
|
Loading…
Reference in New Issue
Block a user