src/video/wayland/SDL_waylandwindow.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 07 Oct 2016 18:11:03 -0700
changeset 10492 786e10ab72d8
parent 10304 ee83e0b4a36f
child 10614 63c2c6c8762c
permissions -rw-r--r--
Fixed bug 3063 - Wayland: SDL resizes EGL surface to 0x0.

x414e54

Wayland will sometimes send empty resize events (0 width and 0 height) to the client. I have not worked out the exact conditions a client would receive these but I can assume it might be if the window is offscreen or not mapped yet.

This causes issues with some SDL clients as they receive the 0x0 event and unexpected resize event or might not request to resize back to the correct size.

As per the wl_shell Wayland spec configure events are only a suggestion and the client is free to ignore or pick a different size (this is how min/max and fixed aspect ratio is supped to be implemented).

A patch is attached but is just the first iteration and I will fix any issues such as checking for FULLSCREEN/MAXIMIZED or RESIZABLE flags unless someone else fixes this first.

I have update to take into account non resizable and fullscreen windows. Also adding in maximize/restore and title functions for Wayland.
gabomdq@8062
     1
/*
gabomdq@8062
     2
  Simple DirectMedia Layer
slouken@9998
     3
  Copyright (C) 1997-2016 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"
gabomdq@8062
    34
gabomdq@8062
    35
static void
gabomdq@8062
    36
handle_ping(void *data, struct wl_shell_surface *shell_surface,
gabomdq@8062
    37
            uint32_t serial)
gabomdq@8062
    38
{
gabomdq@8062
    39
    wl_shell_surface_pong(shell_surface, serial);
gabomdq@8062
    40
}
gabomdq@8062
    41
gabomdq@8062
    42
static void
gabomdq@8062
    43
handle_configure(void *data, struct wl_shell_surface *shell_surface,
gabomdq@8062
    44
                 uint32_t edges, int32_t width, int32_t height)
gabomdq@8062
    45
{
gabomdq@8766
    46
    SDL_WindowData *wind = (SDL_WindowData *)data;
gabomdq@8766
    47
    SDL_Window *window = wind->sdlwindow;
gabomdq@8766
    48
    struct wl_region *region;
gabomdq@8766
    49
slouken@10492
    50
    /* wl_shell_surface spec states that this is a suggestion.
slouken@10492
    51
       Ignore if less than or greater than max/min size. */
slouken@10492
    52
slouken@10492
    53
    if (width == 0 || height == 0) {
slouken@10492
    54
        return;
slouken@10492
    55
    }
slouken@10492
    56
slouken@10492
    57
    if (!(window->flags & SDL_WINDOW_FULLSCREEN)) {
slouken@10492
    58
        if ((window->flags & SDL_WINDOW_RESIZABLE)) {
slouken@10492
    59
            if (window->max_w > 0) {
slouken@10492
    60
                width = SDL_min(width, window->max_w);
slouken@10492
    61
            } 
slouken@10492
    62
            width = SDL_max(width, window->min_w);
slouken@10492
    63
slouken@10492
    64
            if (window->max_h > 0) {
slouken@10492
    65
                height = SDL_min(height, window->max_h);
slouken@10492
    66
            }
slouken@10492
    67
            height = SDL_max(height, window->min_h);
slouken@10492
    68
        } else {
slouken@10492
    69
            return;
slouken@10492
    70
        }
slouken@10492
    71
    }
slouken@10492
    72
slouken@10492
    73
    if (width == window->w && height == window->h) {
slouken@10492
    74
        return;
slouken@10492
    75
    }
slouken@10492
    76
gabomdq@8766
    77
    window->w = width;
gabomdq@8766
    78
    window->h = height;
gabomdq@8766
    79
    WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
gabomdq@8766
    80
gabomdq@8766
    81
    region = wl_compositor_create_region(wind->waylandData->compositor);
gabomdq@8766
    82
    wl_region_add(region, 0, 0, window->w, window->h);
gabomdq@8766
    83
    wl_surface_set_opaque_region(wind->surface, region);
gabomdq@8766
    84
    wl_region_destroy(region);
gabomdq@8766
    85
    SDL_SendWindowEvent(window, SDL_WINDOWEVENT_RESIZED, window->w, window->h);
gabomdq@8062
    86
}
gabomdq@8062
    87
gabomdq@8062
    88
static void
gabomdq@8062
    89
handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
gabomdq@8062
    90
{
gabomdq@8062
    91
}
gabomdq@8062
    92
gabomdq@8062
    93
static const struct wl_shell_surface_listener shell_surface_listener = {
gabomdq@8062
    94
    handle_ping,
gabomdq@8062
    95
    handle_configure,
gabomdq@8062
    96
    handle_popup_done
gabomdq@8062
    97
};
gabomdq@8062
    98
gabomdq@8082
    99
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
gabomdq@8082
   100
static void
gabomdq@8082
   101
handle_onscreen_visibility(void *data,
gabomdq@8082
   102
        struct qt_extended_surface *qt_extended_surface, int32_t visible)
gabomdq@8082
   103
{
gabomdq@8082
   104
}
gabomdq@8082
   105
gabomdq@8082
   106
static void
gabomdq@8082
   107
handle_set_generic_property(void *data,
gabomdq@8082
   108
        struct qt_extended_surface *qt_extended_surface, const char *name,
gabomdq@8082
   109
        struct wl_array *value)
gabomdq@8082
   110
{
gabomdq@8082
   111
}
gabomdq@8082
   112
gabomdq@8082
   113
static void
gabomdq@8082
   114
handle_close(void *data, struct qt_extended_surface *qt_extended_surface)
gabomdq@8082
   115
{
gabomdq@8082
   116
    SDL_WindowData *window = (SDL_WindowData *)data;
gabomdq@8082
   117
    SDL_SendWindowEvent(window->sdlwindow, SDL_WINDOWEVENT_CLOSE, 0, 0);
gabomdq@8082
   118
}
gabomdq@8082
   119
gabomdq@8082
   120
static const struct qt_extended_surface_listener extended_surface_listener = {
gabomdq@8082
   121
    handle_onscreen_visibility,
gabomdq@8082
   122
    handle_set_generic_property,
gabomdq@8082
   123
    handle_close,
gabomdq@8082
   124
};
gabomdq@8082
   125
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
gabomdq@8082
   126
gabomdq@8062
   127
SDL_bool
gabomdq@8062
   128
Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
gabomdq@8062
   129
{
gabomdq@8062
   130
    SDL_WindowData *data = (SDL_WindowData *) window->driverdata;
gabomdq@8062
   131
gabomdq@8062
   132
    info->info.wl.display = data->waylandData->display;
gabomdq@8062
   133
    info->info.wl.surface = data->surface;
gabomdq@8062
   134
    info->info.wl.shell_surface = data->shell_surface;
gabomdq@8062
   135
    info->subsystem = SDL_SYSWM_WAYLAND;
gabomdq@8062
   136
gabomdq@8062
   137
    return SDL_TRUE;
gabomdq@8062
   138
}
gabomdq@8062
   139
icculus@9554
   140
int
icculus@9554
   141
Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
icculus@9554
   142
{
icculus@9554
   143
    return 0;  /* just succeed, the real work is done elsewhere. */
icculus@9554
   144
}
icculus@9554
   145
gabomdq@8062
   146
void Wayland_ShowWindow(_THIS, SDL_Window *window)
gabomdq@8062
   147
{
gabomdq@8062
   148
    SDL_WindowData *wind = window->driverdata;
gabomdq@8062
   149
gabomdq@8062
   150
    if (window->flags & SDL_WINDOW_FULLSCREEN)
gabomdq@8062
   151
        wl_shell_surface_set_fullscreen(wind->shell_surface,
gabomdq@8062
   152
                                        WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
linkmauve@9468
   153
                                        0, (struct wl_output *)window->fullscreen_mode.driverdata);
gabomdq@8062
   154
    else
gabomdq@8062
   155
        wl_shell_surface_set_toplevel(wind->shell_surface);
gabomdq@8062
   156
gabomdq@8104
   157
    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
gabomdq@8062
   158
}
gabomdq@8062
   159
gabomdq@8062
   160
void
gabomdq@8062
   161
Wayland_SetWindowFullscreen(_THIS, SDL_Window * window,
gabomdq@8062
   162
                            SDL_VideoDisplay * _display, SDL_bool fullscreen)
gabomdq@8062
   163
{
gabomdq@8062
   164
    SDL_WindowData *wind = window->driverdata;
gabomdq@8062
   165
gabomdq@8062
   166
    if (fullscreen)
gabomdq@8062
   167
        wl_shell_surface_set_fullscreen(wind->shell_surface,
gabomdq@8062
   168
                                        WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE,
linkmauve@9468
   169
                                        0, (struct wl_output *)_display->driverdata);
gabomdq@8062
   170
    else
gabomdq@8062
   171
        wl_shell_surface_set_toplevel(wind->shell_surface);
gabomdq@8062
   172
gabomdq@8104
   173
    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
gabomdq@8062
   174
}
gabomdq@8062
   175
slouken@10492
   176
void
slouken@10492
   177
Wayland_RestoreWindow(_THIS, SDL_Window * window)
slouken@10492
   178
{
slouken@10492
   179
    SDL_WindowData *wind = window->driverdata;
slouken@10492
   180
slouken@10492
   181
    wl_shell_surface_set_toplevel(wind->shell_surface);
slouken@10492
   182
slouken@10492
   183
    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
slouken@10492
   184
}
slouken@10492
   185
slouken@10492
   186
void
slouken@10492
   187
Wayland_MaximizeWindow(_THIS, SDL_Window * window)
slouken@10492
   188
{
slouken@10492
   189
    SDL_WindowData *wind = window->driverdata;
slouken@10492
   190
slouken@10492
   191
    wl_shell_surface_set_maximized(wind->shell_surface, NULL);
slouken@10492
   192
slouken@10492
   193
    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
slouken@10492
   194
}
slouken@10492
   195
gabomdq@8062
   196
int Wayland_CreateWindow(_THIS, SDL_Window *window)
gabomdq@8062
   197
{
gabomdq@8062
   198
    SDL_WindowData *data;
gabomdq@8062
   199
    SDL_VideoData *c;
gabomdq@8062
   200
    struct wl_region *region;
gabomdq@8062
   201
gabomdq@8062
   202
    data = calloc(1, sizeof *data);
gabomdq@8062
   203
    if (data == NULL)
philipp@9483
   204
        return SDL_OutOfMemory();
gabomdq@8062
   205
gabomdq@8062
   206
    c = _this->driverdata;
gabomdq@8062
   207
    window->driverdata = data;
gabomdq@8062
   208
gabomdq@8062
   209
    if (!(window->flags & SDL_WINDOW_OPENGL)) {
gabomdq@8062
   210
        SDL_GL_LoadLibrary(NULL);
gabomdq@8062
   211
        window->flags |= SDL_WINDOW_OPENGL;
gabomdq@8062
   212
    }
gabomdq@8062
   213
gabomdq@8062
   214
    if (window->x == SDL_WINDOWPOS_UNDEFINED) {
gabomdq@8062
   215
        window->x = 0;
gabomdq@8062
   216
    }
gabomdq@8062
   217
    if (window->y == SDL_WINDOWPOS_UNDEFINED) {
gabomdq@8062
   218
        window->y = 0;
gabomdq@8062
   219
    }
gabomdq@8062
   220
gabomdq@8062
   221
    data->waylandData = c;
gabomdq@8062
   222
    data->sdlwindow = window;
gabomdq@8062
   223
gabomdq@8062
   224
    data->surface =
gabomdq@8062
   225
        wl_compositor_create_surface(c->compositor);
gabomdq@8062
   226
    wl_surface_set_user_data(data->surface, data);
gabomdq@8062
   227
    data->shell_surface = wl_shell_get_shell_surface(c->shell,
gabomdq@8062
   228
                                                     data->surface);
hadess@10302
   229
    wl_shell_surface_set_class (data->shell_surface, c->classname);
gabomdq@8082
   230
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH    
gabomdq@8082
   231
    if (c->surface_extension) {
gabomdq@8082
   232
        data->extended_surface = qt_surface_extension_get_extended_surface(
gabomdq@8082
   233
                c->surface_extension, data->surface);
gabomdq@8082
   234
    }
gabomdq@8082
   235
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
m@8712
   236
gabomdq@8104
   237
    data->egl_window = WAYLAND_wl_egl_window_create(data->surface,
gabomdq@8062
   238
                                            window->w, window->h);
gabomdq@8062
   239
gabomdq@8062
   240
    /* Create the GLES window surface */
gabomdq@8062
   241
    data->egl_surface = SDL_EGL_CreateSurface(_this, (NativeWindowType) data->egl_window);
gabomdq@8062
   242
    
gabomdq@8062
   243
    if (data->egl_surface == EGL_NO_SURFACE) {
philipp@9543
   244
        return SDL_SetError("failed to create a window surface");
gabomdq@8062
   245
    }
gabomdq@8062
   246
gabomdq@8062
   247
    if (data->shell_surface) {
gabomdq@8062
   248
        wl_shell_surface_set_user_data(data->shell_surface, data);
gabomdq@8062
   249
        wl_shell_surface_add_listener(data->shell_surface,
gabomdq@8062
   250
                                      &shell_surface_listener, data);
gabomdq@8062
   251
    }
gabomdq@8062
   252
gabomdq@8082
   253
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
gabomdq@8082
   254
    if (data->extended_surface) {
gabomdq@8082
   255
        qt_extended_surface_set_user_data(data->extended_surface, data);
gabomdq@8082
   256
        qt_extended_surface_add_listener(data->extended_surface,
gabomdq@8082
   257
                                         &extended_surface_listener, data);
gabomdq@8082
   258
    }
gabomdq@8082
   259
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
gabomdq@8082
   260
gabomdq@8062
   261
    region = wl_compositor_create_region(c->compositor);
gabomdq@8062
   262
    wl_region_add(region, 0, 0, window->w, window->h);
gabomdq@8062
   263
    wl_surface_set_opaque_region(data->surface, region);
gabomdq@8062
   264
    wl_region_destroy(region);
gabomdq@8062
   265
slouken@10304
   266
    if (c->relative_mouse_mode) {
slouken@10304
   267
        Wayland_input_lock_pointer(c->input);
slouken@10304
   268
    }
slouken@10304
   269
gabomdq@8104
   270
    WAYLAND_wl_display_flush(c->display);
gabomdq@8062
   271
gabomdq@8062
   272
    return 0;
gabomdq@8062
   273
}
gabomdq@8062
   274
gabomdq@8062
   275
void Wayland_SetWindowSize(_THIS, SDL_Window * window)
gabomdq@8062
   276
{
gabomdq@8062
   277
    SDL_VideoData *data = _this->driverdata;
gabomdq@8062
   278
    SDL_WindowData *wind = window->driverdata;
gabomdq@8062
   279
    struct wl_region *region;
gabomdq@8062
   280
gabomdq@8104
   281
    WAYLAND_wl_egl_window_resize(wind->egl_window, window->w, window->h, 0, 0);
gabomdq@8062
   282
gabomdq@8104
   283
    region =wl_compositor_create_region(data->compositor);
gabomdq@8062
   284
    wl_region_add(region, 0, 0, window->w, window->h);
gabomdq@8062
   285
    wl_surface_set_opaque_region(wind->surface, region);
gabomdq@8062
   286
    wl_region_destroy(region);
gabomdq@8062
   287
}
gabomdq@8062
   288
slouken@10492
   289
void Wayland_SetWindowTitle(_THIS, SDL_Window * window)
slouken@10492
   290
{
slouken@10492
   291
    SDL_WindowData *wind = window->driverdata;
slouken@10492
   292
    
slouken@10492
   293
    if (window->title != NULL) {
slouken@10492
   294
        wl_shell_surface_set_title(wind->shell_surface, window->title);
slouken@10492
   295
    }
slouken@10492
   296
slouken@10492
   297
    WAYLAND_wl_display_flush( ((SDL_VideoData*)_this->driverdata)->display );
slouken@10492
   298
}
slouken@10492
   299
gabomdq@8062
   300
void Wayland_DestroyWindow(_THIS, SDL_Window *window)
gabomdq@8062
   301
{
gabomdq@8062
   302
    SDL_VideoData *data = _this->driverdata;
gabomdq@8062
   303
    SDL_WindowData *wind = window->driverdata;
gabomdq@8062
   304
gabomdq@8062
   305
    if (data) {
gabomdq@8062
   306
        SDL_EGL_DestroySurface(_this, wind->egl_surface);
gabomdq@8104
   307
        WAYLAND_wl_egl_window_destroy(wind->egl_window);
gabomdq@8062
   308
gabomdq@8062
   309
        if (wind->shell_surface)
gabomdq@8062
   310
            wl_shell_surface_destroy(wind->shell_surface);
gabomdq@8062
   311
gabomdq@8082
   312
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
gabomdq@8082
   313
        if (wind->extended_surface)
gabomdq@8082
   314
            qt_extended_surface_destroy(wind->extended_surface);
gabomdq@8082
   315
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
gabomdq@8062
   316
        wl_surface_destroy(wind->surface);
gabomdq@8062
   317
gabomdq@8062
   318
        SDL_free(wind);
gabomdq@8104
   319
        WAYLAND_wl_display_flush(data->display);
gabomdq@8062
   320
    }
slouken@8978
   321
    window->driverdata = NULL;
gabomdq@8062
   322
}
gabomdq@8062
   323
icculus@8116
   324
#endif /* SDL_VIDEO_DRIVER_WAYLAND && SDL_VIDEO_OPENGL_EGL */
icculus@8116
   325
gabomdq@8062
   326
/* vi: set ts=4 sw=4 expandtab: */