diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c index 9b8547c5a..c297de159 100644 --- a/src/video/wayland/SDL_waylandwindow.c +++ b/src/video/wayland/SDL_waylandwindow.c @@ -64,10 +64,13 @@ FloatEqual(float a, float b) static void GetFullScreenDimensions(SDL_Window *window, int *width, int *height, int *drawable_width, int *drawable_height) { - SDL_WaylandOutputData *output = (SDL_WaylandOutputData *)SDL_GetDisplayForWindow(window)->driverdata; + SDL_WindowData *wind = (SDL_WindowData *) window->driverdata; + SDL_WaylandOutputData *output = (SDL_WaylandOutputData *) SDL_GetDisplayForWindow(window)->driverdata; int fs_width, fs_height; int buf_width, buf_height; + const int output_width = wind->fs_output_width ? wind->fs_output_width : output->width; + const int output_height = wind->fs_output_height ? wind->fs_output_height : output->height; /* * Fullscreen desktop mandates a desktop sized window, so that's what applications will get. @@ -75,8 +78,8 @@ GetFullScreenDimensions(SDL_Window *window, int *width, int *height, int *drawab * differently sized window and backbuffer spaces on its own. */ if ((window->flags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) { - fs_width = output->width; - fs_height = output->height; + fs_width = output_width; + fs_height = output_height; /* If the application is DPI aware, we can expose the true backbuffer size */ if (window->flags & SDL_WINDOW_ALLOW_HIGHDPI) { @@ -98,8 +101,8 @@ GetFullScreenDimensions(SDL_Window *window, int *width, int *height, int *drawab fs_width = output->native_width; fs_height = output->native_height; } else { - fs_width = output->width; - fs_height = output->height; + fs_width = output_width; + fs_height = output_height; } buf_width = fs_width; @@ -258,20 +261,22 @@ ConfigureWindowGeometry(SDL_Window *window) if (FullscreenModeEmulation(window) && NeedViewport(window)) { int fs_width, fs_height; int src_width, src_height; + const int output_width = data->fs_output_width ? data->fs_output_width : output->width; + const int output_height = data->fs_output_height ? data->fs_output_height : output->height; GetFullScreenDimensions(window, &fs_width, &fs_height, &src_width, &src_height); /* Set the buffer scale to 1 since a viewport will be used. */ wl_surface_set_buffer_scale(data->surface, 1); - SetDrawSurfaceViewport(window, src_width, src_height, output->width, output->height); + SetDrawSurfaceViewport(window, src_width, src_height, output_width, output_height); data->viewport_rect.x = 0; data->viewport_rect.y = 0; - data->viewport_rect.w = output->width; - data->viewport_rect.h = output->height; + data->viewport_rect.w = output_width; + data->viewport_rect.h = output_height; - data->pointer_scale_x = (float)fs_width / (float)output->width; - data->pointer_scale_y = (float)fs_height / (float)output->height; + data->pointer_scale_x = (float)fs_width / (float)output_width; + data->pointer_scale_y = (float)fs_height / (float)output_height; if (!EGLTransparencyEnabled()) { region = wl_compositor_create_region(viddata->compositor); @@ -498,6 +503,25 @@ UpdateWindowFullscreen(SDL_Window *window, SDL_bool fullscreen) } } +static void +CommitWindowGeometry(SDL_Window *window) +{ + SDL_WindowData *wind = (SDL_WindowData *) window->driverdata; + SDL_VideoData *viddata = (SDL_VideoData *) wind->waylandData; + +#ifdef HAVE_LIBDECOR_H + if (WINDOW_IS_LIBDECOR(data, window) && wind->shell_surface.libdecor.frame) { + struct libdecor_state *state = libdecor_state_new(GetWindowWidth(window), GetWindowHeight(window)); + libdecor_frame_commit(wind->shell_surface.libdecor.frame, state, NULL); + libdecor_state_free(state); + } else +#endif + if (viddata->shell.xdg && wind->shell_surface.xdg.surface) { + xdg_surface_set_window_geometry(wind->shell_surface.xdg.surface, 0, 0, + GetWindowWidth(window), GetWindowHeight(window)); + } +} + static const struct wl_callback_listener surface_damage_frame_listener; static void @@ -657,6 +681,14 @@ handle_configure_xdg_toplevel(void *data, * UPDATE: Nope, sure enough a compositor sends 0,0. This is a known bug: * https://bugs.kde.org/show_bug.cgi?id=444962 */ + if (width && height) { + wind->fs_output_width = width; + wind->fs_output_height = height; + } else { + wind->fs_output_width = 0; + wind->fs_output_height = 0; + } + if (FullscreenModeEmulation(window)) { GetFullScreenDimensions(window, &width, &height, NULL, NULL); } @@ -836,18 +868,23 @@ decoration_frame_configure(struct libdecor_frame *frame, * Always assume the configure is wrong. */ if (fullscreen) { - if (!FullscreenModeEmulation(window)) { - /* FIXME: We have been explicitly told to respect the fullscreen size - * parameters here, even though they are known to be wrong on GNOME at - * bare minimum. If this is wrong, don't blame us, we were explicitly - * told to do this. - */ - if (!libdecor_configuration_get_content_size(configuration, frame, - &width, &height)) { - width = window->w; - height = window->h; - } + /* FIXME: We have been explicitly told to respect the fullscreen size + * parameters here, even though they are known to be wrong on GNOME at + * bare minimum. If this is wrong, don't blame us, we were explicitly + * told to do this. + */ + if (libdecor_configuration_get_content_size(configuration, frame, + &width, &height)) { + wind->fs_output_width = width; + wind->fs_output_height = height; } else { + width = window->w; + height = window->h; + wind->fs_output_width = 0; + wind->fs_output_height = 0; + } + + if (FullscreenModeEmulation(window)) { GetFullScreenDimensions(window, &width, &height, NULL, NULL); } @@ -990,9 +1027,34 @@ static void Wayland_move_window(SDL_Window *window, SDL_WaylandOutputData *driverdata) { - int i, numdisplays = SDL_GetNumVideoDisplays(); + SDL_WindowData *wind = (SDL_WindowData*)window; + SDL_VideoDisplay *display; + int i, j; + const int numdisplays = SDL_GetNumVideoDisplays(); for (i = 0; i < numdisplays; i += 1) { - if (SDL_GetDisplay(i)->driverdata == driverdata) { + display = SDL_GetDisplay(i); + if (display->driverdata == driverdata) { + SDL_Rect bounds; + + /* If the window is fullscreen and not on the target display, move it. */ + if ((window->flags & SDL_WINDOW_FULLSCREEN) && display->fullscreen_window != window) { + /* If the target display already has a fullscreen window, minimize it. */ + if (display->fullscreen_window) { + SDL_MinimizeWindow(display->fullscreen_window); + } + + /* Find the window and move it to the target display. */ + for (j = 0; j < numdisplays; ++j) { + SDL_VideoDisplay *v = SDL_GetDisplay(j); + + if (v->fullscreen_window == window) { + v->fullscreen_window = NULL; + } + } + + display->fullscreen_window = window; + } + /* We want to send a very very specific combination here: * * 1. A coordinate that tells the application what display we're on @@ -1012,9 +1074,18 @@ Wayland_move_window(SDL_Window *window, * * -flibit */ - SDL_Rect bounds; SDL_GetDisplayBounds(i, &bounds); SDL_SendWindowEvent(window, SDL_WINDOWEVENT_MOVED, bounds.x, bounds.y); + + /* + * We should have gotten the new output size from the compositor, but if not, + * commit with the dimensions with the new display. + */ + if (!wind->fs_output_width || !wind->fs_output_height) { + ConfigureWindowGeometry(window); + CommitWindowGeometry(window); + } + break; } } @@ -1034,9 +1105,10 @@ handle_surface_enter(void *data, struct wl_surface *surface, window->outputs = SDL_realloc(window->outputs, sizeof(SDL_WaylandOutputData*) * (window->num_outputs + 1)); window->outputs[window->num_outputs++] = driverdata; - update_scale_factor(window); + /* Update the scale factor after the move so that fullscreen outputs are updated. */ Wayland_move_window(window->sdlwindow, driverdata); + update_scale_factor(window); } static void @@ -1687,18 +1759,7 @@ Wayland_SetWindowFullscreen(_THIS, SDL_Window * window, * geometry and trigger a commit. */ ConfigureWindowGeometry(window); - -#ifdef HAVE_LIBDECOR_H - if (WINDOW_IS_LIBDECOR(data, window) && wind->shell_surface.libdecor.frame) { - struct libdecor_state *state = libdecor_state_new(GetWindowWidth(window), GetWindowHeight(window)); - libdecor_frame_commit(wind->shell_surface.libdecor.frame, state, NULL); - libdecor_state_free(state); - } else -#endif - if(viddata->shell.xdg && wind->shell_surface.xdg.surface) { - xdg_surface_set_window_geometry(wind->shell_surface.xdg.surface, 0, 0, - GetWindowWidth(window), GetWindowHeight(window)); - } + CommitWindowGeometry(window); /* Roundtrip required to receive the updated window dimensions */ WAYLAND_wl_display_roundtrip(viddata->display); diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h index a1ba0fe5a..0a37a2781 100644 --- a/src/video/wayland/SDL_waylandwindow.h +++ b/src/video/wayland/SDL_waylandwindow.h @@ -104,6 +104,7 @@ typedef struct { float pointer_scale_x; float pointer_scale_y; int drawable_width, drawable_height; + int fs_output_width, fs_output_height; SDL_Rect viewport_rect; SDL_bool needs_resize_event; SDL_bool floating_resize_pending;