src/video/wayland/SDL_waylandvideo.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 26 May 2015 06:27:46 -0700
changeset 9619 b94b6d0bff0f
parent 9554 879f71e1478b
child 9998 f67cf37e9cd4
permissions -rw-r--r--
Updated the copyright year to 2015
gabomdq@8062
     1
/*
gabomdq@8062
     2
  Simple DirectMedia Layer
slouken@9619
     3
  Copyright (C) 1997-2015 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
icculus@8116
    25
gabomdq@8062
    26
#include "SDL_video.h"
gabomdq@8062
    27
#include "SDL_mouse.h"
gabomdq@8104
    28
#include "SDL_stdinc.h"
gabomdq@8062
    29
#include "../../events/SDL_events_c.h"
gabomdq@8062
    30
gabomdq@8062
    31
#include "SDL_waylandvideo.h"
gabomdq@8062
    32
#include "SDL_waylandevents_c.h"
gabomdq@8062
    33
#include "SDL_waylandwindow.h"
gabomdq@8062
    34
#include "SDL_waylandopengles.h"
gabomdq@8062
    35
#include "SDL_waylandmouse.h"
gabomdq@8082
    36
#include "SDL_waylandtouch.h"
gabomdq@8062
    37
gabomdq@8062
    38
#include <fcntl.h>
gabomdq@8062
    39
#include <xkbcommon/xkbcommon.h>
gabomdq@8062
    40
gabomdq@8104
    41
#include "SDL_waylanddyn.h"
gabomdq@8104
    42
#include <wayland-util.h>
gabomdq@8104
    43
gabomdq@8062
    44
#define WAYLANDVID_DRIVER_NAME "wayland"
gabomdq@8062
    45
gabomdq@8062
    46
/* Initialization/Query functions */
gabomdq@8062
    47
static int
gabomdq@8062
    48
Wayland_VideoInit(_THIS);
gabomdq@8062
    49
gabomdq@8062
    50
static void
gabomdq@8062
    51
Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display);
gabomdq@8062
    52
static int
gabomdq@8062
    53
Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
gabomdq@8062
    54
gabomdq@8062
    55
static void
gabomdq@8062
    56
Wayland_VideoQuit(_THIS);
gabomdq@8062
    57
gabomdq@8062
    58
/* Wayland driver bootstrap functions */
gabomdq@8062
    59
static int
gabomdq@8062
    60
Wayland_Available(void)
gabomdq@8062
    61
{
gabomdq@8062
    62
    struct wl_display *display = NULL;
gabomdq@8104
    63
    if (SDL_WAYLAND_LoadSymbols()) {
gabomdq@8104
    64
        display = WAYLAND_wl_display_connect(NULL);
gabomdq@8104
    65
        if (display != NULL) {
gabomdq@8104
    66
            WAYLAND_wl_display_disconnect(display);
gabomdq@8104
    67
        }
gabomdq@8104
    68
        SDL_WAYLAND_UnloadSymbols();
gabomdq@8062
    69
    }
gabomdq@8062
    70
gabomdq@8062
    71
    return (display != NULL);
gabomdq@8062
    72
}
gabomdq@8062
    73
gabomdq@8062
    74
static void
gabomdq@8062
    75
Wayland_DeleteDevice(SDL_VideoDevice *device)
gabomdq@8062
    76
{
gabomdq@8062
    77
    SDL_free(device);
gabomdq@8104
    78
    SDL_WAYLAND_UnloadSymbols();
gabomdq@8062
    79
}
gabomdq@8062
    80
gabomdq@8062
    81
static SDL_VideoDevice *
gabomdq@8062
    82
Wayland_CreateDevice(int devindex)
gabomdq@8062
    83
{
gabomdq@8062
    84
    SDL_VideoDevice *device;
linkmauve@9467
    85
gabomdq@8104
    86
    if (!SDL_WAYLAND_LoadSymbols()) {
gabomdq@8104
    87
        return NULL;
gabomdq@8104
    88
    }
gabomdq@8062
    89
gabomdq@8062
    90
    /* Initialize all variables that we clean on shutdown */
gabomdq@8062
    91
    device = SDL_calloc(1, sizeof(SDL_VideoDevice));
gabomdq@8062
    92
    if (!device) {
icculus@8160
    93
        SDL_WAYLAND_UnloadSymbols();
gabomdq@8062
    94
        SDL_OutOfMemory();
gabomdq@8062
    95
        return NULL;
gabomdq@8062
    96
    }
gabomdq@8062
    97
gabomdq@8062
    98
    /* Set the function pointers */
gabomdq@8062
    99
    device->VideoInit = Wayland_VideoInit;
gabomdq@8062
   100
    device->VideoQuit = Wayland_VideoQuit;
gabomdq@8062
   101
    device->SetDisplayMode = Wayland_SetDisplayMode;
gabomdq@8062
   102
    device->GetDisplayModes = Wayland_GetDisplayModes;
gabomdq@8062
   103
    device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
gabomdq@8062
   104
gabomdq@8062
   105
    device->PumpEvents = Wayland_PumpEvents;
gabomdq@8062
   106
gabomdq@8062
   107
    device->GL_SwapWindow = Wayland_GLES_SwapWindow;
gabomdq@8062
   108
    device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval;
gabomdq@8062
   109
    device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval;
gabomdq@8062
   110
    device->GL_MakeCurrent = Wayland_GLES_MakeCurrent;
gabomdq@8062
   111
    device->GL_CreateContext = Wayland_GLES_CreateContext;
gabomdq@8062
   112
    device->GL_LoadLibrary = Wayland_GLES_LoadLibrary;
gabomdq@8062
   113
    device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary;
gabomdq@8062
   114
    device->GL_GetProcAddress = Wayland_GLES_GetProcAddress;
gabomdq@8062
   115
    device->GL_DeleteContext = Wayland_GLES_DeleteContext;
gabomdq@8062
   116
gabomdq@8062
   117
    device->CreateWindow = Wayland_CreateWindow;
gabomdq@8062
   118
    device->ShowWindow = Wayland_ShowWindow;
gabomdq@8062
   119
    device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
gabomdq@8062
   120
    device->SetWindowSize = Wayland_SetWindowSize;
gabomdq@8062
   121
    device->DestroyWindow = Wayland_DestroyWindow;
icculus@9554
   122
    device->SetWindowHitTest = Wayland_SetWindowHitTest;
gabomdq@8062
   123
gabomdq@8062
   124
    device->free = Wayland_DeleteDevice;
gabomdq@8062
   125
gabomdq@8062
   126
    return device;
gabomdq@8062
   127
}
gabomdq@8062
   128
gabomdq@8062
   129
VideoBootStrap Wayland_bootstrap = {
gabomdq@8062
   130
    WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
gabomdq@8062
   131
    Wayland_Available, Wayland_CreateDevice
gabomdq@8062
   132
};
gabomdq@8062
   133
gabomdq@8062
   134
static void
gabomdq@8062
   135
display_handle_geometry(void *data,
gabomdq@8062
   136
                        struct wl_output *output,
gabomdq@8062
   137
                        int x, int y,
gabomdq@8062
   138
                        int physical_width,
gabomdq@8062
   139
                        int physical_height,
gabomdq@8062
   140
                        int subpixel,
gabomdq@8062
   141
                        const char *make,
gabomdq@8062
   142
                        const char *model,
gabomdq@8062
   143
                        int transform)
gabomdq@8062
   144
gabomdq@8062
   145
{
linkmauve@9467
   146
    SDL_VideoDisplay *display = data;
gabomdq@8062
   147
linkmauve@9467
   148
    display->name = strdup(model);
linkmauve@9467
   149
    display->driverdata = output;
gabomdq@8062
   150
}
gabomdq@8062
   151
gabomdq@8062
   152
static void
gabomdq@8062
   153
display_handle_mode(void *data,
linkmauve@9467
   154
                    struct wl_output *output,
gabomdq@8062
   155
                    uint32_t flags,
gabomdq@8062
   156
                    int width,
gabomdq@8062
   157
                    int height,
gabomdq@8062
   158
                    int refresh)
gabomdq@8062
   159
{
linkmauve@9467
   160
    SDL_VideoDisplay *display = data;
gabomdq@8062
   161
    SDL_DisplayMode mode;
gabomdq@8062
   162
gabomdq@8062
   163
    SDL_zero(mode);
gabomdq@8062
   164
    mode.w = width;
gabomdq@8062
   165
    mode.h = height;
linkmauve@9467
   166
    mode.refresh_rate = refresh / 1000; // mHz to Hz
linkmauve@9467
   167
    SDL_AddDisplayMode(display, &mode);
gabomdq@8062
   168
gabomdq@8062
   169
    if (flags & WL_OUTPUT_MODE_CURRENT) {
linkmauve@9467
   170
        display->current_mode = mode;
linkmauve@9467
   171
        display->desktop_mode = mode;
gabomdq@8062
   172
    }
gabomdq@8062
   173
}
gabomdq@8062
   174
linkmauve@9467
   175
static void
linkmauve@9467
   176
display_handle_done(void *data,
linkmauve@9467
   177
                    struct wl_output *output)
linkmauve@9467
   178
{
linkmauve@9467
   179
    SDL_VideoDisplay *display = data;
linkmauve@9467
   180
    SDL_AddVideoDisplay(display);
linkmauve@9467
   181
    SDL_free(display->name);
linkmauve@9467
   182
    SDL_free(display);
linkmauve@9467
   183
}
linkmauve@9467
   184
linkmauve@9467
   185
static void
linkmauve@9467
   186
display_handle_scale(void *data,
linkmauve@9467
   187
                     struct wl_output *output,
linkmauve@9467
   188
                     int32_t factor)
linkmauve@9467
   189
{
linkmauve@9467
   190
    // TODO: do HiDPI stuff.
linkmauve@9467
   191
}
linkmauve@9467
   192
gabomdq@8062
   193
static const struct wl_output_listener output_listener = {
gabomdq@8062
   194
    display_handle_geometry,
linkmauve@9467
   195
    display_handle_mode,
linkmauve@9467
   196
    display_handle_done,
linkmauve@9467
   197
    display_handle_scale
gabomdq@8062
   198
};
gabomdq@8062
   199
gabomdq@8062
   200
static void
linkmauve@9467
   201
Wayland_add_display(SDL_VideoData *d, uint32_t id)
gabomdq@8062
   202
{
icculus@9472
   203
    struct wl_output *output;
linkmauve@9467
   204
    SDL_VideoDisplay *display = SDL_malloc(sizeof *display);
linkmauve@9467
   205
    if (!display) {
linkmauve@9467
   206
        SDL_OutOfMemory();
linkmauve@9467
   207
        return;
linkmauve@9467
   208
    }
linkmauve@9467
   209
    SDL_zero(*display);
gabomdq@8062
   210
icculus@9472
   211
    output = wl_registry_bind(d->registry, id, &wl_output_interface, 2);
linkmauve@9467
   212
    if (!output) {
linkmauve@9467
   213
        SDL_SetError("Failed to retrieve output.");
linkmauve@9467
   214
        return;
linkmauve@9467
   215
    }
linkmauve@9467
   216
linkmauve@9467
   217
    wl_output_add_listener(output, &output_listener, display);
gabomdq@8062
   218
}
gabomdq@8062
   219
gabomdq@8082
   220
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
gabomdq@8082
   221
static void
gabomdq@8082
   222
windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager,
gabomdq@8082
   223
        int32_t show_is_fullscreen)
gabomdq@8082
   224
{
gabomdq@8082
   225
}
gabomdq@8082
   226
gabomdq@8082
   227
static void
gabomdq@8082
   228
windowmanager_quit(void *data, struct qt_windowmanager *qt_windowmanager)
gabomdq@8082
   229
{
gabomdq@8082
   230
    SDL_SendQuit();
gabomdq@8082
   231
}
gabomdq@8082
   232
gabomdq@8082
   233
static const struct qt_windowmanager_listener windowmanager_listener = {
gabomdq@8082
   234
    windowmanager_hints,
gabomdq@8082
   235
    windowmanager_quit,
gabomdq@8082
   236
};
gabomdq@8082
   237
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
gabomdq@8082
   238
gabomdq@8062
   239
static void
gabomdq@8062
   240
display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
linkmauve@9467
   241
                      const char *interface, uint32_t version)
gabomdq@8062
   242
{
gabomdq@8062
   243
    SDL_VideoData *d = data;
linkmauve@9467
   244
gabomdq@8062
   245
    if (strcmp(interface, "wl_compositor") == 0) {
gabomdq@8062
   246
        d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
gabomdq@8062
   247
    } else if (strcmp(interface, "wl_output") == 0) {
linkmauve@9467
   248
        Wayland_add_display(d, id);
gabomdq@8062
   249
    } else if (strcmp(interface, "wl_seat") == 0) {
gabomdq@8062
   250
        Wayland_display_add_input(d, id);
gabomdq@8062
   251
    } else if (strcmp(interface, "wl_shell") == 0) {
gabomdq@8062
   252
        d->shell = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
gabomdq@8062
   253
    } else if (strcmp(interface, "wl_shm") == 0) {
gabomdq@8062
   254
        d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
gabomdq@8104
   255
        d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm);
gabomdq@8104
   256
        d->default_cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
linkmauve@9467
   257
gabomdq@8082
   258
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
gabomdq@8082
   259
    } else if (strcmp(interface, "qt_touch_extension") == 0) {
gabomdq@8082
   260
        Wayland_touch_create(d, id);
gabomdq@8082
   261
    } else if (strcmp(interface, "qt_surface_extension") == 0) {
gabomdq@8082
   262
        d->surface_extension = wl_registry_bind(registry, id,
gabomdq@8082
   263
                &qt_surface_extension_interface, 1);
gabomdq@8082
   264
    } else if (strcmp(interface, "qt_windowmanager") == 0) {
gabomdq@8082
   265
        d->windowmanager = wl_registry_bind(registry, id,
gabomdq@8082
   266
                &qt_windowmanager_interface, 1);
gabomdq@8082
   267
        qt_windowmanager_add_listener(d->windowmanager, &windowmanager_listener, d);
gabomdq@8082
   268
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
gabomdq@8062
   269
    }
gabomdq@8062
   270
}
gabomdq@8062
   271
gabomdq@8062
   272
static const struct wl_registry_listener registry_listener = {
linkmauve@9467
   273
    display_handle_global
gabomdq@8062
   274
};
gabomdq@8062
   275
gabomdq@8062
   276
int
gabomdq@8062
   277
Wayland_VideoInit(_THIS)
gabomdq@8062
   278
{
linkmauve@9467
   279
    SDL_VideoData *data = SDL_malloc(sizeof *data);
gabomdq@8062
   280
    if (data == NULL)
philipp@9484
   281
        return SDL_OutOfMemory();
gabomdq@8062
   282
    memset(data, 0, sizeof *data);
gabomdq@8062
   283
gabomdq@8062
   284
    _this->driverdata = data;
gabomdq@8062
   285
gabomdq@8104
   286
    data->display = WAYLAND_wl_display_connect(NULL);
gabomdq@8062
   287
    if (data->display == NULL) {
philipp@9484
   288
        return SDL_SetError("Failed to connect to a Wayland display");
gabomdq@8062
   289
    }
gabomdq@8062
   290
gabomdq@8062
   291
    data->registry = wl_display_get_registry(data->display);
linkmauve@9467
   292
    if (data->registry == NULL) {
philipp@9484
   293
        return SDL_SetError("Failed to get the Wayland registry");
gabomdq@8104
   294
    }
linkmauve@9467
   295
gabomdq@8062
   296
    wl_registry_add_listener(data->registry, &registry_listener, data);
gabomdq@8062
   297
linkmauve@9467
   298
    // First roundtrip to receive all registry objects.
icculus@9476
   299
    WAYLAND_wl_display_roundtrip(data->display);
linkmauve@9467
   300
linkmauve@9467
   301
    // Second roundtrip to receive all output events.
icculus@9476
   302
    WAYLAND_wl_display_roundtrip(data->display);
gabomdq@8062
   303
gabomdq@8104
   304
    data->xkb_context = WAYLAND_xkb_context_new(0);
gabomdq@8062
   305
    if (!data->xkb_context) {
philipp@9484
   306
        return SDL_SetError("Failed to create XKB context");
gabomdq@8062
   307
    }
gabomdq@8062
   308
linkmauve@9467
   309
    Wayland_InitMouse();
gabomdq@8062
   310
gabomdq@8104
   311
    WAYLAND_wl_display_flush(data->display);
gabomdq@8062
   312
gabomdq@8062
   313
    return 0;
gabomdq@8062
   314
}
gabomdq@8062
   315
gabomdq@8062
   316
static void
gabomdq@8062
   317
Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
gabomdq@8062
   318
{
linkmauve@9467
   319
    // Nothing to do here, everything was already done in the wl_output
linkmauve@9467
   320
    // callbacks.
gabomdq@8062
   321
}
gabomdq@8062
   322
gabomdq@8062
   323
static int
gabomdq@8062
   324
Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
gabomdq@8062
   325
{
icculus@9469
   326
    return SDL_Unsupported();
gabomdq@8062
   327
}
gabomdq@8062
   328
gabomdq@8062
   329
void
gabomdq@8062
   330
Wayland_VideoQuit(_THIS)
gabomdq@8062
   331
{
gabomdq@8062
   332
    SDL_VideoData *data = _this->driverdata;
linkmauve@9467
   333
    int i;
gabomdq@8062
   334
gabomdq@8062
   335
    Wayland_FiniMouse ();
gabomdq@8062
   336
linkmauve@9467
   337
    for (i = 0; i < _this->num_displays; ++i) {
linkmauve@9467
   338
        SDL_VideoDisplay *display = &_this->displays[i];
linkmauve@9467
   339
        wl_output_destroy(display->driverdata);
linkmauve@9467
   340
        display->driverdata = NULL;
linkmauve@9467
   341
    }
gabomdq@8062
   342
gabomdq@8062
   343
    Wayland_display_destroy_input(data);
gabomdq@8062
   344
gabomdq@8062
   345
    if (data->xkb_context) {
gabomdq@8104
   346
        WAYLAND_xkb_context_unref(data->xkb_context);
gabomdq@8062
   347
        data->xkb_context = NULL;
gabomdq@8062
   348
    }
gabomdq@8082
   349
#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
gabomdq@8082
   350
    if (data->windowmanager)
gabomdq@8082
   351
        qt_windowmanager_destroy(data->windowmanager);
gabomdq@8082
   352
gabomdq@8082
   353
    if (data->surface_extension)
gabomdq@8082
   354
        qt_surface_extension_destroy(data->surface_extension);
gabomdq@8082
   355
gabomdq@8082
   356
    Wayland_touch_destroy(data);
gabomdq@8082
   357
#endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */
gabomdq@8062
   358
gabomdq@8062
   359
    if (data->shm)
gabomdq@8062
   360
        wl_shm_destroy(data->shm);
gabomdq@8062
   361
gabomdq@8062
   362
    if (data->cursor_theme)
gabomdq@8104
   363
        WAYLAND_wl_cursor_theme_destroy(data->cursor_theme);
gabomdq@8062
   364
gabomdq@8062
   365
    if (data->shell)
gabomdq@8062
   366
        wl_shell_destroy(data->shell);
gabomdq@8062
   367
gabomdq@8062
   368
    if (data->compositor)
gabomdq@8062
   369
        wl_compositor_destroy(data->compositor);
gabomdq@8062
   370
linkmauve@9467
   371
    if (data->registry)
linkmauve@9467
   372
        wl_registry_destroy(data->registry);
linkmauve@9467
   373
gabomdq@8062
   374
    if (data->display) {
gabomdq@8104
   375
        WAYLAND_wl_display_flush(data->display);
gabomdq@8104
   376
        WAYLAND_wl_display_disconnect(data->display);
gabomdq@8062
   377
    }
gabomdq@8062
   378
gabomdq@8062
   379
    free(data);
gabomdq@8062
   380
    _this->driverdata = NULL;
gabomdq@8062
   381
}
gabomdq@8062
   382
icculus@8116
   383
#endif /* SDL_VIDEO_DRIVER_WAYLAND */
icculus@8116
   384
gabomdq@8062
   385
/* vi: set ts=4 sw=4 expandtab: */