wayland: Add support for xdg-shell protocol (unstable v6).
This is meant to be the desktop-enhanced version of wl_shell. Right now we just match what the existing wl_shell code does, but there are other areas of functionality available to us now, that we can fill in later. This uses the "unstable" API, since this is what ships in Ubuntu 17.10 (as part of Wayland 1.10), but Wayland 1.12 promotes this to stable with extremely minor changes. We will add support for the stable version when it makes sense to do so. --HG-- extra : rebase_source : dbc84f58501611364f8ecabe5a004e26b4debbf1
This commit is contained in:
parent
a16793542d
commit
c4d0b17522
8 changed files with 242 additions and 49 deletions
|
@ -33,15 +33,22 @@
|
|||
#include "SDL_waylanddyn.h"
|
||||
#include "SDL_hints.h"
|
||||
|
||||
#include "xdg-shell-unstable-v6-client-protocol.h"
|
||||
|
||||
/* On modern desktops, we probably will use the xdg-shell protocol instead
|
||||
of wl_shell, but wl_shell might be useful on older Wayland installs that
|
||||
don't have the newer protocol, or embedded things that don't have a full
|
||||
window manager. */
|
||||
|
||||
static void
|
||||
handle_ping(void *data, struct wl_shell_surface *shell_surface,
|
||||
handle_ping_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
|
||||
uint32_t serial)
|
||||
{
|
||||
wl_shell_surface_pong(shell_surface, serial);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_configure(void *data, struct wl_shell_surface *shell_surface,
|
||||
handle_configure_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
|
||||
uint32_t edges, int32_t width, int32_t height)
|
||||
{
|
||||
SDL_WindowData *wind = (SDL_WindowData *)data;
|
||||
|
@ -87,16 +94,94 @@ handle_configure(void *data, struct wl_shell_surface *shell_surface,
|
|||
}
|
||||
|
||||
static void
|
||||
handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
|
||||
handle_popup_done_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_shell_surface_listener shell_surface_listener = {
|
||||
handle_ping,
|
||||
handle_configure,
|
||||
handle_popup_done
|
||||
static const struct wl_shell_surface_listener shell_surface_listener_wl = {
|
||||
handle_ping_wl_shell_surface,
|
||||
handle_configure_wl_shell_surface,
|
||||
handle_popup_done_wl_shell_surface
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
static void
|
||||
handle_configure_zxdg_shell_surface(void *data, struct zxdg_surface_v6 *zxdg, uint32_t serial)
|
||||
{
|
||||
SDL_WindowData *wind = (SDL_WindowData *)data;
|
||||
SDL_Window *window = wind->sdlwindow;
|
||||
struct wl_region *region;
|
||||
WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
|
||||
|
||||
region = wl_compositor_create_region(wind->waylandData->compositor);
|
||||
wl_region_add(region, 0, 0, window->w, window->h);
|
||||
wl_surface_set_opaque_region(wind->surface, region);
|
||||
wl_region_destroy(region);
|
||||
SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, window->w, window->h);
|
||||
zxdg_surface_v6_ack_configure(zxdg, serial);
|
||||
}
|
||||
|
||||
static const struct zxdg_surface_v6_listener shell_surface_listener_zxdg = {
|
||||
handle_configure_zxdg_shell_surface
|
||||
};
|
||||
|
||||
|
||||
static void
|
||||
handle_configure_zxdg_toplevel(void *data,
|
||||
struct zxdg_toplevel_v6 *zxdg_toplevel_v6,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
struct wl_array *states)
|
||||
{
|
||||
SDL_WindowData *wind = (SDL_WindowData *)data;
|
||||
SDL_Window *window = wind->sdlwindow;
|
||||
|
||||
/* wl_shell_surface spec states that this is a suggestion.
|
||||
Ignore if less than or greater than max/min size. */
|
||||
|
||||
if (width == 0 || height == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
|
||||
if ((window->flags & SDL_WINDOW_RESIZABLE)) {
|
||||
if (window->max_w > 0) {
|
||||
width = SDL_min(width, window->max_w);
|
||||
}
|
||||
width = SDL_max(width, window->min_w);
|
||||
|
||||
if (window->max_h > 0) {
|
||||
height = SDL_min(height, window->max_h);
|
||||
}
|
||||
height = SDL_max(height, window->min_h);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (width == window->w && height == window->h) {
|
||||
return;
|
||||
}
|
||||
|
||||
window->w = width;
|
||||
window->h = height;
|
||||
}
|
||||
|
||||
static void
|
||||
handle_close_zxdg_toplevel(void *data, struct zxdg_toplevel_v6 *zxdg_toplevel_v6)
|
||||
{
|
||||
SDL_WindowData *window = (SDL_WindowData *)data;
|
||||
SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
|
||||
}
|
||||
|
||||
static const struct zxdg_toplevel_v6_listener toplevel_listener_zxdg = {
|
||||
handle_configure_zxdg_toplevel,
|
||||
handle_close_zxdg_toplevel
|
||||
};
|
||||
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
|
||||
static void
|
||||
handle_onscreen_visibility(void *data,
|
||||
|
@ -151,7 +236,7 @@ Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
|
|||
|
||||
info->info.wl.display = data->waylandData->display;
|
||||
info->info.wl.surface = data->surface;
|
||||
info->info.wl.shell_surface = data->shell_surface;
|
||||
info->info.wl.shell_surface = data->shell_surface.wl;
|
||||
info->subsystem = SDL_SYSWM_WAYLAND;
|
||||
|
||||
return SDL_TRUE;
|
||||
|
@ -163,20 +248,37 @@ Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
|
|||
return 0; /* just succeed, the real work is done elsewhere. */
|
||||
}
|
||||
|
||||
void Wayland_ShowWindow(_THIS, SDL_Window *window)
|
||||
static void
|
||||
SetFullscreen(_THIS, SDL_Window * window, struct wl_output *output)
|
||||
{
|
||||
const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
|
||||
SDL_WindowData *wind = window->driverdata;
|
||||
|
||||
if (window->flags & SDL_WINDOW_FULLSCREEN)
|
||||
wl_shell_surface_set_fullscreen(wind->shell_surface,
|
||||
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
|
||||
0, (struct wl_output *)window->fullscreen_mode.driverdata);
|
||||
else
|
||||
wl_shell_surface_set_toplevel(wind->shell_surface);
|
||||
if (viddata->shell.zxdg) {
|
||||
if (output) {
|
||||
zxdg_toplevel_v6_set_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel, output);
|
||||
} else {
|
||||
zxdg_toplevel_v6_unset_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel);
|
||||
}
|
||||
} else {
|
||||
if (output) {
|
||||
wl_shell_surface_set_fullscreen(wind->shell_surface.wl,
|
||||
WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
|
||||
0, output);
|
||||
} else {
|
||||
wl_shell_surface_set_toplevel(wind->shell_surface.wl);
|
||||
}
|
||||
}
|
||||
|
||||
WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
|
||||
}
|
||||
|
||||
void Wayland_ShowWindow(_THIS, SDL_Window *window)
|
||||
{
|
||||
struct wl_output *output = (struct wl_output *) window->fullscreen_mode.driverdata;
|
||||
SetFullscreen(_this, window, (window->flags & SDL_WINDOW_FULLSCREEN) ? output : NULL);
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
|
||||
static void SDLCALL
|
||||
QtExtendedSurface_OnHintChanged(void *userdata, const char *name,
|
||||
|
@ -247,24 +349,20 @@ void
|
|||
Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
|
||||
SDL_VideoDisplay * _display, SDL_bool fullscreen)
|
||||
{
|
||||
SDL_WindowData *wind = window->driverdata;
|
||||
|
||||
if (fullscreen)
|
||||
wl_shell_surface_set_fullscreen(wind->shell_surface,
|
||||
WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE,
|
||||
0, (struct wl_output *)_display->driverdata);
|
||||
else
|
||||
wl_shell_surface_set_toplevel(wind->shell_surface);
|
||||
|
||||
WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
|
||||
struct wl_output *output = (struct wl_output *) _display->driverdata;
|
||||
SetFullscreen(_this, window, fullscreen ? output : NULL);
|
||||
}
|
||||
|
||||
void
|
||||
Wayland_RestoreWindow(_THIS, SDL_Window * window)
|
||||
{
|
||||
SDL_WindowData *wind = window->driverdata;
|
||||
const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
|
||||
|
||||
wl_shell_surface_set_toplevel(wind->shell_surface);
|
||||
if (viddata->shell.zxdg) {
|
||||
} else {
|
||||
wl_shell_surface_set_toplevel(wind->shell_surface.wl);
|
||||
}
|
||||
|
||||
WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
|
||||
}
|
||||
|
@ -273,10 +371,15 @@ void
|
|||
Wayland_MaximizeWindow(_THIS, SDL_Window * window)
|
||||
{
|
||||
SDL_WindowData *wind = window->driverdata;
|
||||
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
|
||||
|
||||
wl_shell_surface_set_maximized(wind->shell_surface, NULL);
|
||||
if (viddata->shell.zxdg) {
|
||||
zxdg_toplevel_v6_set_maximized(wind->shell_surface.zxdg.roleobj.toplevel);
|
||||
} else {
|
||||
wl_shell_surface_set_maximized(wind->shell_surface.wl, NULL);
|
||||
}
|
||||
|
||||
WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
|
||||
WAYLAND_wl_display_flush( viddata->display );
|
||||
}
|
||||
|
||||
int Wayland_CreateWindow(_THIS, SDL_Window *window)
|
||||
|
@ -310,9 +413,18 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
|
|||
data->surface =
|
||||
wl_compositor_create_surface(c->compositor);
|
||||
wl_surface_set_user_data(data->surface, data);
|
||||
data->shell_surface = wl_shell_get_shell_surface(c->shell,
|
||||
data->surface);
|
||||
wl_shell_surface_set_class (data->shell_surface, c->classname);
|
||||
|
||||
if (c->shell.zxdg) {
|
||||
data->shell_surface.zxdg.surface = zxdg_shell_v6_get_xdg_surface(c->shell.zxdg, data->surface);
|
||||
/* !!! FIXME: add popup role */
|
||||
data->shell_surface.zxdg.roleobj.toplevel = zxdg_surface_v6_get_toplevel(data->shell_surface.zxdg.surface);
|
||||
zxdg_toplevel_v6_add_listener(data->shell_surface.zxdg.roleobj.toplevel, &toplevel_listener_zxdg, data);
|
||||
zxdg_toplevel_v6_set_app_id(data->shell_surface.zxdg.roleobj.toplevel, c->classname);
|
||||
} else {
|
||||
data->shell_surface.wl = wl_shell_get_shell_surface(c->shell.wl, data->surface);
|
||||
wl_shell_surface_set_class(data->shell_surface.wl, c->classname);
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
|
||||
if (c->surface_extension) {
|
||||
data->extended_surface = qt_surface_extension_get_extended_surface(
|
||||
|
@ -333,10 +445,16 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
|
|||
return SDL_SetError("failed to create a window surface");
|
||||
}
|
||||
|
||||
if (data->shell_surface) {
|
||||
wl_shell_surface_set_user_data(data->shell_surface, data);
|
||||
wl_shell_surface_add_listener(data->shell_surface,
|
||||
&shell_surface_listener, data);
|
||||
if (c->shell.zxdg) {
|
||||
if (data->shell_surface.zxdg.surface) {
|
||||
zxdg_surface_v6_set_user_data(data->shell_surface.zxdg.surface, data);
|
||||
zxdg_surface_v6_add_listener(data->shell_surface.zxdg.surface, &shell_surface_listener_zxdg, data);
|
||||
}
|
||||
} else {
|
||||
if (data->shell_surface.wl) {
|
||||
wl_shell_surface_set_user_data(data->shell_surface.wl, data);
|
||||
wl_shell_surface_add_listener(data->shell_surface.wl, &shell_surface_listener_wl, data);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
|
||||
|
@ -356,6 +474,7 @@ int Wayland_CreateWindow(_THIS, SDL_Window *window)
|
|||
Wayland_input_lock_pointer(c->input);
|
||||
}
|
||||
|
||||
wl_surface_commit(data->surface);
|
||||
WAYLAND_wl_display_flush(c->display);
|
||||
|
||||
return 0;
|
||||
|
@ -378,9 +497,14 @@ void Wayland_SetWindowSize(_THIS, SDL_Window * window)
|
|||
void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
|
||||
{
|
||||
SDL_WindowData *wind = window->driverdata;
|
||||
SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
|
||||
|
||||
if (window->title != NULL) {
|
||||
wl_shell_surface_set_title(wind->shell_surface, window->title);
|
||||
if (viddata->shell.zxdg) {
|
||||
zxdg_toplevel_v6_set_title(wind->shell_surface.zxdg.roleobj.toplevel, window->title);
|
||||
} else {
|
||||
wl_shell_surface_set_title(wind->shell_surface.wl, window->title);
|
||||
}
|
||||
}
|
||||
|
||||
WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
|
||||
|
@ -395,8 +519,18 @@ void Wayland_DestroyWindow(_THIS, SDL_Window *window)
|
|||
SDL_EGL_DestroySurface(_this, wind->egl_surface);
|
||||
WAYLAND_wl_egl_window_destroy(wind->egl_window);
|
||||
|
||||
if (wind->shell_surface)
|
||||
wl_shell_surface_destroy(wind->shell_surface);
|
||||
if (data->shell.zxdg) {
|
||||
if (wind->shell_surface.zxdg.roleobj.toplevel) {
|
||||
zxdg_toplevel_v6_destroy(wind->shell_surface.zxdg.roleobj.toplevel);
|
||||
}
|
||||
if (wind->shell_surface.zxdg.surface) {
|
||||
zxdg_surface_v6_destroy(wind->shell_surface.zxdg.surface);
|
||||
}
|
||||
} else {
|
||||
if (wind->shell_surface.wl) {
|
||||
wl_shell_surface_destroy(wind->shell_surface.wl);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
|
||||
if (wind->extended_surface) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue