# HG changeset patch # User Emmanuel Gil Peyrot # Date 1426637685 -3600 # Wed Mar 18 01:14:45 2015 +0100 # Node ID 237135603a75e97a6148e0c7297a790c7c2cf1a9 # Parent 62164ad0b7d5d4a13c4f6a411b83abcf6f2af172 Wayland: Properly discover displays and their modes. diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c --- a/src/video/wayland/SDL_waylandvideo.c +++ b/src/video/wayland/SDL_waylandvideo.c @@ -43,11 +43,6 @@ #define WAYLANDVID_DRIVER_NAME "wayland" -struct wayland_mode { - SDL_DisplayMode mode; - struct wl_list link; -}; - /* Initialization/Query functions */ static int Wayland_VideoInit(_THIS); @@ -87,7 +82,7 @@ Wayland_CreateDevice(int devindex) { SDL_VideoDevice *device; - + if (!SDL_WAYLAND_LoadSymbols()) { return NULL; } @@ -136,27 +131,6 @@ }; static void -wayland_add_mode(SDL_VideoData *d, SDL_DisplayMode m) -{ - struct wayland_mode *mode; - - /* Check for duplicate mode */ - wl_list_for_each(mode, &d->modes_list, link) - if (mode->mode.w == m.w && mode->mode.h == m.h && - mode->mode.refresh_rate == m.refresh_rate) - return; - - /* Add new mode to the list */ - mode = (struct wayland_mode *) SDL_calloc(1, sizeof *mode); - - if (!mode) - return; - - mode->mode = m; - WAYLAND_wl_list_insert(&d->modes_list, &mode->link); -} - -static void display_handle_geometry(void *data, struct wl_output *output, int x, int y, @@ -168,55 +142,79 @@ int transform) { - SDL_VideoData *d = data; + SDL_VideoDisplay *display = data; - d->screen_allocation.x = x; - d->screen_allocation.y = y; + display->name = strdup(model); + display->driverdata = output; } static void display_handle_mode(void *data, - struct wl_output *wl_output, + struct wl_output *output, uint32_t flags, int width, int height, int refresh) { - SDL_VideoData *d = data; + SDL_VideoDisplay *display = data; SDL_DisplayMode mode; SDL_zero(mode); mode.w = width; mode.h = height; - mode.refresh_rate = refresh / 1000; - - wayland_add_mode(d, mode); + mode.refresh_rate = refresh / 1000; // mHz to Hz + SDL_AddDisplayMode(display, &mode); if (flags & WL_OUTPUT_MODE_CURRENT) { - d->screen_allocation.width = width; - d->screen_allocation.height = height; + display->current_mode = mode; + display->desktop_mode = mode; } } +static void +display_handle_done(void *data, + struct wl_output *output) +{ + SDL_VideoDisplay *display = data; + SDL_AddVideoDisplay(display); + SDL_free(display->name); + SDL_free(display); +} + +static void +display_handle_scale(void *data, + struct wl_output *output, + int32_t factor) +{ + // TODO: do HiDPI stuff. +} + static const struct wl_output_listener output_listener = { display_handle_geometry, - display_handle_mode + display_handle_mode, + display_handle_done, + display_handle_scale }; static void -shm_handle_format(void *data, - struct wl_shm *shm, - uint32_t format) +Wayland_add_display(SDL_VideoData *d, uint32_t id) { - SDL_VideoData *d = data; + SDL_VideoDisplay *display = SDL_malloc(sizeof *display); + if (!display) { + SDL_OutOfMemory(); + return; + } + SDL_zero(*display); - d->shm_formats |= (1 << format); + struct wl_output *output = wl_registry_bind(d->registry, id, &wl_output_interface, 2); + if (!output) { + SDL_SetError("Failed to retrieve output."); + return; + } + + wl_output_add_listener(output, &output_listener, display); } -static const struct wl_shm_listener shm_listener = { - shm_handle_format -}; - #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH static void windowmanager_hints(void *data, struct qt_windowmanager *qt_windowmanager, @@ -238,15 +236,14 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint32_t id, - const char *interface, uint32_t version) + const char *interface, uint32_t version) { SDL_VideoData *d = data; - + 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); + Wayland_add_display(d, id); } else if (strcmp(interface, "wl_seat") == 0) { Wayland_display_add_input(d, id); } else if (strcmp(interface, "wl_shell") == 0) { @@ -255,8 +252,7 @@ d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1); d->cursor_theme = WAYLAND_wl_cursor_theme_load(NULL, 32, d->shm); d->default_cursor = WAYLAND_wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr"); - wl_shm_add_listener(d->shm, &shm_listener, d); - + #ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH } else if (strcmp(interface, "qt_touch_extension") == 0) { Wayland_touch_create(d, id); @@ -272,26 +268,19 @@ } static const struct wl_registry_listener registry_listener = { - display_handle_global + display_handle_global }; int Wayland_VideoInit(_THIS) { - SDL_VideoData *data; - SDL_VideoDisplay display; - SDL_DisplayMode mode; - int i; - - data = malloc(sizeof *data); + SDL_VideoData *data = SDL_malloc(sizeof *data); if (data == NULL) return 0; memset(data, 0, sizeof *data); _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"); @@ -299,25 +288,18 @@ } data->registry = wl_display_get_registry(data->display); - - if ( data->registry == NULL) { + if (data->registry == NULL) { SDL_SetError("Failed to get the Wayland registry"); return 0; } - + 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; - } + // First roundtrip to receive all registry objects. + wl_display_roundtrip(data->display); + + // Second roundtrip to receive all output events. + wl_display_roundtrip(data->display); data->xkb_context = WAYLAND_xkb_context_new(0); if (!data->xkb_context) { @@ -325,20 +307,7 @@ 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_InitMouse (); + Wayland_InitMouse(); WAYLAND_wl_display_flush(data->display); @@ -348,46 +317,30 @@ static void Wayland_GetDisplayModes(_THIS, SDL_VideoDisplay *sdl_display) { - SDL_VideoData *data = _this->driverdata; - SDL_DisplayMode mode; - struct wayland_mode *m; - - Wayland_PumpEvents(_this); - - wl_list_for_each(m, &data->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.refresh_rate = 0; - mode.driverdata = NULL; - - mode.format = SDL_PIXELFORMAT_RGB888; - SDL_AddDisplayMode(sdl_display, &mode); - mode.format = SDL_PIXELFORMAT_RGBA8888; - SDL_AddDisplayMode(sdl_display, &mode); + // Nothing to do here, everything was already done in the wl_output + // callbacks. } static int Wayland_SetDisplayMode(_THIS, SDL_VideoDisplay *display, SDL_DisplayMode *mode) { - return 0; + SDL_SetError("SetDisplayMode not (yet?) supported on Wayland."); + return -1; } void Wayland_VideoQuit(_THIS) { SDL_VideoData *data = _this->driverdata; - struct wayland_mode *t, *m; + int i; Wayland_FiniMouse (); - if (data->output) - wl_output_destroy(data->output); + for (i = 0; i < _this->num_displays; ++i) { + SDL_VideoDisplay *display = &_this->displays[i]; + wl_output_destroy(display->driverdata); + display->driverdata = NULL; + } Wayland_display_destroy_input(data); @@ -417,16 +370,13 @@ if (data->compositor) wl_compositor_destroy(data->compositor); + if (data->registry) + wl_registry_destroy(data->registry); + if (data->display) { 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); _this->driverdata = NULL; diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h --- a/src/video/wayland/SDL_waylandvideo.h +++ b/src/video/wayland/SDL_waylandvideo.h @@ -40,27 +40,20 @@ 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; - EGLDisplay edpy; EGLContext context; EGLConfig econf; struct xkb_context *xkb_context; struct SDL_WaylandInput *input; - -#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH + +#ifdef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH struct SDL_WaylandTouch *touch; struct qt_surface_extension *surface_extension; struct qt_windowmanager *windowmanager; diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -179,17 +179,6 @@ } #endif /* SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH */ - /** - * 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; - } - if (window->h == 1) { - window->h = c->screen_allocation.height; - } - data->egl_window = WAYLAND_wl_egl_window_create(data->surface, window->w, window->h);