[PATCH weston 5/6] Display the window menu using the desktop shell
Dima Ryazanov
dima at gmail.com
Mon Dec 5 03:36:34 UTC 2016
The compositor creates a resource that gives the desktop shell limited access
to the window that requested a window menu, and sends the desktop shell a
"show_window_menu" event. The desktop shell then displays a popup menu using
the usual window APIs, and sends back a request with the result (only "Close"
for now).
This patch is hacky and not quite finished - but I'd like to get some feedback
first, to make sure this is the correct approach.
Signed-off-by: Dima Ryazanov <dima at gmail.com>
---
clients/desktop-shell.c | 45 +++++++++++++++++++++++++++--
clients/window.c | 47 +++++++++++++++++++++++++++++--
clients/window.h | 10 +++++++
desktop-shell/shell.c | 49 +++++++++++++++++++++++++++++++-
desktop-shell/shell.h | 2 ++
libweston-desktop/internal.h | 5 ++++
libweston-desktop/libweston-desktop.h | 7 +++++
libweston-desktop/surface.c | 30 ++++++++++++++++++++
libweston-desktop/xdg-shell-v6.c | 53 +++++++++++++++++++++++++++++++++++
protocol/weston-desktop-shell.xml | 12 ++++++++
10 files changed, 255 insertions(+), 5 deletions(-)
diff --git a/clients/desktop-shell.c b/clients/desktop-shell.c
index a1cf51d..e12171f 100644
--- a/clients/desktop-shell.c
+++ b/clients/desktop-shell.c
@@ -50,7 +50,8 @@
#include "shared/xalloc.h"
#include "shared/zalloc.h"
-#include "weston-desktop-shell-client-protocol.h"
+#include "xdg-shell-unstable-v6-client-protocol.h"
+#include "weston-desktop-shell-client-protocol.h" /* XXX: Relies on the include order */
#define DEFAULT_CLOCK_FORMAT CLOCK_FORMAT_MINUTES
@@ -1071,10 +1072,50 @@ desktop_shell_grab_cursor(void *data,
}
}
+static void
+frame_menu_func(void *data, struct input *input, int index)
+{
+ struct window *window = data;
+ struct weston_desktop_shell *desktop_shell = window_get_user_data(window);
+
+ switch (index) {
+ case 0: /* close */
+ weston_desktop_shell_window_menu_close(desktop_shell);
+ break;
+ }
+
+ window_destroy(window);
+}
+
+static void
+desktop_shell_show_window_menu(void *data,
+ struct weston_desktop_shell *desktop_shell,
+ struct zxdg_surface_v6 *parent_surface,
+ struct wl_seat *seat, uint32_t serial, uint32_t time,
+ int32_t x, int32_t y)
+{
+ struct desktop *desktop = data;
+ struct window *parent = window_create_foreign(desktop->display,
+ parent_surface);
+ struct input *input = find_input_for_seat(desktop->display, seat);
+
+ static const char *entries[] = {
+ "Close",
+ };
+
+ assert(input);
+
+ window_set_user_data(parent, desktop_shell);
+
+ window_show_menu(desktop->display, input, serial, time, parent, x, y,
+ frame_menu_func, entries, ARRAY_LENGTH(entries));
+}
+
static const struct weston_desktop_shell_listener listener = {
desktop_shell_configure,
desktop_shell_prepare_lock_surface,
- desktop_shell_grab_cursor
+ desktop_shell_grab_cursor,
+ desktop_shell_show_window_menu
};
static void
diff --git a/clients/window.c b/clients/window.c
index 12884f4..d4eeca6 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -1558,7 +1558,8 @@ surface_destroy(struct surface *surface)
if (surface->subsurface)
wl_subsurface_destroy(surface->subsurface);
- wl_surface_destroy(surface->surface);
+ if (surface->surface)
+ wl_surface_destroy(surface->surface);
if (surface->toysurface)
surface->toysurface->destroy(surface->toysurface);
@@ -3540,6 +3541,18 @@ input_get_focus_widget(struct input *input)
return input->focus_widget;
}
+struct input *
+find_input_for_seat(struct display *display, struct wl_seat *seat)
+{
+ struct input *input = NULL;
+
+ wl_list_for_each(input, &display->input_list, link) {
+ if (input_get_seat(input) == seat)
+ return input;
+ }
+ return NULL;
+}
+
struct data_offer {
struct wl_data_offer *offer;
struct input *input;
@@ -5213,7 +5226,7 @@ window_create_internal(struct display *display, int custom)
wl_list_insert(display->window_list.prev, &window->link);
wl_list_init(&window->redraw_task.link);
- wl_list_init (&window->window_output_list);
+ wl_list_init(&window->window_output_list);
return window;
}
@@ -5266,6 +5279,36 @@ window_create_custom(struct display *display)
return window_create_internal(display, 1);
}
+struct window *
+window_create_foreign(struct display *display, struct zxdg_surface_v6 *xdg_surface)
+{
+ struct window *window;
+ struct surface *surface;
+
+ window = xzalloc(sizeof *window);
+ wl_list_init(&window->subsurface_list);
+ window->display = display;
+
+ surface = xzalloc(sizeof *surface);
+ surface->window = window;
+ surface->buffer_scale = 1;
+ wl_list_insert(&window->subsurface_list, &surface->link);
+ window->main_surface = surface;
+
+ window->xdg_surface = xdg_surface;
+
+ window->custom = 1;
+ window->preferred_format = WINDOW_PREFERRED_FORMAT_NONE;
+
+ surface->buffer_type = get_preferred_buffer_type(display);
+
+ wl_list_insert(display->window_list.prev, &window->link);
+ wl_list_init(&window->redraw_task.link);
+ wl_list_init(&window->window_output_list);
+
+ return window;
+}
+
void
window_set_parent(struct window *window,
struct window *parent_window)
diff --git a/clients/window.h b/clients/window.h
index 1cb3d27..8cf4aa6 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -1,3 +1,4 @@
+
/*
* Copyright © 2008 Kristian Høgsberg
*
@@ -713,4 +714,13 @@ xkb_mod_mask_t
keysym_modifiers_get_mask(struct wl_array *modifiers_map,
const char *name);
+/* Used interally by the desktop shell. */
+
+struct zxdg_surface_v6;
+struct window *
+window_create_foreign(struct display *display, struct zxdg_surface_v6 *surface);
+
+struct input *
+find_input_for_seat(struct display *display, struct wl_seat *seat);
+
#endif
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index 3913f95..96366d1 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -2531,6 +2531,42 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
}
static void
+desktop_show_window_menu(struct weston_desktop_surface *desktop_surface,
+ struct weston_seat *seat, uint32_t serial,
+ int32_t x, int32_t y, void *data)
+{
+ struct desktop_shell *shell = data;
+ struct wl_resource *shell_resource = shell->child.desktop_shell;
+ struct wl_resource *parent_resource;
+ struct wl_resource *shell_seat_resource = NULL;
+ struct wl_resource *resource;
+
+ parent_resource = weston_desktop_create_window_menu_parent_resource(
+ shell->child.client, desktop_surface, 0);
+
+ if (!parent_resource)
+ return;
+
+ shell->window_menu_parent_surface = desktop_surface;
+
+ wl_resource_for_each(resource, &seat->base_resource_list) {
+ if (wl_resource_get_client(resource) == shell->child.client) {
+ shell_seat_resource = resource;
+ break;
+ }
+ }
+
+ assert(shell_seat_resource);
+
+ uint32_t time = weston_compositor_get_time();
+
+ weston_desktop_shell_send_show_window_menu(shell_resource,
+ parent_resource,
+ shell_seat_resource,
+ serial, time, x, y);
+}
+
+static void
set_fullscreen(struct shell_surface *shsurf, bool fullscreen,
struct weston_output *output)
{
@@ -2788,6 +2824,7 @@ static const struct weston_desktop_api shell_desktop_api = {
.surface_added = desktop_surface_added,
.surface_removed = desktop_surface_removed,
.committed = desktop_surface_committed,
+ .show_window_menu = desktop_show_window_menu,
.move = desktop_surface_move,
.resize = desktop_surface_resize,
.fullscreen_requested = desktop_surface_fullscreen_requested,
@@ -3138,6 +3175,15 @@ desktop_shell_set_panel_position(struct wl_client *client,
shell->panel_position = position;
}
+static void
+desktop_shell_window_menu_close(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ struct desktop_shell *shell = wl_resource_get_user_data(resource);
+
+ weston_desktop_surface_close(shell->window_menu_parent_surface);
+}
+
static const struct weston_desktop_shell_interface desktop_shell_implementation = {
desktop_shell_set_background,
desktop_shell_set_panel,
@@ -3145,7 +3191,8 @@ static const struct weston_desktop_shell_interface desktop_shell_implementation
desktop_shell_unlock,
desktop_shell_set_grab_surface,
desktop_shell_desktop_ready,
- desktop_shell_set_panel_position
+ desktop_shell_set_panel_position,
+ desktop_shell_window_menu_close
};
static void
diff --git a/desktop-shell/shell.h b/desktop-shell/shell.h
index a1cea75..0f3c2bc 100644
--- a/desktop-shell/shell.h
+++ b/desktop-shell/shell.h
@@ -171,6 +171,8 @@ struct desktop_shell {
struct weston_surface *lock_surface;
struct wl_listener lock_surface_listener;
+ struct weston_desktop_surface *window_menu_parent_surface;
+
struct {
struct wl_array array;
unsigned int current;
diff --git a/libweston-desktop/internal.h b/libweston-desktop/internal.h
index e7044a4..2ecc8c2 100644
--- a/libweston-desktop/internal.h
+++ b/libweston-desktop/internal.h
@@ -159,6 +159,11 @@ weston_desktop_surface_add_resource(struct weston_desktop_surface *surface,
const struct wl_interface *interface,
const void *implementation, uint32_t id,
wl_resource_destroy_func_t destroy);
+struct wl_resource *
+weston_desktop_surface_add_foreign_resource(struct wl_client *wl_client,
+ struct weston_desktop_surface *surface,
+ const struct wl_interface *interface,
+ const void *implementation, uint32_t id);
struct weston_desktop_surface *
weston_desktop_surface_from_grab_link(struct wl_list *grab_link);
diff --git a/libweston-desktop/libweston-desktop.h b/libweston-desktop/libweston-desktop.h
index befecdf..d25359b 100644
--- a/libweston-desktop/libweston-desktop.h
+++ b/libweston-desktop/libweston-desktop.h
@@ -159,6 +159,13 @@ weston_desktop_surface_get_max_size(struct weston_desktop_surface *surface);
struct weston_size
weston_desktop_surface_get_min_size(struct weston_desktop_surface *surface);
+struct wl_resource;
+
+WL_EXPORT struct wl_resource *
+weston_desktop_create_window_menu_parent_resource(struct wl_client *wl_client,
+ struct weston_desktop_surface *surface,
+ uint32_t id);
+
#ifdef __cplusplus
}
#endif
diff --git a/libweston-desktop/surface.c b/libweston-desktop/surface.c
index 2205107..7c3fffe 100644
--- a/libweston-desktop/surface.c
+++ b/libweston-desktop/surface.c
@@ -317,6 +317,36 @@ weston_desktop_surface_add_resource(struct weston_desktop_surface *surface,
return resource;
}
+static void
+destroy_foreign_resource(struct wl_resource *resource)
+{
+ struct weston_desktop_surface *surface =
+ wl_resource_get_user_data(resource);
+
+ if (surface != NULL)
+ wl_list_remove(wl_resource_get_link(resource));
+}
+
+struct wl_resource *
+weston_desktop_surface_add_foreign_resource(struct wl_client *wl_client,
+ struct weston_desktop_surface *surface,
+ const struct wl_interface *interface,
+ const void *implementation, uint32_t id)
+{
+ struct wl_resource *resource;
+
+ resource = wl_resource_create(wl_client, interface, 1, id);
+ if (resource == NULL) {
+ /* Probably don't want to kill the shell here. Kill the client? Ignore? */
+ return NULL;
+ }
+ wl_resource_set_implementation(resource, implementation, surface,
+ destroy_foreign_resource);
+ wl_list_insert(&surface->resource_list, wl_resource_get_link(resource));
+
+ return resource;
+}
+
struct weston_desktop_surface *
weston_desktop_surface_from_grab_link(struct wl_list *grab_link)
{
diff --git a/libweston-desktop/xdg-shell-v6.c b/libweston-desktop/xdg-shell-v6.c
index cab9808..59bb954 100644
--- a/libweston-desktop/xdg-shell-v6.c
+++ b/libweston-desktop/xdg-shell-v6.c
@@ -1346,3 +1346,56 @@ weston_desktop_xdg_shell_v6_create(struct weston_desktop *desktop, struct wl_dis
WD_XDG_SHELL_PROTOCOL_VERSION, desktop,
weston_desktop_xdg_shell_bind);
}
+
+static void
+weston_desktop_window_menu_parent_get_toplevel(struct wl_client *wl_client,
+ struct wl_resource *resource,
+ uint32_t id)
+{
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "not allowed");
+}
+
+static void
+weston_desktop_window_menu_parent_set_window_geometry(struct wl_client *wl_client,
+ struct wl_resource *resource,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "not allowed");
+}
+
+static void
+weston_desktop_window_menu_parent_ack_configure(struct wl_client *wl_client,
+ struct wl_resource *resource,
+ uint32_t serial)
+{
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "not allowed");
+}
+
+static const struct zxdg_surface_v6_interface weston_desktop_window_menu_parent_implementation = {
+ .destroy = weston_desktop_destroy_request,
+ .get_toplevel = weston_desktop_window_menu_parent_get_toplevel,
+ .get_popup = weston_desktop_xdg_surface_protocol_get_popup,
+ .set_window_geometry = weston_desktop_window_menu_parent_set_window_geometry,
+ .ack_configure = weston_desktop_window_menu_parent_ack_configure,
+};
+
+WL_EXPORT struct wl_resource *
+weston_desktop_create_window_menu_parent_resource(struct wl_client *wl_client,
+ struct weston_desktop_surface *surface,
+ uint32_t id)
+{
+ return weston_desktop_surface_add_foreign_resource(
+ wl_client,
+ surface,
+ &zxdg_surface_v6_interface,
+ &weston_desktop_window_menu_parent_implementation,
+ id
+ );
+}
diff --git a/protocol/weston-desktop-shell.xml b/protocol/weston-desktop-shell.xml
index 91c5eb4..9f717b5 100644
--- a/protocol/weston-desktop-shell.xml
+++ b/protocol/weston-desktop-shell.xml
@@ -114,6 +114,18 @@
<arg name="position" type="uint"/>
</request>
+ <event name="show_window_menu">
+ <arg name="parent" type="new_id" interface="zxdg_surface_v6"/>
+ <arg name="seat" type="object" interface="wl_seat"/>
+ <arg name="serial" type="uint"/>
+ <arg name="time" type="uint"/>
+ <arg name="x" type="int"/>
+ <arg name="y" type="int"/>
+ </event>
+
+ <request name="window_menu_close">
+ </request>
+
</interface>
<interface name="weston_screensaver" version="1">
--
2.9.3
More information about the wayland-devel
mailing list