src/video/wayland/SDL_waylandvideo.c
changeset 8062 4fc5f66d63cc
child 8082 5b83ad3f01ac
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/video/wayland/SDL_waylandvideo.c	Sat Dec 14 20:18:43 2013 -0300
     1.3 @@ -0,0 +1,365 @@
     1.4 +/*
     1.5 +  Simple DirectMedia Layer
     1.6 +  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     1.7 +
     1.8 +  This software is provided 'as-is', without any express or implied
     1.9 +  warranty.  In no event will the authors be held liable for any damages
    1.10 +  arising from the use of this software.
    1.11 +
    1.12 +  Permission is granted to anyone to use this software for any purpose,
    1.13 +  including commercial applications, and to alter it and redistribute it
    1.14 +  freely, subject to the following restrictions:
    1.15 +
    1.16 +  1. The origin of this software must not be misrepresented; you must not
    1.17 +     claim that you wrote the original software. If you use this software
    1.18 +     in a product, an acknowledgment in the product documentation would be
    1.19 +     appreciated but is not required.
    1.20 +  2. Altered source versions must be plainly marked as such, and must not be
    1.21 +     misrepresented as being the original software.
    1.22 +  3. This notice may not be removed or altered from any source distribution.
    1.23 +*/
    1.24 +
    1.25 +#include "SDL_config.h"
    1.26 +
    1.27 +#include "SDL_video.h"
    1.28 +#include "SDL_mouse.h"
    1.29 +#include "../../events/SDL_events_c.h"
    1.30 +
    1.31 +#include "SDL_waylandvideo.h"
    1.32 +#include "SDL_waylandevents_c.h"
    1.33 +#include "SDL_waylandwindow.h"
    1.34 +#include "SDL_waylandopengles.h"
    1.35 +#include "SDL_waylandmouse.h"
    1.36 +
    1.37 +#include <fcntl.h>
    1.38 +#include <xkbcommon/xkbcommon.h>
    1.39 +
    1.40 +#define WAYLANDVID_DRIVER_NAME "wayland"
    1.41 +
    1.42 +struct wayland_mode {
    1.43 +    SDL_DisplayMode mode;
    1.44 +    struct wl_list link;
    1.45 +};
    1.46 +
    1.47 +/* Initialization/Query functions */
    1.48 +static int
    1.49 +Wayland_VideoInit(_THIS);
    1.50 +
    1.51 +static void
    1.52 +Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display);
    1.53 +static int
    1.54 +Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
    1.55 +
    1.56 +static void
    1.57 +Wayland_VideoQuit(_THIS);
    1.58 +
    1.59 +/* Wayland driver bootstrap functions */
    1.60 +static int
    1.61 +Wayland_Available(void)
    1.62 +{
    1.63 +    struct wl_display *display = NULL;
    1.64 +
    1.65 +    display = wl_display_connect(NULL);
    1.66 +    if (display != NULL) {
    1.67 +        wl_display_disconnect(display);
    1.68 +    }
    1.69 +
    1.70 +    return (display != NULL);
    1.71 +}
    1.72 +
    1.73 +static void
    1.74 +Wayland_DeleteDevice(SDL_VideoDevice *device)
    1.75 +{
    1.76 +    SDL_free(device);
    1.77 +}
    1.78 +
    1.79 +static SDL_VideoDevice *
    1.80 +Wayland_CreateDevice(int devindex)
    1.81 +{
    1.82 +    SDL_VideoDevice *device;
    1.83 +
    1.84 +    /* Initialize all variables that we clean on shutdown */
    1.85 +    device = SDL_calloc(1, sizeof(SDL_VideoDevice));
    1.86 +    if (!device) {
    1.87 +        SDL_OutOfMemory();
    1.88 +        return NULL;
    1.89 +    }
    1.90 +
    1.91 +    /* Set the function pointers */
    1.92 +    device->VideoInit = Wayland_VideoInit;
    1.93 +    device->VideoQuit = Wayland_VideoQuit;
    1.94 +    device->SetDisplayMode = Wayland_SetDisplayMode;
    1.95 +    device->GetDisplayModes = Wayland_GetDisplayModes;
    1.96 +    device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
    1.97 +
    1.98 +    device->PumpEvents = Wayland_PumpEvents;
    1.99 +
   1.100 +    device->GL_SwapWindow = Wayland_GLES_SwapWindow;
   1.101 +    device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval;
   1.102 +    device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval;
   1.103 +    device->GL_MakeCurrent = Wayland_GLES_MakeCurrent;
   1.104 +    device->GL_CreateContext = Wayland_GLES_CreateContext;
   1.105 +    device->GL_LoadLibrary = Wayland_GLES_LoadLibrary;
   1.106 +    device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary;
   1.107 +    device->GL_GetProcAddress = Wayland_GLES_GetProcAddress;
   1.108 +    device->GL_DeleteContext = Wayland_GLES_DeleteContext;
   1.109 +
   1.110 +    device->CreateWindow = Wayland_CreateWindow;
   1.111 +    device->ShowWindow = Wayland_ShowWindow;
   1.112 +    device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
   1.113 +    device->SetWindowSize = Wayland_SetWindowSize;
   1.114 +    device->DestroyWindow = Wayland_DestroyWindow;
   1.115 +
   1.116 +    device->free = Wayland_DeleteDevice;
   1.117 +
   1.118 +    return device;
   1.119 +}
   1.120 +
   1.121 +VideoBootStrap Wayland_bootstrap = {
   1.122 +    WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
   1.123 +    Wayland_Available, Wayland_CreateDevice
   1.124 +};
   1.125 +
   1.126 +static void
   1.127 +wayland_add_mode(SDL_VideoData *d, SDL_DisplayMode m)
   1.128 +{
   1.129 +    struct wayland_mode *mode;
   1.130 +
   1.131 +    /* Check for duplicate mode */
   1.132 +    wl_list_for_each(mode, &d->modes_list, link)
   1.133 +        if (mode->mode.w == m.w && mode->mode.h == m.h &&
   1.134 +	    mode->mode.refresh_rate == m.refresh_rate)
   1.135 +	    return;
   1.136 +
   1.137 +    /* Add new mode to the list */
   1.138 +    mode = SDL_calloc(1, sizeof *mode);
   1.139 +
   1.140 +    if (!mode)
   1.141 +	return;
   1.142 +
   1.143 +    mode->mode = m;
   1.144 +    wl_list_insert(&d->modes_list, &mode->link);
   1.145 +}
   1.146 +
   1.147 +static void
   1.148 +display_handle_geometry(void *data,
   1.149 +                        struct wl_output *output,
   1.150 +                        int x, int y,
   1.151 +                        int physical_width,
   1.152 +                        int physical_height,
   1.153 +                        int subpixel,
   1.154 +                        const char *make,
   1.155 +                        const char *model,
   1.156 +                        int transform)
   1.157 +
   1.158 +{
   1.159 +    SDL_VideoData *d = data;
   1.160 +
   1.161 +    d->screen_allocation.x = x;
   1.162 +    d->screen_allocation.y = y;
   1.163 +}
   1.164 +
   1.165 +static void
   1.166 +display_handle_mode(void *data,
   1.167 +                    struct wl_output *wl_output,
   1.168 +                    uint32_t flags,
   1.169 +                    int width,
   1.170 +                    int height,
   1.171 +                    int refresh)
   1.172 +{
   1.173 +    SDL_VideoData *d = data;
   1.174 +    SDL_DisplayMode mode;
   1.175 +
   1.176 +    SDL_zero(mode);
   1.177 +    mode.w = width;
   1.178 +    mode.h = height;
   1.179 +    mode.refresh_rate = refresh / 1000;
   1.180 +
   1.181 +    wayland_add_mode(d, mode);
   1.182 +
   1.183 +    if (flags & WL_OUTPUT_MODE_CURRENT) {
   1.184 +        d->screen_allocation.width = width;
   1.185 +        d->screen_allocation.height = height;
   1.186 +    }
   1.187 +}
   1.188 +
   1.189 +static const struct wl_output_listener output_listener = {
   1.190 +    display_handle_geometry,
   1.191 +    display_handle_mode
   1.192 +};
   1.193 +
   1.194 +static void
   1.195 +shm_handle_format(void *data,
   1.196 +                  struct wl_shm *shm,
   1.197 +                  uint32_t format)
   1.198 +{
   1.199 +    SDL_VideoData *d = data;
   1.200 +
   1.201 +    d->shm_formats |= (1 << format);
   1.202 +}
   1.203 +
   1.204 +static const struct wl_shm_listener shm_listener = {
   1.205 +    shm_handle_format
   1.206 +};
   1.207 +
   1.208 +static void
   1.209 +display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
   1.210 +					const char *interface, uint32_t version)
   1.211 +{
   1.212 +    SDL_VideoData *d = data;
   1.213 +
   1.214 +    if (strcmp(interface, "wl_compositor") == 0) {
   1.215 +        d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
   1.216 +    } else if (strcmp(interface, "wl_output") == 0) {
   1.217 +        d->output = wl_registry_bind(d->registry, id, &wl_output_interface, 1);
   1.218 +        wl_output_add_listener(d->output, &output_listener, d);
   1.219 +    } else if (strcmp(interface, "wl_seat") == 0) {
   1.220 +        Wayland_display_add_input(d, id);
   1.221 +    } else if (strcmp(interface, "wl_shell") == 0) {
   1.222 +        d->shell = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
   1.223 +    } else if (strcmp(interface, "wl_shm") == 0) {
   1.224 +        d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
   1.225 +        d->cursor_theme = wl_cursor_theme_load(NULL, 32, d->shm);
   1.226 +        d->default_cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
   1.227 +        wl_shm_add_listener(d->shm, &shm_listener, d);
   1.228 +    }
   1.229 +}
   1.230 +
   1.231 +static const struct wl_registry_listener registry_listener = {
   1.232 +	display_handle_global
   1.233 +};
   1.234 +
   1.235 +int
   1.236 +Wayland_VideoInit(_THIS)
   1.237 +{
   1.238 +    SDL_VideoData *data;
   1.239 +
   1.240 +    data = malloc(sizeof *data);
   1.241 +    if (data == NULL)
   1.242 +        return 0;
   1.243 +    memset(data, 0, sizeof *data);
   1.244 +
   1.245 +    _this->driverdata = data;
   1.246 +
   1.247 +    wl_list_init(&data->modes_list);
   1.248 +    
   1.249 +    data->display = wl_display_connect(NULL);
   1.250 +    if (data->display == NULL) {
   1.251 +        SDL_SetError("Failed to connect to a Wayland display");
   1.252 +        return 0;
   1.253 +    }
   1.254 +
   1.255 +    data->registry = wl_display_get_registry(data->display);
   1.256 +    wl_registry_add_listener(data->registry, &registry_listener, data);
   1.257 +
   1.258 +    while (data->screen_allocation.width == 0)
   1.259 +        wl_display_dispatch(data->display);
   1.260 +
   1.261 +    data->xkb_context = xkb_context_new(0);
   1.262 +    if (!data->xkb_context) {
   1.263 +        SDL_SetError("Failed to create XKB context");
   1.264 +        return 0;
   1.265 +    }
   1.266 +
   1.267 +    SDL_VideoDisplay display;
   1.268 +    SDL_DisplayMode mode;
   1.269 +
   1.270 +    /* Use a fake 32-bpp desktop mode */
   1.271 +    mode.format = SDL_PIXELFORMAT_RGB888;
   1.272 +    mode.w = data->screen_allocation.width;
   1.273 +    mode.h = data->screen_allocation.height;
   1.274 +    mode.refresh_rate = 0;
   1.275 +    mode.driverdata = NULL;
   1.276 +    wayland_add_mode(data, mode);
   1.277 +    SDL_zero(display);
   1.278 +    display.desktop_mode = mode;
   1.279 +    display.current_mode = mode;
   1.280 +    display.driverdata = NULL;
   1.281 +    SDL_AddVideoDisplay(&display);
   1.282 +
   1.283 +    Wayland_InitMouse ();
   1.284 +
   1.285 +    wayland_schedule_write(data);
   1.286 +
   1.287 +    return 0;
   1.288 +}
   1.289 +
   1.290 +static void
   1.291 +Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
   1.292 +{
   1.293 +    SDL_VideoData *data = _this->driverdata;
   1.294 +    SDL_DisplayMode mode;
   1.295 +    struct wayland_mode *m;
   1.296 +
   1.297 +    Wayland_PumpEvents(_this);
   1.298 +
   1.299 +    wl_list_for_each(m, &data->modes_list, link) {
   1.300 +        m->mode.format = SDL_PIXELFORMAT_RGB888;
   1.301 +        SDL_AddDisplayMode(sdl_display, &m->mode);
   1.302 +        m->mode.format = SDL_PIXELFORMAT_RGBA8888;
   1.303 +        SDL_AddDisplayMode(sdl_display, &m->mode);
   1.304 +    }
   1.305 +
   1.306 +    mode.w = data->screen_allocation.width;
   1.307 +    mode.h = data->screen_allocation.height;
   1.308 +    mode.refresh_rate = 0;
   1.309 +    mode.driverdata = NULL;
   1.310 +
   1.311 +    mode.format = SDL_PIXELFORMAT_RGB888;
   1.312 +    SDL_AddDisplayMode(sdl_display, &mode);
   1.313 +    mode.format = SDL_PIXELFORMAT_RGBA8888;
   1.314 +    SDL_AddDisplayMode(sdl_display, &mode);
   1.315 +}
   1.316 +
   1.317 +static int
   1.318 +Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
   1.319 +{
   1.320 +    return 0;
   1.321 +}
   1.322 +
   1.323 +void
   1.324 +Wayland_VideoQuit(_THIS)
   1.325 +{
   1.326 +    SDL_VideoData *data = _this->driverdata;
   1.327 +    struct wayland_mode *t, *m;
   1.328 +
   1.329 +    Wayland_FiniMouse ();
   1.330 +
   1.331 +    if (data->output)
   1.332 +        wl_output_destroy(data->output);
   1.333 +
   1.334 +    Wayland_display_destroy_input(data);
   1.335 +
   1.336 +    if (data->xkb_context) {
   1.337 +        xkb_context_unref(data->xkb_context);
   1.338 +        data->xkb_context = NULL;
   1.339 +    }
   1.340 +
   1.341 +    if (data->shm)
   1.342 +        wl_shm_destroy(data->shm);
   1.343 +
   1.344 +    if (data->cursor_theme)
   1.345 +        wl_cursor_theme_destroy(data->cursor_theme);
   1.346 +
   1.347 +    if (data->shell)
   1.348 +        wl_shell_destroy(data->shell);
   1.349 +
   1.350 +    if (data->compositor)
   1.351 +        wl_compositor_destroy(data->compositor);
   1.352 +
   1.353 +    if (data->display) {
   1.354 +        wl_display_flush(data->display);
   1.355 +        wl_display_disconnect(data->display);
   1.356 +    }
   1.357 +    
   1.358 +    wl_list_for_each_safe(m, t, &data->modes_list, link) {
   1.359 +        wl_list_remove(&m->link);
   1.360 +        free(m);
   1.361 +    }
   1.362 +
   1.363 +
   1.364 +    free(data);
   1.365 +    _this->driverdata = NULL;
   1.366 +}
   1.367 +
   1.368 +/* vi: set ts=4 sw=4 expandtab: */