mirror of
https://github.com/libsdl-org/SDL.git
synced 2026-05-04 13:04:41 +00:00
wayland: Rework scale-to-display
This extends the display scaling mode to be global and work in terms of pixels everywhere, with the content scale value set on displays. The per-window property had some issues, and has been removed in favor of retaining only the global hint that changes all coordinates to pixel values, sets the content scale on the displays, and generally makes the Wayland backend behave similarly to Win32 or X11. Some additional work was needed to fix cases where displays can appear to overlap, since Wayland desktops are always described in logical coordinates, and attempting to adjust the display positions so that they don't overlap can get very ugly in all but the simplest cases, as large gaps between displays can result.
This commit is contained in:
@@ -157,7 +157,8 @@ typedef enum
|
||||
VIDEO_DEVICE_CAPS_MODE_SWITCHING_EMULATED = 0x01,
|
||||
VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT = 0x02,
|
||||
VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS = 0x04,
|
||||
VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY = 0x08
|
||||
VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY = 0x08,
|
||||
VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES = 0x10
|
||||
} DeviceCaps;
|
||||
|
||||
struct SDL_VideoDevice
|
||||
|
||||
@@ -185,6 +185,11 @@ static SDL_bool IsFullscreenOnly(SDL_VideoDevice *_this)
|
||||
return !!(_this->device_caps & VIDEO_DEVICE_CAPS_FULLSCREEN_ONLY);
|
||||
}
|
||||
|
||||
static SDL_bool SDL_SendsDisplayChanges(SDL_VideoDevice *_this)
|
||||
{
|
||||
return !!(_this->device_caps & VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES);
|
||||
}
|
||||
|
||||
/* Hint to treat all window ops as synchronous */
|
||||
static SDL_bool syncHint;
|
||||
|
||||
@@ -1545,6 +1550,10 @@ SDL_DisplayID SDL_GetDisplayForWindow(SDL_Window *window)
|
||||
|
||||
static void SDL_CheckWindowDisplayChanged(SDL_Window *window)
|
||||
{
|
||||
if (SDL_SendsDisplayChanges(_this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_DisplayID displayID = SDL_GetDisplayForWindowPosition(window);
|
||||
|
||||
if (displayID != window->last_displayID) {
|
||||
|
||||
@@ -423,6 +423,7 @@ static SDL_VideoDevice *Wayland_CreateDevice(void)
|
||||
data->display = display;
|
||||
data->input = input;
|
||||
data->display_externally_owned = display_is_external;
|
||||
data->scale_to_display_enabled = SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_SCALE_TO_DISPLAY, SDL_FALSE);
|
||||
WAYLAND_wl_list_init(&data->output_list);
|
||||
WAYLAND_wl_list_init(&data->output_order);
|
||||
WAYLAND_wl_list_init(&external_window_list);
|
||||
@@ -488,6 +489,7 @@ static SDL_VideoDevice *Wayland_CreateDevice(void)
|
||||
device->SetWindowModalFor = Wayland_SetWindowModalFor;
|
||||
device->SetWindowTitle = Wayland_SetWindowTitle;
|
||||
device->GetWindowSizeInPixels = Wayland_GetWindowSizeInPixels;
|
||||
device->GetDisplayForWindow = Wayland_GetDisplayForWindow;
|
||||
device->DestroyWindow = Wayland_DestroyWindow;
|
||||
device->SetWindowHitTest = Wayland_SetWindowHitTest;
|
||||
device->FlashWindow = Wayland_FlashWindow;
|
||||
@@ -519,7 +521,8 @@ static SDL_VideoDevice *Wayland_CreateDevice(void)
|
||||
|
||||
device->device_caps = VIDEO_DEVICE_CAPS_MODE_SWITCHING_EMULATED |
|
||||
VIDEO_DEVICE_CAPS_HAS_POPUP_WINDOW_SUPPORT |
|
||||
VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS;
|
||||
VIDEO_DEVICE_CAPS_SENDS_FULLSCREEN_DIMENSIONS |
|
||||
VIDEO_DEVICE_CAPS_SENDS_DISPLAY_CHANGES;
|
||||
|
||||
return device;
|
||||
}
|
||||
@@ -831,9 +834,16 @@ static void display_handle_done(void *data,
|
||||
SDL_zero(desktop_mode);
|
||||
desktop_mode.format = SDL_PIXELFORMAT_XRGB8888;
|
||||
|
||||
desktop_mode.w = driverdata->screen_width;
|
||||
desktop_mode.h = driverdata->screen_height;
|
||||
desktop_mode.pixel_density = driverdata->scale_factor;
|
||||
if (!video->scale_to_display_enabled) {
|
||||
desktop_mode.w = driverdata->screen_width;
|
||||
desktop_mode.h = driverdata->screen_height;
|
||||
desktop_mode.pixel_density = driverdata->scale_factor;
|
||||
} else {
|
||||
desktop_mode.w = native_mode.w;
|
||||
desktop_mode.h = native_mode.h;
|
||||
desktop_mode.pixel_density = 1.0f;
|
||||
}
|
||||
|
||||
desktop_mode.refresh_rate = ((100 * driverdata->refresh) / 1000) / 100.0f; /* mHz to Hz */
|
||||
|
||||
if (driverdata->display > 0) {
|
||||
@@ -842,6 +852,10 @@ static void display_handle_done(void *data,
|
||||
dpy = &driverdata->placeholder;
|
||||
}
|
||||
|
||||
if (video->scale_to_display_enabled) {
|
||||
SDL_SetDisplayContentScale(dpy, driverdata->scale_factor);
|
||||
}
|
||||
|
||||
/* Set the desktop display mode. */
|
||||
SDL_SetDesktopDisplayMode(dpy, &desktop_mode);
|
||||
|
||||
@@ -1176,6 +1190,12 @@ int Wayland_VideoInit(SDL_VideoDevice *_this)
|
||||
// First roundtrip to receive all registry objects.
|
||||
WAYLAND_wl_display_roundtrip(data->display);
|
||||
|
||||
// Require viewports for display scaling.
|
||||
if (data->scale_to_display_enabled && !data->viewporter) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "wayland: Display scaling requires the missing 'wp_viewporter' protocol: disabling");
|
||||
data->scale_to_display_enabled = SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Now that we have all the protocols, load libdecor if applicable */
|
||||
Wayland_LoadLibdecor(data, SDL_FALSE);
|
||||
|
||||
@@ -1203,6 +1223,7 @@ int Wayland_VideoInit(SDL_VideoDevice *_this)
|
||||
|
||||
static int Wayland_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *display, SDL_Rect *rect)
|
||||
{
|
||||
SDL_VideoData *viddata = _this->driverdata;
|
||||
SDL_DisplayData *driverdata = display->driverdata;
|
||||
rect->x = driverdata->x;
|
||||
rect->y = driverdata->y;
|
||||
@@ -1216,15 +1237,7 @@ static int Wayland_GetDisplayBounds(SDL_VideoDevice *_this, SDL_VideoDisplay *di
|
||||
rect->w = display->fullscreen_window->current_fullscreen_mode.w;
|
||||
rect->h = display->fullscreen_window->current_fullscreen_mode.h;
|
||||
} else {
|
||||
/* If the focused window is on the requested display and requires display scaling,
|
||||
* return the physical dimensions in pixels.
|
||||
*/
|
||||
SDL_Window *kb = SDL_GetKeyboardFocus();
|
||||
SDL_Window *m = SDL_GetMouseFocus();
|
||||
SDL_bool scale_output = (kb && kb->driverdata->scale_to_display && (kb->last_displayID == display->id)) ||
|
||||
(m && m->driverdata->scale_to_display && (m->last_displayID == display->id));
|
||||
|
||||
if (!scale_output) {
|
||||
if (!viddata->scale_to_display_enabled) {
|
||||
rect->w = display->current_mode->w;
|
||||
rect->h = display->current_mode->h;
|
||||
} else if (driverdata->transform & WL_OUTPUT_TRANSFORM_90) {
|
||||
|
||||
@@ -93,6 +93,8 @@ struct SDL_VideoData
|
||||
|
||||
int relative_mouse_mode;
|
||||
SDL_bool display_externally_owned;
|
||||
|
||||
SDL_bool scale_to_display_enabled;
|
||||
};
|
||||
|
||||
struct SDL_DisplayData
|
||||
|
||||
@@ -538,6 +538,7 @@ static void Wayland_move_window(SDL_Window *window)
|
||||
*/
|
||||
FlushFullscreenEvents(window);
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_MOVED, display->x, display->y);
|
||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_DISPLAY_CHANGED, wind->last_displayID, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -2212,20 +2213,6 @@ int Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Propert
|
||||
const SDL_bool custom_surface_role = (external_surface != NULL) || SDL_GetBooleanProperty(create_props, SDL_PROP_WINDOW_CREATE_WAYLAND_SURFACE_ROLE_CUSTOM_BOOLEAN, SDL_FALSE);
|
||||
const SDL_bool create_egl_window = !!(window->flags & SDL_WINDOW_OPENGL) ||
|
||||
SDL_GetBooleanProperty(create_props, SDL_PROP_WINDOW_CREATE_WAYLAND_CREATE_EGL_WINDOW_BOOLEAN, SDL_FALSE);
|
||||
SDL_bool scale_to_display = !(window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) && !custom_surface_role &&
|
||||
SDL_GetBooleanProperty(create_props, SDL_PROP_WINDOW_CREATE_WAYLAND_SCALE_TO_DISPLAY_BOOLEAN,
|
||||
SDL_GetHintBoolean(SDL_HINT_VIDEO_WAYLAND_SCALE_TO_DISPLAY, SDL_FALSE));
|
||||
|
||||
/* Require viewports for display scaling. */
|
||||
if (scale_to_display && !c->viewporter) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "wayland: Display scaling requires the missing 'wp_viewporter' protocol: disabling");
|
||||
scale_to_display = SDL_FALSE;
|
||||
}
|
||||
|
||||
/* Require popups to have the same scaling mode as the parent. */
|
||||
if (SDL_WINDOW_IS_POPUP(window) && scale_to_display != window->parent->driverdata->scale_to_display) {
|
||||
return SDL_SetError("wayland: Popup windows must use the same scaling as their parent");
|
||||
}
|
||||
|
||||
data = SDL_calloc(1, sizeof(*data));
|
||||
if (!data) {
|
||||
@@ -2250,7 +2237,7 @@ int Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Propert
|
||||
data->scale_to_display = window->parent->driverdata->scale_to_display;
|
||||
data->windowed_scale_factor = window->parent->driverdata->windowed_scale_factor;
|
||||
EnsurePopupPositionIsValid(window, &window->x, &window->y);
|
||||
} else if ((window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) || scale_to_display) {
|
||||
} else if ((window->flags & SDL_WINDOW_HIGH_PIXEL_DENSITY) || c->scale_to_display_enabled) {
|
||||
for (int i = 0; i < _this->num_displays; i++) {
|
||||
float scale = _this->displays[i]->driverdata->scale_factor;
|
||||
data->windowed_scale_factor = SDL_max(data->windowed_scale_factor, scale);
|
||||
@@ -2259,7 +2246,7 @@ int Wayland_CreateWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_Propert
|
||||
|
||||
data->outputs = NULL;
|
||||
data->num_outputs = 0;
|
||||
data->scale_to_display = scale_to_display;
|
||||
data->scale_to_display = c->scale_to_display_enabled;
|
||||
|
||||
/* Cache the app_id at creation time, as it may change before the window is mapped. */
|
||||
data->app_id = SDL_strdup(SDL_GetAppID());
|
||||
@@ -2509,6 +2496,17 @@ void Wayland_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, i
|
||||
*h = data->current.drawable_height;
|
||||
}
|
||||
|
||||
SDL_DisplayID Wayland_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *wind = window->driverdata;
|
||||
|
||||
if (wind) {
|
||||
return wind->last_displayID;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window)
|
||||
{
|
||||
SDL_WindowData *wind = window->driverdata;
|
||||
|
||||
@@ -200,6 +200,7 @@ extern void Wayland_SetWindowSize(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Wayland_SetWindowMinimumSize(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Wayland_SetWindowMaximumSize(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Wayland_GetWindowSizeInPixels(SDL_VideoDevice *_this, SDL_Window *window, int *w, int *h);
|
||||
extern SDL_DisplayID Wayland_GetDisplayForWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern int Wayland_SetWindowModalFor(SDL_VideoDevice *_this, SDL_Window *modal_window, SDL_Window *parent_window);
|
||||
extern void Wayland_SetWindowTitle(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
extern void Wayland_ShowWindowSystemMenu(SDL_Window *window, int x, int y);
|
||||
|
||||
Reference in New Issue
Block a user