src/video/wayland/SDL_waylandvideo.c
changeset 8062 4fc5f66d63cc
child 8082 5b83ad3f01ac
equal deleted inserted replaced
8061:a5f8137ccf01 8062:4fc5f66d63cc
       
     1 /*
       
     2   Simple DirectMedia Layer
       
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
       
     4 
       
     5   This software is provided 'as-is', without any express or implied
       
     6   warranty.  In no event will the authors be held liable for any damages
       
     7   arising from the use of this software.
       
     8 
       
     9   Permission is granted to anyone to use this software for any purpose,
       
    10   including commercial applications, and to alter it and redistribute it
       
    11   freely, subject to the following restrictions:
       
    12 
       
    13   1. The origin of this software must not be misrepresented; you must not
       
    14      claim that you wrote the original software. If you use this software
       
    15      in a product, an acknowledgment in the product documentation would be
       
    16      appreciated but is not required.
       
    17   2. Altered source versions must be plainly marked as such, and must not be
       
    18      misrepresented as being the original software.
       
    19   3. This notice may not be removed or altered from any source distribution.
       
    20 */
       
    21 
       
    22 #include "SDL_config.h"
       
    23 
       
    24 #include "SDL_video.h"
       
    25 #include "SDL_mouse.h"
       
    26 #include "../../events/SDL_events_c.h"
       
    27 
       
    28 #include "SDL_waylandvideo.h"
       
    29 #include "SDL_waylandevents_c.h"
       
    30 #include "SDL_waylandwindow.h"
       
    31 #include "SDL_waylandopengles.h"
       
    32 #include "SDL_waylandmouse.h"
       
    33 
       
    34 #include <fcntl.h>
       
    35 #include <xkbcommon/xkbcommon.h>
       
    36 
       
    37 #define WAYLANDVID_DRIVER_NAME "wayland"
       
    38 
       
    39 struct wayland_mode {
       
    40     SDL_DisplayMode mode;
       
    41     struct wl_list link;
       
    42 };
       
    43 
       
    44 /* Initialization/Query functions */
       
    45 static int
       
    46 Wayland_VideoInit(_THIS);
       
    47 
       
    48 static void
       
    49 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display);
       
    50 static int
       
    51 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode);
       
    52 
       
    53 static void
       
    54 Wayland_VideoQuit(_THIS);
       
    55 
       
    56 /* Wayland driver bootstrap functions */
       
    57 static int
       
    58 Wayland_Available(void)
       
    59 {
       
    60     struct wl_display *display = NULL;
       
    61 
       
    62     display = wl_display_connect(NULL);
       
    63     if (display != NULL) {
       
    64         wl_display_disconnect(display);
       
    65     }
       
    66 
       
    67     return (display != NULL);
       
    68 }
       
    69 
       
    70 static void
       
    71 Wayland_DeleteDevice(SDL_VideoDevice *device)
       
    72 {
       
    73     SDL_free(device);
       
    74 }
       
    75 
       
    76 static SDL_VideoDevice *
       
    77 Wayland_CreateDevice(int devindex)
       
    78 {
       
    79     SDL_VideoDevice *device;
       
    80 
       
    81     /* Initialize all variables that we clean on shutdown */
       
    82     device = SDL_calloc(1, sizeof(SDL_VideoDevice));
       
    83     if (!device) {
       
    84         SDL_OutOfMemory();
       
    85         return NULL;
       
    86     }
       
    87 
       
    88     /* Set the function pointers */
       
    89     device->VideoInit = Wayland_VideoInit;
       
    90     device->VideoQuit = Wayland_VideoQuit;
       
    91     device->SetDisplayMode = Wayland_SetDisplayMode;
       
    92     device->GetDisplayModes = Wayland_GetDisplayModes;
       
    93     device->GetWindowWMInfo = Wayland_GetWindowWMInfo;
       
    94 
       
    95     device->PumpEvents = Wayland_PumpEvents;
       
    96 
       
    97     device->GL_SwapWindow = Wayland_GLES_SwapWindow;
       
    98     device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval;
       
    99     device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval;
       
   100     device->GL_MakeCurrent = Wayland_GLES_MakeCurrent;
       
   101     device->GL_CreateContext = Wayland_GLES_CreateContext;
       
   102     device->GL_LoadLibrary = Wayland_GLES_LoadLibrary;
       
   103     device->GL_UnloadLibrary = Wayland_GLES_UnloadLibrary;
       
   104     device->GL_GetProcAddress = Wayland_GLES_GetProcAddress;
       
   105     device->GL_DeleteContext = Wayland_GLES_DeleteContext;
       
   106 
       
   107     device->CreateWindow = Wayland_CreateWindow;
       
   108     device->ShowWindow = Wayland_ShowWindow;
       
   109     device->SetWindowFullscreen = Wayland_SetWindowFullscreen;
       
   110     device->SetWindowSize = Wayland_SetWindowSize;
       
   111     device->DestroyWindow = Wayland_DestroyWindow;
       
   112 
       
   113     device->free = Wayland_DeleteDevice;
       
   114 
       
   115     return device;
       
   116 }
       
   117 
       
   118 VideoBootStrap Wayland_bootstrap = {
       
   119     WAYLANDVID_DRIVER_NAME, "SDL Wayland video driver",
       
   120     Wayland_Available, Wayland_CreateDevice
       
   121 };
       
   122 
       
   123 static void
       
   124 wayland_add_mode(SDL_VideoData *d, SDL_DisplayMode m)
       
   125 {
       
   126     struct wayland_mode *mode;
       
   127 
       
   128     /* Check for duplicate mode */
       
   129     wl_list_for_each(mode, &d->modes_list, link)
       
   130         if (mode->mode.w == m.w && mode->mode.h == m.h &&
       
   131 	    mode->mode.refresh_rate == m.refresh_rate)
       
   132 	    return;
       
   133 
       
   134     /* Add new mode to the list */
       
   135     mode = SDL_calloc(1, sizeof *mode);
       
   136 
       
   137     if (!mode)
       
   138 	return;
       
   139 
       
   140     mode->mode = m;
       
   141     wl_list_insert(&d->modes_list, &mode->link);
       
   142 }
       
   143 
       
   144 static void
       
   145 display_handle_geometry(void *data,
       
   146                         struct wl_output *output,
       
   147                         int x, int y,
       
   148                         int physical_width,
       
   149                         int physical_height,
       
   150                         int subpixel,
       
   151                         const char *make,
       
   152                         const char *model,
       
   153                         int transform)
       
   154 
       
   155 {
       
   156     SDL_VideoData *d = data;
       
   157 
       
   158     d->screen_allocation.x = x;
       
   159     d->screen_allocation.y = y;
       
   160 }
       
   161 
       
   162 static void
       
   163 display_handle_mode(void *data,
       
   164                     struct wl_output *wl_output,
       
   165                     uint32_t flags,
       
   166                     int width,
       
   167                     int height,
       
   168                     int refresh)
       
   169 {
       
   170     SDL_VideoData *d = data;
       
   171     SDL_DisplayMode mode;
       
   172 
       
   173     SDL_zero(mode);
       
   174     mode.w = width;
       
   175     mode.h = height;
       
   176     mode.refresh_rate = refresh / 1000;
       
   177 
       
   178     wayland_add_mode(d, mode);
       
   179 
       
   180     if (flags & WL_OUTPUT_MODE_CURRENT) {
       
   181         d->screen_allocation.width = width;
       
   182         d->screen_allocation.height = height;
       
   183     }
       
   184 }
       
   185 
       
   186 static const struct wl_output_listener output_listener = {
       
   187     display_handle_geometry,
       
   188     display_handle_mode
       
   189 };
       
   190 
       
   191 static void
       
   192 shm_handle_format(void *data,
       
   193                   struct wl_shm *shm,
       
   194                   uint32_t format)
       
   195 {
       
   196     SDL_VideoData *d = data;
       
   197 
       
   198     d->shm_formats |= (1 << format);
       
   199 }
       
   200 
       
   201 static const struct wl_shm_listener shm_listener = {
       
   202     shm_handle_format
       
   203 };
       
   204 
       
   205 static void
       
   206 display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
       
   207 					const char *interface, uint32_t version)
       
   208 {
       
   209     SDL_VideoData *d = data;
       
   210 
       
   211     if (strcmp(interface, "wl_compositor") == 0) {
       
   212         d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1);
       
   213     } else if (strcmp(interface, "wl_output") == 0) {
       
   214         d->output = wl_registry_bind(d->registry, id, &wl_output_interface, 1);
       
   215         wl_output_add_listener(d->output, &output_listener, d);
       
   216     } else if (strcmp(interface, "wl_seat") == 0) {
       
   217         Wayland_display_add_input(d, id);
       
   218     } else if (strcmp(interface, "wl_shell") == 0) {
       
   219         d->shell = wl_registry_bind(d->registry, id, &wl_shell_interface, 1);
       
   220     } else if (strcmp(interface, "wl_shm") == 0) {
       
   221         d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
       
   222         d->cursor_theme = wl_cursor_theme_load(NULL, 32, d->shm);
       
   223         d->default_cursor = wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
       
   224         wl_shm_add_listener(d->shm, &shm_listener, d);
       
   225     }
       
   226 }
       
   227 
       
   228 static const struct wl_registry_listener registry_listener = {
       
   229 	display_handle_global
       
   230 };
       
   231 
       
   232 int
       
   233 Wayland_VideoInit(_THIS)
       
   234 {
       
   235     SDL_VideoData *data;
       
   236 
       
   237     data = malloc(sizeof *data);
       
   238     if (data == NULL)
       
   239         return 0;
       
   240     memset(data, 0, sizeof *data);
       
   241 
       
   242     _this->driverdata = data;
       
   243 
       
   244     wl_list_init(&data->modes_list);
       
   245     
       
   246     data->display = wl_display_connect(NULL);
       
   247     if (data->display == NULL) {
       
   248         SDL_SetError("Failed to connect to a Wayland display");
       
   249         return 0;
       
   250     }
       
   251 
       
   252     data->registry = wl_display_get_registry(data->display);
       
   253     wl_registry_add_listener(data->registry, &registry_listener, data);
       
   254 
       
   255     while (data->screen_allocation.width == 0)
       
   256         wl_display_dispatch(data->display);
       
   257 
       
   258     data->xkb_context = xkb_context_new(0);
       
   259     if (!data->xkb_context) {
       
   260         SDL_SetError("Failed to create XKB context");
       
   261         return 0;
       
   262     }
       
   263 
       
   264     SDL_VideoDisplay display;
       
   265     SDL_DisplayMode mode;
       
   266 
       
   267     /* Use a fake 32-bpp desktop mode */
       
   268     mode.format = SDL_PIXELFORMAT_RGB888;
       
   269     mode.w = data->screen_allocation.width;
       
   270     mode.h = data->screen_allocation.height;
       
   271     mode.refresh_rate = 0;
       
   272     mode.driverdata = NULL;
       
   273     wayland_add_mode(data, mode);
       
   274     SDL_zero(display);
       
   275     display.desktop_mode = mode;
       
   276     display.current_mode = mode;
       
   277     display.driverdata = NULL;
       
   278     SDL_AddVideoDisplay(&display);
       
   279 
       
   280     Wayland_InitMouse ();
       
   281 
       
   282     wayland_schedule_write(data);
       
   283 
       
   284     return 0;
       
   285 }
       
   286 
       
   287 static void
       
   288 Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display)
       
   289 {
       
   290     SDL_VideoData *data = _this->driverdata;
       
   291     SDL_DisplayMode mode;
       
   292     struct wayland_mode *m;
       
   293 
       
   294     Wayland_PumpEvents(_this);
       
   295 
       
   296     wl_list_for_each(m, &data->modes_list, link) {
       
   297         m->mode.format = SDL_PIXELFORMAT_RGB888;
       
   298         SDL_AddDisplayMode(sdl_display, &m->mode);
       
   299         m->mode.format = SDL_PIXELFORMAT_RGBA8888;
       
   300         SDL_AddDisplayMode(sdl_display, &m->mode);
       
   301     }
       
   302 
       
   303     mode.w = data->screen_allocation.width;
       
   304     mode.h = data->screen_allocation.height;
       
   305     mode.refresh_rate = 0;
       
   306     mode.driverdata = NULL;
       
   307 
       
   308     mode.format = SDL_PIXELFORMAT_RGB888;
       
   309     SDL_AddDisplayMode(sdl_display, &mode);
       
   310     mode.format = SDL_PIXELFORMAT_RGBA8888;
       
   311     SDL_AddDisplayMode(sdl_display, &mode);
       
   312 }
       
   313 
       
   314 static int
       
   315 Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode)
       
   316 {
       
   317     return 0;
       
   318 }
       
   319 
       
   320 void
       
   321 Wayland_VideoQuit(_THIS)
       
   322 {
       
   323     SDL_VideoData *data = _this->driverdata;
       
   324     struct wayland_mode *t, *m;
       
   325 
       
   326     Wayland_FiniMouse ();
       
   327 
       
   328     if (data->output)
       
   329         wl_output_destroy(data->output);
       
   330 
       
   331     Wayland_display_destroy_input(data);
       
   332 
       
   333     if (data->xkb_context) {
       
   334         xkb_context_unref(data->xkb_context);
       
   335         data->xkb_context = NULL;
       
   336     }
       
   337 
       
   338     if (data->shm)
       
   339         wl_shm_destroy(data->shm);
       
   340 
       
   341     if (data->cursor_theme)
       
   342         wl_cursor_theme_destroy(data->cursor_theme);
       
   343 
       
   344     if (data->shell)
       
   345         wl_shell_destroy(data->shell);
       
   346 
       
   347     if (data->compositor)
       
   348         wl_compositor_destroy(data->compositor);
       
   349 
       
   350     if (data->display) {
       
   351         wl_display_flush(data->display);
       
   352         wl_display_disconnect(data->display);
       
   353     }
       
   354     
       
   355     wl_list_for_each_safe(m, t, &data->modes_list, link) {
       
   356         wl_list_remove(&m->link);
       
   357         free(m);
       
   358     }
       
   359 
       
   360 
       
   361     free(data);
       
   362     _this->driverdata = NULL;
       
   363 }
       
   364 
       
   365 /* vi: set ts=4 sw=4 expandtab: */