# HG changeset patch # User Dmitry Cherkassov # Date 1417800340 -10800 # Fri Dec 05 20:25:40 2014 +0300 # Node ID 82f6d5196c2d48a7abdfa19b3a1ba97d1f471b28 # Parent f6355bfca853ce54e754673303975cbe269e1243 [Video/Wayland] This patch add multiple wayland display outputs. Output number can be specified for fullscreen windows via SDL_WINDOWPOS_CENTERED_DISPLAY(X) option in SDL_CreateWindow diff -r f6355bfca853 -r 82f6d5196c2d src/video/SDL_sysvideo.h --- a/src/video/SDL_sysvideo.h Thu Dec 04 21:41:30 2014 +0100 +++ b/src/video/SDL_sysvideo.h Fri Dec 05 20:25:40 2014 +0300 @@ -130,6 +130,7 @@ SDL_VideoDevice *device; + void *outputdata; /* driver-specific display output data */ void *driverdata; }; @@ -401,6 +402,8 @@ extern SDL_bool SDL_AddDisplayMode(SDL_VideoDisplay *display, const SDL_DisplayMode * mode); extern SDL_VideoDisplay *SDL_GetDisplayForWindow(SDL_Window *window); extern void *SDL_GetDisplayDriverData( int displayIndex ); +extern void *SDL_GetDisplayOutputData( int displayIndex ); +extern SDL_VideoDisplay *SDL_GetDisplayByOutputData( void *data ); extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags); diff -r f6355bfca853 -r 82f6d5196c2d src/video/SDL_video.c --- a/src/video/SDL_video.c Thu Dec 04 21:41:30 2014 +0100 +++ b/src/video/SDL_video.c Fri Dec 05 20:25:40 2014 +0300 @@ -637,6 +637,27 @@ } void * +SDL_GetDisplayOutputData(int displayIndex) +{ + CHECK_DISPLAY_INDEX(displayIndex, NULL); + + return _this->displays[displayIndex].outputdata; +} + +SDL_VideoDisplay * +SDL_GetDisplayByOutputData(void *data) +{ + int i; + + for (i = 0; i < _this->num_displays; i++) { + if (_this->displays[i].outputdata == data) { + return &_this->displays[i]; + } + } + return NULL; +} + +void * SDL_GetDisplayDriverData(int displayIndex) { CHECK_DISPLAY_INDEX(displayIndex, NULL); diff -r f6355bfca853 -r 82f6d5196c2d src/video/wayland/SDL_waylandvideo.c --- a/src/video/wayland/SDL_waylandvideo.c Thu Dec 04 21:41:30 2014 +0100 +++ b/src/video/wayland/SDL_waylandvideo.c Fri Dec 05 20:25:40 2014 +0300 @@ -34,6 +34,7 @@ #include "SDL_waylandopengles.h" #include "SDL_waylandmouse.h" #include "SDL_waylandtouch.h" +#include "SDL_assert.h" #include #include @@ -60,6 +61,8 @@ static void Wayland_VideoQuit(_THIS); +static Wayland_Output *get_Wayland_Output(SDL_VideoDisplay *d); + /* Wayland driver bootstrap functions */ static int Wayland_Available(void) @@ -109,6 +112,8 @@ device->PumpEvents = Wayland_PumpEvents; + device->GetDisplayBounds = Wayland_GetDisplayBounds; + device->GL_SwapWindow = Wayland_GLES_SwapWindow; device->GL_GetSwapInterval = Wayland_GLES_GetSwapInterval; device->GL_SetSwapInterval = Wayland_GLES_SetSwapInterval; @@ -136,12 +141,12 @@ }; static void -wayland_add_mode(SDL_VideoData *d, SDL_DisplayMode m) +wayland_add_mode(Wayland_Output *wo, SDL_DisplayMode m) { struct wayland_mode *mode; /* Check for duplicate mode */ - wl_list_for_each(mode, &d->modes_list, link) + wl_list_for_each(mode, &wo->modes_list, link) if (mode->mode.w == m.w && mode->mode.h == m.h && mode->mode.refresh_rate == m.refresh_rate) return; @@ -153,7 +158,17 @@ return; mode->mode = m; - WAYLAND_wl_list_insert(&d->modes_list, &mode->link); + WAYLAND_wl_list_insert(&wo->modes_list, &mode->link); +} + +Wayland_Output *Wayland_Get_OutputData(SDL_VideoData *data, struct wl_output *o) { + int i; + + for (i = 0; i < data->output_count; i++) { + if (data->outputs[i]->output == o) + return data->outputs[i]; + } + return NULL; } static void @@ -168,10 +183,11 @@ int transform) { - SDL_VideoData *d = data; + Wayland_Output *wo = Wayland_Get_OutputData(data, output); + SDL_assert(wo); - d->screen_allocation.x = x; - d->screen_allocation.y = y; + wo->screen_allocation.x = x; + wo->screen_allocation.y = y; } static void @@ -182,19 +198,33 @@ int height, int refresh) { - SDL_VideoData *d = data; + SDL_VideoData *vd = (SDL_VideoData *) data; + Wayland_Output *wo = Wayland_Get_OutputData(data, wl_output); + SDL_DisplayMode mode; SDL_zero(mode); mode.w = width; mode.h = height; + mode.format = SDL_PIXELFORMAT_RGB888; mode.refresh_rate = refresh / 1000; - wayland_add_mode(d, mode); + wayland_add_mode(wo, mode); if (flags & WL_OUTPUT_MODE_CURRENT) { - d->screen_allocation.width = width; - d->screen_allocation.height = height; + wo->screen_allocation.width = width; + wo->screen_allocation.height = height; + + SDL_VideoDisplay *d = SDL_GetDisplayByOutputData(wo); + SDL_assert(d); + + d->desktop_mode = mode; + d->current_mode = mode; + } + + if (!wo->configured) { + wo->configured = 1; + vd->outputs_configured++; } } @@ -236,6 +266,20 @@ }; #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ + + +static inline Wayland_Output *get_Wayland_Output(SDL_VideoDisplay *d) { + return (Wayland_Output *) d->outputdata; +} + +Wayland_Output *Wayland_Get_Display_Output(int displayId) { + if (SDL_GetNumVideoDisplays() == 0) + return NULL; + + return (Wayland_Output *) SDL_GetDisplayOutputData(displayId); +} + + static void display_handle_global(void *data, struct wl_registry *registry, uint32_t id, const char *interface, uint32_t version) @@ -245,8 +289,22 @@ if (strcmp(interface, "wl_compositor") == 0) { d->compositor = wl_registry_bind(d->registry, id, &wl_compositor_interface, 1); } else if (strcmp(interface, "wl_output") == 0) { - d->output = wl_registry_bind(d->registry, id, &wl_output_interface, 1); - wl_output_add_listener(d->output, &output_listener, d); + void *output = wl_registry_bind(d->registry, id, &wl_output_interface, 1); + d->outputs[d->output_count] = calloc(1, sizeof(Wayland_Output)); + + SDL_VideoDisplay display; + SDL_zero(display); + + Wayland_Output *wo = d->outputs[d->output_count]; + wo->index = d->output_count++; + + display.outputdata = wo; + WAYLAND_wl_list_init(&wo->modes_list); + wo->output = output; + + SDL_AddVideoDisplay(&display); + + wl_output_add_listener(output, &output_listener, d); } else if (strcmp(interface, "wl_seat") == 0) { Wayland_display_add_input(d, id); } else if (strcmp(interface, "wl_shell") == 0) { @@ -275,14 +333,11 @@ display_handle_global }; -int -Wayland_VideoInit(_THIS) +int Wayland_VideoInit(_THIS) { SDL_VideoData *data; - SDL_VideoDisplay display; - SDL_DisplayMode mode; int i; - + data = malloc(sizeof *data); if (data == NULL) return 0; @@ -290,8 +345,6 @@ _this->driverdata = data; - WAYLAND_wl_list_init(&data->modes_list); - data->display = WAYLAND_wl_display_connect(NULL); if (data->display == NULL) { SDL_SetError("Failed to connect to a Wayland display"); @@ -307,36 +360,32 @@ wl_registry_add_listener(data->registry, ®istry_listener, data); - for (i=0; i < 100; i++) { - if (data->screen_allocation.width != 0 || WAYLAND_wl_display_get_error(data->display) != 0) { - break; - } - WAYLAND_wl_display_dispatch(data->display); - } - - if (data->screen_allocation.width == 0) { - SDL_SetError("Failed while waiting for screen allocation: %d ", WAYLAND_wl_display_get_error(data->display)); - return 0; - } - data->xkb_context = WAYLAND_xkb_context_new(0); if (!data->xkb_context) { SDL_SetError("Failed to create XKB context"); return 0; } - /* Use a fake 32-bpp desktop mode */ - mode.format = SDL_PIXELFORMAT_RGB888; - mode.w = data->screen_allocation.width; - mode.h = data->screen_allocation.height; - mode.refresh_rate = 0; - mode.driverdata = NULL; - wayland_add_mode(data, mode); - SDL_zero(display); - display.desktop_mode = mode; - display.current_mode = mode; - display.driverdata = NULL; - SDL_AddVideoDisplay(&display); + Wayland_Output *wo; + + for (i=0; i < 100; i++) { + wo = Wayland_Get_Display_Output(0); + if ((wo != NULL && wo->screen_allocation.width != 0) + || WAYLAND_wl_display_get_error(data->display) != 0) { + break; + } + + WAYLAND_wl_display_dispatch(data->display); + } + + if (wo == 0 || wo->screen_allocation.width == 0) { + SDL_SetError("Failed while waiting for screen allocation: %d ", WAYLAND_wl_display_get_error(data->display)); + return 0; + } + + while (data->output_count != data->outputs_configured) { + WAYLAND_wl_display_dispatch(data->display); + } Wayland_InitMouse (); @@ -348,21 +397,21 @@ static void Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display) { - SDL_VideoData *data = _this->driverdata; SDL_DisplayMode mode; struct wayland_mode *m; + Wayland_Output *wo = get_Wayland_Output(sdl_display); Wayland_PumpEvents(_this); - wl_list_for_each(m, &data->modes_list, link) { + wl_list_for_each(m, &wo->modes_list, link) { m->mode.format = SDL_PIXELFORMAT_RGB888; SDL_AddDisplayMode(sdl_display, &m->mode); m->mode.format = SDL_PIXELFORMAT_RGBA8888; SDL_AddDisplayMode(sdl_display, &m->mode); } - mode.w = data->screen_allocation.width; - mode.h = data->screen_allocation.height; + mode.w = wo->screen_allocation.width; + mode.h = wo->screen_allocation.height; mode.refresh_rate = 0; mode.driverdata = NULL; @@ -383,11 +432,24 @@ { SDL_VideoData *data = _this->driverdata; struct wayland_mode *t, *m; + int i, display_num = SDL_GetNumVideoDisplays(); Wayland_FiniMouse (); - if (data->output) - wl_output_destroy(data->output); + for (i = 0; i < display_num; i++) { + Wayland_Output *wo = Wayland_Get_Display_Output(i); + SDL_assert (wo != NULL); + + if (!wo->output) + continue; + + wl_list_for_each_safe(m, t, &wo->modes_list, link) { + WAYLAND_wl_list_remove(&m->link); + free(m); + } + + wl_output_destroy(wo->output); + } Wayland_display_destroy_input(data); @@ -421,11 +483,7 @@ WAYLAND_wl_display_flush(data->display); WAYLAND_wl_display_disconnect(data->display); } - - wl_list_for_each_safe(m, t, &data->modes_list, link) { - WAYLAND_wl_list_remove(&m->link); - free(m); - } + free(data); diff -r f6355bfca853 -r 82f6d5196c2d src/video/wayland/SDL_waylandvideo.h --- a/src/video/wayland/SDL_waylandvideo.h Thu Dec 04 21:41:30 2014 +0100 +++ b/src/video/wayland/SDL_waylandvideo.h Fri Dec 05 20:25:40 2014 +0300 @@ -27,6 +27,9 @@ #include #include "wayland-util.h" +#include "SDL_video.h" +#include "SDL_waylanddyn.h" + struct xkb_context; struct SDL_WaylandInput; @@ -37,21 +40,32 @@ #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ typedef struct { + struct { + int32_t x, y, width, height; + } screen_allocation; + + struct wl_output *output; + struct wl_list modes_list; + int index; + int configured; +} Wayland_Output; + +#define WAYLAND_MAX_OUTPUTS 20 + +typedef struct { struct wl_display *display; struct wl_registry *registry; struct wl_compositor *compositor; - struct wl_output *output; + struct wl_shm *shm; struct wl_cursor_theme *cursor_theme; struct wl_cursor *default_cursor; struct wl_pointer *pointer; struct wl_shell *shell; - struct { - int32_t x, y, width, height; - } screen_allocation; - - struct wl_list modes_list; + Wayland_Output *outputs[WAYLAND_MAX_OUTPUTS]; + int output_count; + int outputs_configured; EGLDisplay edpy; EGLContext context; @@ -69,6 +83,8 @@ uint32_t shm_formats; } SDL_VideoData; +extern Wayland_Output *Wayland_Get_Display_Output(int displayId); #endif /* _SDL_waylandvideo_h */ + /* vi: set ts=4 sw=4 expandtab: */ diff -r f6355bfca853 -r 82f6d5196c2d src/video/wayland/SDL_waylandwindow.c --- a/src/video/wayland/SDL_waylandwindow.c Thu Dec 04 21:41:30 2014 +0100 +++ b/src/video/wayland/SDL_waylandwindow.c Fri Dec 05 20:25:40 2014 +0300 @@ -29,6 +29,7 @@ #include "SDL_waylandwindow.h" #include "SDL_waylandvideo.h" #include "SDL_waylandtouch.h" +#include "SDL_assert.h" static void handle_ping(void *data, struct wl_shell_surface *shell_surface, @@ -95,6 +96,23 @@ }; #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ +int +Wayland_GetDisplayBounds (_THIS, SDL_VideoDisplay * display, SDL_Rect * rect) +{ + Wayland_Output *wo = (Wayland_Output *)display->outputdata; + + if (!wo) { + return -1; + } + + rect->x = wo->screen_allocation.x; + rect->y = wo->screen_allocation.y; + rect->w = wo->screen_allocation.width; + rect->h = wo->screen_allocation.height; + + return 0; +} + SDL_bool Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info) { @@ -112,10 +130,14 @@ { SDL_WindowData *wind = window->driverdata; - if (window->flags & SDL_WINDOW_FULLSCREEN) + if (window->flags & SDL_WINDOW_FULLSCREEN) { + Wayland_Output *wo = Wayland_Get_Display_Output(SDL_GetWindowDisplayIndex(window)); + SDL_assert(wo != NULL); + wl_shell_surface_set_fullscreen(wind->shell_surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, - 0, NULL); + 0, wo->output); + } else wl_shell_surface_set_toplevel(wind->shell_surface); @@ -128,10 +150,14 @@ { SDL_WindowData *wind = window->driverdata; - if (fullscreen) + if (fullscreen) { + Wayland_Output *wo = (Wayland_Output *)_display->outputdata; + SDL_assert(wo != NULL); + wl_shell_surface_set_fullscreen(wind->shell_surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE, - 0, NULL); + 0, wo->output); + } else wl_shell_surface_set_toplevel(wind->shell_surface); @@ -178,15 +204,20 @@ } #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ + int displayId = SDL_GetWindowDisplayIndex(window); + Wayland_Output *wo = Wayland_Get_Display_Output(displayId); + SDL_assert(wo != NULL); + /** * If the user specified 0x0 as the size (turned to 1x1 by SDL_CreateWindow * in SDL_video.c), we want to make the window fill the whole screen **/ + if (window->w == 1) { - window->w = c->screen_allocation.width; + window->w = wo->screen_allocation.width; } if (window->h == 1) { - window->h = c->screen_allocation.height; + window->h = wo->screen_allocation.height; } data->egl_window = WAYLAND_wl_egl_window_create(data->surface, diff -r f6355bfca853 -r 82f6d5196c2d src/video/wayland/SDL_waylandwindow.h --- a/src/video/wayland/SDL_waylandwindow.h Thu Dec 04 21:41:30 2014 +0100 +++ b/src/video/wayland/SDL_waylandwindow.h Fri Dec 05 20:25:40 2014 +0300 @@ -52,6 +52,7 @@ extern int Wayland_CreateWindow(_THIS, SDL_Window *window); extern void Wayland_SetWindowSize(_THIS, SDL_Window * window); extern void Wayland_DestroyWindow(_THIS, SDL_Window *window); +extern int Wayland_GetDisplayBounds (_THIS, SDL_VideoDisplay * display, SDL_Rect * rect); extern SDL_bool Wayland_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);