src/video/wayland/SDL_waylandwindow.c
author Sebastian Krzyszkowiak <dos@dosowisko.net>
Wed, 07 Nov 2018 01:08:35 +0100
changeset 12400 28303fca62bd
parent 12381 dc9108cd4340
child 12426 779d711b6b5e
permissions -rw-r--r--
wayland: fix resizing and fullscreen toggling
For starters, we need to correctly respond to 0,0 configure after unsetting
fullscreen. Also, turns out that there should be no drawing calls at all
in between eglSwapBuffers and wl_egl_window_resize, as otherwise EGL can
already allocate a wrongly sized buffer for a next frame, so handle those
together.
gabomdq@8062
     1
/*
gabomdq@8062
     2
  Simple DirectMedia Layer
slouken@11811
     3
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
gabomdq@8062
     4
gabomdq@8062
     5
  This software is provided 'as-is', without any express or implied
gabomdq@8062
     6
  warranty.  In no event will the authors be held liable for any damages
gabomdq@8062
     7
  arising from the use of this software.
gabomdq@8062
     8
gabomdq@8062
     9
  Permission is granted to anyone to use this software for any purpose,
gabomdq@8062
    10
  including commercial applications, and to alter it and redistribute it
gabomdq@8062
    11
  freely, subject to the following restrictions:
gabomdq@8062
    12
gabomdq@8062
    13
  1. The origin of this software must not be misrepresented; you must not
gabomdq@8062
    14
     claim that you wrote the original software. If you use this software
gabomdq@8062
    15
     in a product, an acknowledgment in the product documentation would be
gabomdq@8062
    16
     appreciated but is not required.
gabomdq@8062
    17
  2. Altered source versions must be plainly marked as such, and must not be
gabomdq@8062
    18
     misrepresented as being the original software.
gabomdq@8062
    19
  3. This notice may not be removed or altered from any source distribution.
gabomdq@8062
    20
*/
gabomdq@8062
    21
gabomdq@8104
    22
#include "../../SDL_internal.h"
gabomdq@8062
    23
icculus@8116
    24
#if SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL
icculus@8116
    25
gabomdq@8062
    26
#include "../SDL_sysvideo.h"
gabomdq@8062
    27
#include "../../events/SDL_windowevents_c.h"
gabomdq@8062
    28
#include "../SDL_egl_c.h"
slouken@10304
    29
#include "SDL_waylandevents_c.h"
gabomdq@8062
    30
#include "SDL_waylandwindow.h"
gabomdq@8062
    31
#include "SDL_waylandvideo.h"
gabomdq@8082
    32
#include "SDL_waylandtouch.h"
arnej@9362
    33
#include "SDL_waylanddyn.h"
m@10614
    34
#include "SDL_hints.h"
gabomdq@8062
    35
icculus@12033
    36
#include "xdg-shell-client-protocol.h"
icculus@11848
    37
#include "xdg-shell-unstable-v6-client-protocol.h"
icculus@12367
    38
#include "org-kde-kwin-server-decoration-manager-client-protocol.h"
icculus@11848
    39
icculus@11848
    40
/* On modern desktops, we probably will use the xdg-shell protocol instead
icculus@11848
    41
   of wl_shell, but wl_shell might be useful on older Wayland installs that
icculus@11848
    42
   don't have the newer protocol, or embedded things that don't have a full
icculus@11848
    43
   window manager. */
icculus@11848
    44
gabomdq@8062
    45
static void
icculus@11848
    46
handle_ping_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
gabomdq@8062
    47
            uint32_t serial)
gabomdq@8062
    48
{
gabomdq@8062
    49
    wl_shell_surface_pong(shell_surface, serial);
gabomdq@8062
    50
}
gabomdq@8062
    51
gabomdq@8062
    52
static void
icculus@11848
    53
handle_configure_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface,
gabomdq@8062
    54
                 uint32_t edges, int32_t width, int32_t height)
gabomdq@8062
    55
{
gabomdq@8766
    56
    SDL_WindowData *wind = (SDL_WindowData *)data;
gabomdq@8766
    57
    SDL_Window *window = wind->sdlwindow;
gabomdq@8766
    58
slouken@10492
    59
    /* wl_shell_surface spec states that this is a suggestion.
slouken@10492
    60
       Ignore if less than or greater than max/min size. */
slouken@10492
    61
slouken@10492
    62
    if (width == 0 || height == 0) {
slouken@10492
    63
        return;
slouken@10492
    64
    }
slouken@10492
    65
slouken@10492
    66
    if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
slouken@10492
    67
        if ((window->flags & SDL_WINDOW_RESIZABLE)) {
slouken@10492
    68
            if (window->max_w > 0) {
slouken@10492
    69
                width = SDL_min(width, window->max_w);
dos@12400
    70
            }
slouken@10492
    71
            width = SDL_max(width, window->min_w);
slouken@10492
    72
slouken@10492
    73
            if (window->max_h > 0) {
slouken@10492
    74
                height = SDL_min(height, window->max_h);
slouken@10492
    75
            }
slouken@10492
    76
            height = SDL_max(height, window->min_h);
slouken@10492
    77
        } else {
slouken@10492
    78
            return;
slouken@10492
    79
        }
slouken@10492
    80
    }
slouken@10492
    81
dos@12400
    82
    wind->resize.width = width;
dos@12400
    83
    wind->resize.height = height;
dos@12400
    84
    wind->resize.pending = SDL_TRUE;
gabomdq@8062
    85
}
gabomdq@8062
    86
gabomdq@8062
    87
static void
icculus@11848
    88
handle_popup_done_wl_shell_surface(void *data, struct wl_shell_surface *shell_surface)
gabomdq@8062
    89
{
gabomdq@8062
    90
}
gabomdq@8062
    91
icculus@11848
    92
static const struct wl_shell_surface_listener shell_surface_listener_wl = {
icculus@11848
    93
    handle_ping_wl_shell_surface,
icculus@11848
    94
    handle_configure_wl_shell_surface,
icculus@11848
    95
    handle_popup_done_wl_shell_surface
gabomdq@8062
    96
};
gabomdq@8062
    97
icculus@11848
    98
icculus@11848
    99
icculus@11848
   100
icculus@11848
   101
static void
icculus@11848
   102
handle_configure_zxdg_shell_surface(void *data, struct zxdg_surface_v6 *zxdg, uint32_t serial)
icculus@11848
   103
{
icculus@11848
   104
    SDL_WindowData *wind = (SDL_WindowData *)data;
icculus@11848
   105
    SDL_Window *window = wind->sdlwindow;
icculus@11848
   106
    struct wl_region *region;
icculus@11944
   107
dos@12400
   108
    if (!wind->shell_surface.zxdg.initial_configure_seen) {
dos@12400
   109
        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, wind->resize.width, wind->resize.height);
dos@12400
   110
        window->w = wind->resize.width;
dos@12400
   111
        window->h = wind->resize.height;
icculus@11944
   112
dos@12400
   113
        WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
icculus@11848
   114
dos@12400
   115
        zxdg_surface_v6_ack_configure(zxdg, serial);
dos@12400
   116
dos@12400
   117
        region = wl_compositor_create_region(wind->waylandData->compositor);
dos@12400
   118
        wl_region_add(region, 0, 0, window->w, window->h);
dos@12400
   119
        wl_surface_set_opaque_region(wind->surface, region);
dos@12400
   120
        wl_region_destroy(region);
dos@12400
   121
dos@12400
   122
        wind->shell_surface.zxdg.initial_configure_seen = SDL_TRUE;
dos@12400
   123
    } else {
dos@12400
   124
        wind->resize.pending = SDL_TRUE;
dos@12400
   125
        wind->resize.serial = serial;
dos@12400
   126
    }
icculus@11848
   127
}
icculus@11848
   128
icculus@11848
   129
static const struct zxdg_surface_v6_listener shell_surface_listener_zxdg = {
icculus@11848
   130
    handle_configure_zxdg_shell_surface
icculus@11848
   131
};
icculus@11848
   132
icculus@11848
   133
icculus@11848
   134
static void
icculus@11848
   135
handle_configure_zxdg_toplevel(void *data,
slouken@12201
   136
              struct zxdg_toplevel_v6 *zxdg_toplevel_v6,
slouken@12201
   137
              int32_t width,
slouken@12201
   138
              int32_t height,
slouken@12201
   139
              struct wl_array *states)
icculus@12033
   140
{
icculus@12033
   141
    SDL_WindowData *wind = (SDL_WindowData *)data;
icculus@12033
   142
    SDL_Window *window = wind->sdlwindow;
icculus@12033
   143
dos@12400
   144
    enum zxdg_toplevel_v6_state *state;
dos@12400
   145
    SDL_bool fullscreen = SDL_FALSE;
dos@12400
   146
    wl_array_for_each(state, states) {
dos@12400
   147
        if (*state == ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN) {
dos@12400
   148
            fullscreen = SDL_TRUE;
dos@12400
   149
        }
icculus@12033
   150
    }
icculus@12033
   151
dos@12400
   152
    if (!fullscreen) {
dos@12400
   153
        if (width == 0 || height == 0) {
dos@12400
   154
            width = window->windowed.w;
dos@12400
   155
            height = window->windowed.h;
dos@12400
   156
        }
dos@12400
   157
dos@12400
   158
        /* zxdg_toplevel spec states that this is a suggestion.
dos@12400
   159
           Ignore if less than or greater than max/min size. */
dos@12400
   160
icculus@12033
   161
        if ((window->flags & SDL_WINDOW_RESIZABLE)) {
icculus@12033
   162
            if (window->max_w > 0) {
icculus@12033
   163
                width = SDL_min(width, window->max_w);
dos@12400
   164
            }
icculus@12033
   165
            width = SDL_max(width, window->min_w);
icculus@12033
   166
icculus@12033
   167
            if (window->max_h > 0) {
icculus@12033
   168
                height = SDL_min(height, window->max_h);
icculus@12033
   169
            }
icculus@12033
   170
            height = SDL_max(height, window->min_h);
icculus@12033
   171
        } else {
dos@12400
   172
            wind->resize.width = window->w;
dos@12400
   173
            wind->resize.height = window->h;
icculus@12033
   174
            return;
icculus@12033
   175
        }
icculus@12033
   176
    }
icculus@12033
   177
dos@12400
   178
    if (width == 0 || height == 0) {
dos@12400
   179
        wind->resize.width = window->w;
dos@12400
   180
        wind->resize.height = window->h;
dos@12400
   181
        return;
dos@12400
   182
    }
dos@12400
   183
dos@12400
   184
    wind->resize.width = width;
dos@12400
   185
    wind->resize.height = height;
icculus@12033
   186
}
icculus@12033
   187
icculus@12033
   188
static void
icculus@12033
   189
handle_close_zxdg_toplevel(void *data, struct zxdg_toplevel_v6 *zxdg_toplevel_v6)
icculus@12033
   190
{
icculus@12033
   191
    SDL_WindowData *window = (SDL_WindowData *)data;
icculus@12033
   192
    SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
icculus@12033
   193
}
icculus@12033
   194
icculus@12033
   195
static const struct zxdg_toplevel_v6_listener toplevel_listener_zxdg = {
icculus@12033
   196
    handle_configure_zxdg_toplevel,
icculus@12033
   197
    handle_close_zxdg_toplevel
icculus@12033
   198
};
icculus@12033
   199
icculus@12033
   200
icculus@12033
   201
icculus@12033
   202
static void
icculus@12033
   203
handle_configure_xdg_shell_surface(void *data, struct xdg_surface *xdg, uint32_t serial)
icculus@12033
   204
{
icculus@12033
   205
    SDL_WindowData *wind = (SDL_WindowData *)data;
icculus@12033
   206
    SDL_Window *window = wind->sdlwindow;
icculus@12033
   207
    struct wl_region *region;
icculus@12033
   208
dos@12400
   209
    if (!wind->shell_surface.xdg.initial_configure_seen) {
dos@12400
   210
        SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, wind->resize.width, wind->resize.height);
dos@12400
   211
        window->w = wind->resize.width;
dos@12400
   212
        window->h = wind->resize.height;
icculus@12033
   213
dos@12400
   214
        WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
icculus@12033
   215
dos@12400
   216
        xdg_surface_ack_configure(xdg, serial);
dos@12400
   217
dos@12400
   218
        region = wl_compositor_create_region(wind->waylandData->compositor);
dos@12400
   219
        wl_region_add(region, 0, 0, window->w, window->h);
dos@12400
   220
        wl_surface_set_opaque_region(wind->surface, region);
dos@12400
   221
        wl_region_destroy(region);
dos@12400
   222
dos@12400
   223
        wind->shell_surface.xdg.initial_configure_seen = SDL_TRUE;
dos@12400
   224
    } else {
dos@12400
   225
        wind->resize.pending = SDL_TRUE;
dos@12400
   226
        wind->resize.serial = serial;
dos@12400
   227
    }
icculus@12033
   228
}
icculus@12033
   229
icculus@12033
   230
static const struct xdg_surface_listener shell_surface_listener_xdg = {
icculus@12033
   231
    handle_configure_xdg_shell_surface
icculus@12033
   232
};
icculus@12033
   233
icculus@12033
   234
icculus@12033
   235
static void
icculus@12033
   236
handle_configure_xdg_toplevel(void *data,
slouken@12201
   237
              struct xdg_toplevel *xdg_toplevel,
slouken@12201
   238
              int32_t width,
slouken@12201
   239
              int32_t height,
slouken@12201
   240
              struct wl_array *states)
icculus@11848
   241
{
icculus@11848
   242
    SDL_WindowData *wind = (SDL_WindowData *)data;
icculus@11848
   243
    SDL_Window *window = wind->sdlwindow;
icculus@11848
   244
dos@12400
   245
    enum xdg_toplevel_state *state;
dos@12400
   246
    SDL_bool fullscreen = SDL_FALSE;
dos@12400
   247
    wl_array_for_each(state, states) {
dos@12400
   248
        if (*state == XDG_TOPLEVEL_STATE_FULLSCREEN) {
dos@12400
   249
            fullscreen = SDL_TRUE;
dos@12400
   250
        }
dos@12400
   251
     }
icculus@11848
   252
dos@12400
   253
    if (!fullscreen) {
dos@12400
   254
        if (width == 0 || height == 0) {
dos@12400
   255
            width = window->windowed.w;
dos@12400
   256
            height = window->windowed.h;
dos@12400
   257
        }
icculus@11848
   258
dos@12400
   259
        /* xdg_toplevel spec states that this is a suggestion.
dos@12400
   260
           Ignore if less than or greater than max/min size. */
dos@12400
   261
icculus@11848
   262
        if ((window->flags & SDL_WINDOW_RESIZABLE)) {
icculus@11848
   263
            if (window->max_w > 0) {
icculus@11848
   264
                width = SDL_min(width, window->max_w);
dos@12400
   265
            }
icculus@11848
   266
            width = SDL_max(width, window->min_w);
icculus@11848
   267
icculus@11848
   268
            if (window->max_h > 0) {
icculus@11848
   269
                height = SDL_min(height, window->max_h);
icculus@11848
   270
            }
icculus@11848
   271
            height = SDL_max(height, window->min_h);
icculus@11848
   272
        } else {
dos@12400
   273
            wind->resize.width = window->w;
dos@12400
   274
            wind->resize.height = window->h;
icculus@11848
   275
            return;
icculus@11848
   276
        }
icculus@11848
   277
    }
icculus@11848
   278
dos@12400
   279
    if (width == 0 || height == 0) {
dos@12400
   280
        wind->resize.width = window->w;
dos@12400
   281
        wind->resize.height = window->h;
icculus@11848
   282
        return;
icculus@11848
   283
    }
icculus@11848
   284
dos@12400
   285
    wind->resize.width = width;
dos@12400
   286
    wind->resize.height = height;
icculus@12033
   287
}
icculus@12033
   288
icculus@12033
   289
static void
icculus@12033
   290
handle_close_xdg_toplevel(void *data, struct xdg_toplevel *xdg_toplevel)
icculus@12033
   291
{
icculus@12033
   292
    SDL_WindowData *window = (SDL_WindowData *)data;
icculus@12033
   293
    SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
icculus@12033
   294
}
icculus@12033
   295
icculus@12033
   296
static const struct xdg_toplevel_listener toplevel_listener_xdg = {
icculus@12033
   297
    handle_configure_xdg_toplevel,
icculus@12033
   298
    handle_close_xdg_toplevel
icculus@12033
   299
};
icculus@12033
   300
icculus@12033
   301
icculus@12033
   302
icculus@12033
   303
gabomdq@8082
   304
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
gabomdq@8082
   305
static void
gabomdq@8082
   306
handle_onscreen_visibility(void *data,
gabomdq@8082
   307
        struct qt_extended_surface *qt_extended_surface, int32_t visible)
gabomdq@8082
   308
{
gabomdq@8082
   309
}
gabomdq@8082
   310
gabomdq@8082
   311
static void
gabomdq@8082
   312
handle_set_generic_property(void *data,
gabomdq@8082
   313
        struct qt_extended_surface *qt_extended_surface, const char *name,
gabomdq@8082
   314
        struct wl_array *value)
gabomdq@8082
   315
{
gabomdq@8082
   316
}
gabomdq@8082
   317
gabomdq@8082
   318
static void
gabomdq@8082
   319
handle_close(void *data, struct qt_extended_surface *qt_extended_surface)
gabomdq@8082
   320
{
gabomdq@8082
   321
    SDL_WindowData *window = (SDL_WindowData *)data;
gabomdq@8082
   322
    SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
gabomdq@8082
   323
}
gabomdq@8082
   324
gabomdq@8082
   325
static const struct qt_extended_surface_listener extended_surface_listener = {
gabomdq@8082
   326
    handle_onscreen_visibility,
gabomdq@8082
   327
    handle_set_generic_property,
gabomdq@8082
   328
    handle_close,
gabomdq@8082
   329
};
gabomdq@8082
   330
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
gabomdq@8082
   331
gabomdq@8062
   332
SDL_bool
gabomdq@8062
   333
Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
gabomdq@8062
   334
{
gabomdq@8062
   335
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
icculus@11088
   336
    const Uint32 version = ((((Uint32) info->version.major) * 1000000) +
icculus@11088
   337
                            (((Uint32) info->version.minor) * 10000) +
icculus@11088
   338
                            (((Uint32) info->version.patch)));
icculus@11088
   339
icculus@11088
   340
    /* Before 2.0.6, it was possible to build an SDL with Wayland support
icculus@11088
   341
       (SDL_SysWMinfo will be large enough to hold Wayland info), but build
icculus@11088
   342
       your app against SDL headers that didn't have Wayland support
icculus@11088
   343
       (SDL_SysWMinfo could be smaller than Wayland needs. This would lead
icculus@11088
   344
       to an app properly using SDL_GetWindowWMInfo() but we'd accidentally
icculus@11088
   345
       overflow memory on the stack or heap. To protect against this, we've
icculus@11088
   346
       padded out the struct unconditionally in the headers and Wayland will
icculus@11088
   347
       just return an error for older apps using this function. Those apps
icculus@11088
   348
       will need to be recompiled against newer headers or not use Wayland,
icculus@11088
   349
       maybe by forcing SDL_VIDEODRIVER=x11. */
icculus@11088
   350
    if (version < 2000006) {
icculus@11088
   351
        info->subsystem = SDL_SYSWM_UNKNOWN;
philipp@11092
   352
        SDL_SetError("Version must be 2.0.6 or newer");
icculus@11088
   353
        return SDL_FALSE;
icculus@11088
   354
    }
gabomdq@8062
   355
gabomdq@8062
   356
    info->info.wl.display = data->waylandData->display;
gabomdq@8062
   357
    info->info.wl.surface = data->surface;
icculus@11848
   358
    info->info.wl.shell_surface = data->shell_surface.wl;
gabomdq@8062
   359
    info->subsystem = SDL_SYSWM_WAYLAND;
gabomdq@8062
   360
gabomdq@8062
   361
    return SDL_TRUE;
gabomdq@8062
   362
}
gabomdq@8062
   363
icculus@9554
   364
int
icculus@9554
   365
Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
icculus@9554
   366
{
icculus@9554
   367
    return 0;  /* just succeed, the real work is done elsewhere. */
icculus@9554
   368
}
icculus@9554
   369
icculus@11848
   370
static void
icculus@11848
   371
SetFullscreen(_THIS, SDL_Window * window, struct wl_output *output)
icculus@11848
   372
{
icculus@11848
   373
    const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
icculus@11848
   374
    SDL_WindowData *wind = window->driverdata;
icculus@11848
   375
icculus@12033
   376
    if (viddata->shell.xdg) {
icculus@12033
   377
        if (output) {
icculus@12033
   378
            xdg_toplevel_set_fullscreen(wind->shell_surface.xdg.roleobj.toplevel, output);
icculus@12033
   379
        } else {
icculus@12033
   380
            xdg_toplevel_unset_fullscreen(wind->shell_surface.xdg.roleobj.toplevel);
icculus@12033
   381
        }
icculus@12033
   382
    } else if (viddata->shell.zxdg) {
icculus@11848
   383
        if (output) {
icculus@11848
   384
            zxdg_toplevel_v6_set_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel, output);
icculus@11848
   385
        } else {
icculus@11848
   386
            zxdg_toplevel_v6_unset_fullscreen(wind->shell_surface.zxdg.roleobj.toplevel);
icculus@11848
   387
        }
icculus@11848
   388
    } else {
icculus@11848
   389
        if (output) {
icculus@11848
   390
            wl_shell_surface_set_fullscreen(wind->shell_surface.wl,
icculus@11848
   391
                                            WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
icculus@11848
   392
                                            0, output);
icculus@11848
   393
        } else {
icculus@11848
   394
            wl_shell_surface_set_toplevel(wind->shell_surface.wl);
icculus@11848
   395
        }
icculus@11848
   396
    }
icculus@11848
   397
icculus@11848
   398
    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
icculus@11848
   399
}
icculus@11848
   400
gabomdq@8062
   401
void Wayland_ShowWindow(_THIS, SDL_Window *window)
gabomdq@8062
   402
{
icculus@11848
   403
    struct wl_output *output = (struct wl_output *) window->fullscreen_mode.driverdata;
icculus@11848
   404
    SetFullscreen(_this, window, (window->flags & SDL_WINDOW_FULLSCREEN) ? output : NULL);
gabomdq@8062
   405
}
gabomdq@8062
   406
m@10614
   407
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
slouken@11284
   408
static void SDLCALL
slouken@11284
   409
QtExtendedSurface_OnHintChanged(void *userdata, const char *name,
m@10614
   410
        const char *oldValue, const char *newValue)
m@10614
   411
{
m@10614
   412
    struct qt_extended_surface *qt_extended_surface = userdata;
m@10614
   413
m@10614
   414
    if (name == NULL) {
m@10614
   415
        return;
m@10614
   416
    }
m@10614
   417
m@10614
   418
    if (strcmp(name, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION) == 0) {
m@10614
   419
        int32_t orientation = QT_EXTENDED_SURFACE_ORIENTATION_PRIMARYORIENTATION;
m@10614
   420
m@10614
   421
        if (newValue != NULL) {
m@10614
   422
            if (strcmp(newValue, "portrait") == 0) {
m@10614
   423
                orientation = QT_EXTENDED_SURFACE_ORIENTATION_PORTRAITORIENTATION;
m@10614
   424
            } else if (strcmp(newValue, "landscape") == 0) {
m@10614
   425
                orientation = QT_EXTENDED_SURFACE_ORIENTATION_LANDSCAPEORIENTATION;
m@10614
   426
            } else if (strcmp(newValue, "inverted-portrait") == 0) {
m@10614
   427
                orientation = QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDPORTRAITORIENTATION;
m@10614
   428
            } else if (strcmp(newValue, "inverted-landscape") == 0) {
m@10614
   429
                orientation = QT_EXTENDED_SURFACE_ORIENTATION_INVERTEDLANDSCAPEORIENTATION;
m@10614
   430
            }
m@10614
   431
        }
m@10614
   432
m@10614
   433
        qt_extended_surface_set_content_orientation(qt_extended_surface, orientation);
m@10614
   434
    } else if (strcmp(name, SDL_HINT_QTWAYLAND_WINDOW_FLAGS) == 0) {
m@10614
   435
        uint32_t flags = 0;
m@10614
   436
m@10614
   437
        if (newValue != NULL) {
m@10614
   438
            char *tmp = strdup(newValue);
m@10614
   439
            char *saveptr = NULL;
m@10614
   440
m@10614
   441
            char *flag = strtok_r(tmp, " ", &saveptr);
m@10614
   442
            while (flag) {
m@10614
   443
                if (strcmp(flag, "OverridesSystemGestures") == 0) {
m@10614
   444
                    flags |= QT_EXTENDED_SURFACE_WINDOWFLAG_OVERRIDESSYSTEMGESTURES;
m@10614
   445
                } else if (strcmp(flag, "StaysOnTop") == 0) {
m@10614
   446
                    flags |= QT_EXTENDED_SURFACE_WINDOWFLAG_STAYSONTOP;
m@10614
   447
                } else if (strcmp(flag, "BypassWindowManager") == 0) {
m@10614
   448
                    // See https://github.com/qtproject/qtwayland/commit/fb4267103d
m@10614
   449
                    flags |= 4 /* QT_EXTENDED_SURFACE_WINDOWFLAG_BYPASSWINDOWMANAGER */;
m@10614
   450
                }
m@10614
   451
m@10614
   452
                flag = strtok_r(NULL, " ", &saveptr);
m@10614
   453
            }
m@10614
   454
m@10614
   455
            free(tmp);
m@10614
   456
        }
m@10614
   457
m@10614
   458
        qt_extended_surface_set_window_flags(qt_extended_surface, flags);
m@10614
   459
    }
m@10614
   460
}
m@10614
   461
m@10614
   462
static void QtExtendedSurface_Subscribe(struct qt_extended_surface *surface, const char *name)
m@10614
   463
{
m@10614
   464
    SDL_AddHintCallback(name, QtExtendedSurface_OnHintChanged, surface);
m@10614
   465
}
m@10614
   466
m@10614
   467
static void QtExtendedSurface_Unsubscribe(struct qt_extended_surface *surface, const char *name)
m@10614
   468
{
m@10614
   469
    SDL_DelHintCallback(name, QtExtendedSurface_OnHintChanged, surface);
m@10614
   470
}
m@10614
   471
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
m@10614
   472
gabomdq@8062
   473
void
gabomdq@8062
   474
Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
gabomdq@8062
   475
                            SDL_VideoDisplay * _display, SDL_bool fullscreen)
gabomdq@8062
   476
{
icculus@11848
   477
    struct wl_output *output = (struct wl_output *) _display->driverdata;
icculus@11848
   478
    SetFullscreen(_this, window, fullscreen ? output : NULL);
gabomdq@8062
   479
}
gabomdq@8062
   480
slouken@10492
   481
void
slouken@10492
   482
Wayland_RestoreWindow(_THIS, SDL_Window * window)
slouken@10492
   483
{
slouken@10492
   484
    SDL_WindowData *wind = window->driverdata;
icculus@11848
   485
    const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
slouken@10492
   486
icculus@12033
   487
    if (viddata->shell.xdg) {
icculus@12033
   488
    } else if (viddata->shell.zxdg) {
icculus@11848
   489
    } else {
icculus@11848
   490
        wl_shell_surface_set_toplevel(wind->shell_surface.wl);
icculus@11848
   491
    }
slouken@10492
   492
slouken@10492
   493
    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
slouken@10492
   494
}
slouken@10492
   495
slouken@10492
   496
void
icculus@12367
   497
Wayland_SetWindowBordered(_THIS, SDL_Window * window, SDL_bool bordered)
icculus@12367
   498
{
icculus@12367
   499
    SDL_WindowData *wind = window->driverdata;
icculus@12367
   500
    const SDL_VideoData *viddata = (const SDL_VideoData *) _this->driverdata;
icculus@12367
   501
    if ((viddata->kwin_server_decoration_manager) && (wind->kwin_server_decoration)) {
icculus@12367
   502
        const enum org_kde_kwin_server_decoration_mode mode = bordered ? ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER : ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE;
icculus@12367
   503
        org_kde_kwin_server_decoration_request_mode(wind->kwin_server_decoration, mode);
icculus@12367
   504
    }
icculus@12367
   505
}
icculus@12367
   506
icculus@12367
   507
void
slouken@10492
   508
Wayland_MaximizeWindow(_THIS, SDL_Window * window)
slouken@10492
   509
{
slouken@10492
   510
    SDL_WindowData *wind = window->driverdata;
icculus@11848
   511
    SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
slouken@10492
   512
icculus@12033
   513
    if (viddata->shell.xdg) {
icculus@12033
   514
        xdg_toplevel_set_maximized(wind->shell_surface.xdg.roleobj.toplevel);
icculus@12033
   515
    } else if (viddata->shell.zxdg) {
icculus@11848
   516
        zxdg_toplevel_v6_set_maximized(wind->shell_surface.zxdg.roleobj.toplevel);
icculus@11848
   517
    } else {
icculus@11848
   518
        wl_shell_surface_set_maximized(wind->shell_surface.wl, NULL);
icculus@11848
   519
    }
slouken@10492
   520
icculus@11848
   521
    WAYLAND_wl_display_flush( viddata->display );
slouken@10492
   522
}
slouken@10492
   523
gabomdq@8062
   524
int Wayland_CreateWindow(_THIS, SDL_Window *window)
gabomdq@8062
   525
{
gabomdq@8062
   526
    SDL_WindowData *data;
gabomdq@8062
   527
    SDL_VideoData *c;
gabomdq@8062
   528
    struct wl_region *region;
gabomdq@8062
   529
gabomdq@8062
   530
    data = calloc(1, sizeof *data);
gabomdq@8062
   531
    if (data == NULL)
philipp@9483
   532
        return SDL_OutOfMemory();
gabomdq@8062
   533
gabomdq@8062
   534
    c = _this->driverdata;
gabomdq@8062
   535
    window->driverdata = data;
gabomdq@8062
   536
gabomdq@8062
   537
    if (!(window->flags & SDL_WINDOW_OPENGL)) {
gabomdq@8062
   538
        SDL_GL_LoadLibrary(NULL);
gabomdq@8062
   539
        window->flags |= SDL_WINDOW_OPENGL;
gabomdq@8062
   540
    }
gabomdq@8062
   541
gabomdq@8062
   542
    if (window->x == SDL_WINDOWPOS_UNDEFINED) {
gabomdq@8062
   543
        window->x = 0;
gabomdq@8062
   544
    }
gabomdq@8062
   545
    if (window->y == SDL_WINDOWPOS_UNDEFINED) {
gabomdq@8062
   546
        window->y = 0;
gabomdq@8062
   547
    }
gabomdq@8062
   548
gabomdq@8062
   549
    data->waylandData = c;
gabomdq@8062
   550
    data->sdlwindow = window;
gabomdq@8062
   551
dos@12400
   552
    data->resize.pending = SDL_FALSE;
dos@12400
   553
gabomdq@8062
   554
    data->surface =
gabomdq@8062
   555
        wl_compositor_create_surface(c->compositor);
gabomdq@8062
   556
    wl_surface_set_user_data(data->surface, data);
icculus@11848
   557
icculus@12033
   558
    if (c->shell.xdg) {
icculus@12033
   559
        data->shell_surface.xdg.surface = xdg_wm_base_get_xdg_surface(c->shell.xdg, data->surface);
icculus@12033
   560
        /* !!! FIXME: add popup role */
icculus@12033
   561
        data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface);
icculus@12033
   562
        xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data);
icculus@12033
   563
        xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, c->classname);
icculus@12033
   564
    } else if (c->shell.zxdg) {
icculus@11848
   565
        data->shell_surface.zxdg.surface = zxdg_shell_v6_get_xdg_surface(c->shell.zxdg, data->surface);
icculus@11848
   566
        /* !!! FIXME: add popup role */
icculus@11848
   567
        data->shell_surface.zxdg.roleobj.toplevel = zxdg_surface_v6_get_toplevel(data->shell_surface.zxdg.surface);
icculus@11848
   568
        zxdg_toplevel_v6_add_listener(data->shell_surface.zxdg.roleobj.toplevel, &toplevel_listener_zxdg, data);
icculus@11848
   569
        zxdg_toplevel_v6_set_app_id(data->shell_surface.zxdg.roleobj.toplevel, c->classname);
icculus@11848
   570
    } else {
icculus@11848
   571
        data->shell_surface.wl = wl_shell_get_shell_surface(c->shell.wl, data->surface);
icculus@11848
   572
        wl_shell_surface_set_class(data->shell_surface.wl, c->classname);
icculus@11848
   573
    }
icculus@11848
   574
m@10614
   575
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
gabomdq@8082
   576
    if (c->surface_extension) {
gabomdq@8082
   577
        data->extended_surface = qt_surface_extension_get_extended_surface(
gabomdq@8082
   578
                c->surface_extension, data->surface);
m@10614
   579
m@10614
   580
        QtExtendedSurface_Subscribe(data->extended_surface, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION);
m@10614
   581
        QtExtendedSurface_Subscribe(data->extended_surface, SDL_HINT_QTWAYLAND_WINDOW_FLAGS);
gabomdq@8082
   582
    }
gabomdq@8082
   583
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
m@8712
   584
gabomdq@8104
   585
    data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
gabomdq@8062
   586
                                            window->w, window->h);
gabomdq@8062
   587
gabomdq@8062
   588
    /* Create the GLES window surface */
gabomdq@8062
   589
    data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
gabomdq@8062
   590
    
gabomdq@8062
   591
    if (data->egl_surface == EGL_NO_SURFACE) {
philipp@9543
   592
        return SDL_SetError("failed to create a window surface");
gabomdq@8062
   593
    }
gabomdq@8062
   594
icculus@12033
   595
    if (c->shell.xdg) {
icculus@12033
   596
        if (data->shell_surface.xdg.surface) {
icculus@12033
   597
            xdg_surface_set_user_data(data->shell_surface.xdg.surface, data);
icculus@12033
   598
            xdg_surface_add_listener(data->shell_surface.xdg.surface, &shell_surface_listener_xdg, data);
icculus@12033
   599
        }
icculus@12033
   600
    } else if (c->shell.zxdg) {
icculus@11848
   601
        if (data->shell_surface.zxdg.surface) {
icculus@11848
   602
            zxdg_surface_v6_set_user_data(data->shell_surface.zxdg.surface, data);
icculus@11848
   603
            zxdg_surface_v6_add_listener(data->shell_surface.zxdg.surface, &shell_surface_listener_zxdg, data);
icculus@11848
   604
        }
icculus@11848
   605
    } else {
icculus@11848
   606
        if (data->shell_surface.wl) {
icculus@11848
   607
            wl_shell_surface_set_user_data(data->shell_surface.wl, data);
icculus@11848
   608
            wl_shell_surface_add_listener(data->shell_surface.wl, &shell_surface_listener_wl, data);
icculus@11848
   609
        }
gabomdq@8062
   610
    }
gabomdq@8062
   611
gabomdq@8082
   612
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
gabomdq@8082
   613
    if (data->extended_surface) {
gabomdq@8082
   614
        qt_extended_surface_set_user_data(data->extended_surface, data);
gabomdq@8082
   615
        qt_extended_surface_add_listener(data->extended_surface,
gabomdq@8082
   616
                                         &extended_surface_listener, data);
gabomdq@8082
   617
    }
gabomdq@8082
   618
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
gabomdq@8082
   619
icculus@12367
   620
    if (c->kwin_server_decoration_manager) {
icculus@12367
   621
        data->kwin_server_decoration = org_kde_kwin_server_decoration_manager_create(c->kwin_server_decoration_manager, data->surface);
icculus@12367
   622
        if (data->kwin_server_decoration) {
icculus@12367
   623
            const SDL_bool bordered = (window->flags & SDL_WINDOW_BORDERLESS) == 0;
icculus@12367
   624
            const enum org_kde_kwin_server_decoration_mode mode = bordered ? ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_SERVER : ORG_KDE_KWIN_SERVER_DECORATION_MANAGER_MODE_NONE;
icculus@12367
   625
            org_kde_kwin_server_decoration_request_mode(data->kwin_server_decoration, mode);
icculus@12367
   626
        }
icculus@12367
   627
    }
icculus@12367
   628
gabomdq@8062
   629
    region = wl_compositor_create_region(c->compositor);
gabomdq@8062
   630
    wl_region_add(region, 0, 0, window->w, window->h);
gabomdq@8062
   631
    wl_surface_set_opaque_region(data->surface, region);
gabomdq@8062
   632
    wl_region_destroy(region);
gabomdq@8062
   633
slouken@10304
   634
    if (c->relative_mouse_mode) {
slouken@10304
   635
        Wayland_input_lock_pointer(c->input);
slouken@10304
   636
    }
slouken@10304
   637
icculus@11848
   638
    wl_surface_commit(data->surface);
gabomdq@8104
   639
    WAYLAND_wl_display_flush(c->display);
gabomdq@8062
   640
icculus@11944
   641
    /* we have to wait until the surface gets a "configure" event, or
icculus@11944
   642
       use of this surface will fail. This is a new rule for xdg_shell. */
icculus@12033
   643
    if (c->shell.xdg) {
icculus@12033
   644
        if (data->shell_surface.xdg.surface) {
icculus@12033
   645
            while (!data->shell_surface.xdg.initial_configure_seen) {
icculus@12033
   646
                WAYLAND_wl_display_flush(c->display);
icculus@12033
   647
                WAYLAND_wl_display_dispatch(c->display);
icculus@12033
   648
            }
icculus@12033
   649
        }
icculus@12033
   650
    } else if (c->shell.zxdg) {
icculus@11944
   651
        if (data->shell_surface.zxdg.surface) {
icculus@11944
   652
            while (!data->shell_surface.zxdg.initial_configure_seen) {
icculus@11944
   653
                WAYLAND_wl_display_flush(c->display);
icculus@11944
   654
                WAYLAND_wl_display_dispatch(c->display);
icculus@11944
   655
            }
icculus@11944
   656
        }
icculus@11944
   657
    }
icculus@11944
   658
gabomdq@8062
   659
    return 0;
gabomdq@8062
   660
}
gabomdq@8062
   661
gabomdq@8062
   662
void Wayland_SetWindowSize(_THIS, SDL_Window * window)
gabomdq@8062
   663
{
gabomdq@8062
   664
    SDL_VideoData *data = _this->driverdata;
gabomdq@8062
   665
    SDL_WindowData *wind = window->driverdata;
gabomdq@8062
   666
    struct wl_region *region;
gabomdq@8062
   667
gabomdq@8104
   668
    WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
gabomdq@8062
   669
gabomdq@8104
   670
    region =wl_compositor_create_region(data->compositor);
gabomdq@8062
   671
    wl_region_add(region, 0, 0, window->w, window->h);
gabomdq@8062
   672
    wl_surface_set_opaque_region(wind->surface, region);
gabomdq@8062
   673
    wl_region_destroy(region);
gabomdq@8062
   674
}
gabomdq@8062
   675
slouken@10492
   676
void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
slouken@10492
   677
{
slouken@10492
   678
    SDL_WindowData *wind = window->driverdata;
icculus@11848
   679
    SDL_VideoData *viddata = (SDL_VideoData *) _this->driverdata;
slouken@10492
   680
    
slouken@10492
   681
    if (window->title != NULL) {
icculus@12033
   682
        if (viddata->shell.xdg) {
icculus@12033
   683
            xdg_toplevel_set_title(wind->shell_surface.xdg.roleobj.toplevel, window->title);
icculus@12033
   684
        } else if (viddata->shell.zxdg) {
icculus@11848
   685
            zxdg_toplevel_v6_set_title(wind->shell_surface.zxdg.roleobj.toplevel, window->title);
icculus@11848
   686
        } else {
icculus@11848
   687
            wl_shell_surface_set_title(wind->shell_surface.wl, window->title);
icculus@11848
   688
        }
slouken@10492
   689
    }
slouken@10492
   690
slouken@10492
   691
    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
slouken@10492
   692
}
slouken@10492
   693
gabomdq@8062
   694
void Wayland_DestroyWindow(_THIS, SDL_Window *window)
gabomdq@8062
   695
{
gabomdq@8062
   696
    SDL_VideoData *data = _this->driverdata;
gabomdq@8062
   697
    SDL_WindowData *wind = window->driverdata;
gabomdq@8062
   698
gabomdq@8062
   699
    if (data) {
gabomdq@8062
   700
        SDL_EGL_DestroySurface(_this, wind->egl_surface);
gabomdq@8104
   701
        WAYLAND_wl_egl_window_destroy(wind->egl_window);
gabomdq@8062
   702
icculus@12367
   703
        if (wind->kwin_server_decoration) {
icculus@12367
   704
            org_kde_kwin_server_decoration_release(wind->kwin_server_decoration);
icculus@12367
   705
        }
icculus@12367
   706
icculus@12033
   707
        if (data->shell.xdg) {
icculus@12033
   708
            if (wind->shell_surface.xdg.roleobj.toplevel) {
icculus@12033
   709
                xdg_toplevel_destroy(wind->shell_surface.xdg.roleobj.toplevel);
icculus@12033
   710
            }
icculus@12033
   711
            if (wind->shell_surface.zxdg.surface) {
icculus@12033
   712
                xdg_surface_destroy(wind->shell_surface.xdg.surface);
icculus@12033
   713
            }
icculus@12033
   714
        } else if (data->shell.zxdg) {
icculus@11848
   715
            if (wind->shell_surface.zxdg.roleobj.toplevel) {
icculus@11848
   716
                zxdg_toplevel_v6_destroy(wind->shell_surface.zxdg.roleobj.toplevel);
icculus@11848
   717
            }
icculus@11848
   718
            if (wind->shell_surface.zxdg.surface) {
icculus@11848
   719
                zxdg_surface_v6_destroy(wind->shell_surface.zxdg.surface);
icculus@11848
   720
            }
icculus@11848
   721
        } else {
icculus@11848
   722
            if (wind->shell_surface.wl) {
icculus@11848
   723
                wl_shell_surface_destroy(wind->shell_surface.wl);
icculus@11848
   724
            }
icculus@11848
   725
        }
gabomdq@8062
   726
gabomdq@8082
   727
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
m@10614
   728
        if (wind->extended_surface) {
m@10614
   729
            QtExtendedSurface_Unsubscribe(wind->extended_surface, SDL_HINT_QTWAYLAND_CONTENT_ORIENTATION);
m@10614
   730
            QtExtendedSurface_Unsubscribe(wind->extended_surface, SDL_HINT_QTWAYLAND_WINDOW_FLAGS);
gabomdq@8082
   731
            qt_extended_surface_destroy(wind->extended_surface);
m@10614
   732
        }
gabomdq@8082
   733
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
gabomdq@8062
   734
        wl_surface_destroy(wind->surface);
gabomdq@8062
   735
gabomdq@8062
   736
        SDL_free(wind);
gabomdq@8104
   737
        WAYLAND_wl_display_flush(data->display);
gabomdq@8062
   738
    }
slouken@8978
   739
    window->driverdata = NULL;
gabomdq@8062
   740
}
gabomdq@8062
   741
icculus@8116
   742
#endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */
icculus@8116
   743
gabomdq@8062
   744
/* vi: set ts=4 sw=4 expandtab: */