-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SDL_GetDisplayUsableBounds returns initial bounds #11407
Comments
I wasn't able to replicate this exact issue, but I noticed a very similar issue with the usable bounds and the panel on X11. These tests probably won't fix the issue, but can give some insights into how X11 display bounds work. My issue was on X11, when having the panel on the top or bottom of any display, it affected all usable bounds on every display. This code was used to print the display bounds: Code
To compile with SDL2, predefine: Optionally: On SDL3, to compile with Wayland instead with X11, predefine #if MY_SDL_MAJOR_VERSION == 2
#include <SDL2/SDL.h>
#include <stdbool.h>
#elif MY_SDL_MAJOR_VERSION == 3
#include <SDL3/SDL.h>
#else
#error define MY_SDL_MAJOR_VERSION as 2 or 3
#endif
#include <stdio.h>
#include <string.h>
// print error message if value is false
//
// check if error message was set if value is true
//
// returns original value
static int my_print_SDL_error(bool val) {
const char *error_msg = SDL_GetError();
if (!val) {
printf("ERROR: %s\n", error_msg);
}
else if (error_msg[0]) {
printf("TRUE_BUT_ERROR_MESSAGE_SET: %s\n", error_msg);
}
SDL_ClearError();
return val;
}
// "main" function =================================================================================
int main(void) {
bool return_value;
#if MY_SDL_MAJOR_VERSION == 3 && defined(MY_USE_WAYLAND)
return_value = SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "wayland");
my_print_SDL_error(return_value);
#endif
// init SDL
#if MY_SDL_MAJOR_VERSION == 2
return_value = SDL_Init(SDL_INIT_VIDEO) == 0;
#elif MY_SDL_MAJOR_VERSION == 3
return_value = SDL_Init(SDL_INIT_VIDEO);
#endif
if (!my_print_SDL_error(return_value)) {
printf("ERROR: %s\n", SDL_GetError());
return -1;
}
// print SDL version
printf("SDL Version (linked): ");
#if MY_SDL_MAJOR_VERSION == 2
SDL_version linked_version;
SDL_GetVersion(&linked_version);
printf("%d.%d.%d\n", linked_version.major, linked_version.minor, linked_version.patch);
#elif MY_SDL_MAJOR_VERSION == 3
printf("%d.%d.%d\n", SDL_VERSIONNUM_MAJOR(SDL_GetVersion()),
SDL_VERSIONNUM_MINOR(SDL_GetVersion()),
SDL_VERSIONNUM_MICRO(SDL_GetVersion()));
#endif
// print video driver
const char * current_video_driver = SDL_GetCurrentVideoDriver();
printf("SDL_GetCurrentVideoDriver(): ");
printf("%s\n", current_video_driver ? current_video_driver : "NULL");
my_print_SDL_error(current_video_driver);
// num displays variable (and SDL3 display ID array)
#if MY_SDL_MAJOR_VERSION == 2
printf("SDL_GetNumVideoDisplays(): ");
const int num_video_displays = SDL_GetNumVideoDisplays();
printf("%d\n", num_video_displays);
#elif MY_SDL_MAJOR_VERSION == 3
printf("SDL_GetDisplays(): ");
int display_count;
SDL_DisplayID * displays = SDL_GetDisplays(&display_count);
printf("display_count = %d\n", display_count);
my_print_SDL_error(displays);
#endif
// print primary display
#if MY_SDL_MAJOR_VERSION == 3
printf("SDL_GetPrimaryDisplay(): ID = ");
const SDL_DisplayID primary_display_id = SDL_GetPrimaryDisplay();
printf("%d\n", primary_display_id);
my_print_SDL_error(primary_display_id);
#endif
// get max display name len
size_t max_display_name_len = 0;
#if MY_SDL_MAJOR_VERSION == 2
for (int display_idx = 0; display_idx < num_video_displays; ++display_idx) {
#elif MY_SDL_MAJOR_VERSION == 3
for (int display_idx = 0; display_idx < display_count; ++display_idx) {
#endif
#if MY_SDL_MAJOR_VERSION == 2
const char * const display_name = SDL_GetDisplayName(display_idx);
#elif MY_SDL_MAJOR_VERSION == 3
const char * const display_name = SDL_GetDisplayName(displays[display_idx]);
#endif
if (display_name) {
const size_t display_name_len = strlen(display_name);
if (display_name_len > max_display_name_len) {
max_display_name_len = display_name_len;
}
}
}
if (max_display_name_len < 4) {
max_display_name_len = 4;
}
// print display info table --------------------------------------------------------------------
printf("Display Info:\n");
// print header
printf("idx | ");
#if MY_SDL_MAJOR_VERSION == 3
printf("ID | ");
#endif
printf("%-*s | bounds | usable bounds\n", (int)max_display_name_len, "name");
printf("----|");
#if MY_SDL_MAJOR_VERSION == 3
printf("----|");
#endif
for (int num_dashes_to_print = (int)max_display_name_len + 2; num_dashes_to_print > 0; --num_dashes_to_print) {
printf("-");
}
printf("|-----------------------|----------------------\n");
// loop start
#if MY_SDL_MAJOR_VERSION == 2
for (int display_idx = 0; display_idx < num_video_displays; ++display_idx) {
#elif MY_SDL_MAJOR_VERSION == 3
for (int display_idx = 0; display_idx < display_count; ++display_idx) {
#endif
// print idx
printf("%d | ", display_idx);
// print ID
#if MY_SDL_MAJOR_VERSION == 3
printf("%d | ", displays[display_idx]);
#endif
// print name
#if MY_SDL_MAJOR_VERSION == 2
const char * const display_name = SDL_GetDisplayName(display_idx);
#elif MY_SDL_MAJOR_VERSION == 3
const char * const display_name = SDL_GetDisplayName(displays[display_idx]);
#endif
printf("%-*s | ", (int)max_display_name_len, display_name ? display_name : "NULL");
my_print_SDL_error(display_name);
SDL_Rect display_bounds = {0,0,0,0};
// print display bounds
#if MY_SDL_MAJOR_VERSION == 2
return_value = SDL_GetDisplayBounds(display_idx, &display_bounds) == 0;
#elif MY_SDL_MAJOR_VERSION == 3
return_value = SDL_GetDisplayBounds(displays[display_idx], &display_bounds);
#endif
printf("{%4d,%4d,%4d,%4d} | ", display_bounds.x, display_bounds.y, display_bounds.w, display_bounds.h);
my_print_SDL_error(return_value);
// print display usable bounds
#if MY_SDL_MAJOR_VERSION == 2
return_value = SDL_GetDisplayUsableBounds(display_idx, &display_bounds) == 0;
#elif MY_SDL_MAJOR_VERSION == 3
return_value = SDL_GetDisplayUsableBounds(displays[display_idx], &display_bounds);
#endif
printf("{%4d,%4d,%4d,%4d}", display_bounds.x, display_bounds.y, display_bounds.w, display_bounds.h);
my_print_SDL_error(return_value);
printf("\n");
} // loop end
// cleanup and quit
#if MY_SDL_MAJOR_VERSION == 3
SDL_free(displays);
#endif
SDL_Quit();
return 0;
} My setup:3 displays: 1920x1080, 2560x1440, 1920x1080 Results:I tested SDL2.30.0, SDL2.30.9 and the newest commit of the git master branch for SDL3. Result 1:Panel display: middle
Result 1, is my normal setup(the panel height is bigger for demonstration purposes). For further results, only the display table will be shown, Result 2:Panel display: left or middle or right
When the panel is at the top, the panel-height is added to display bound's y and subtracted from the height to get the usable bounds. Result 3:Panel display: left or right
This result was even more surprising then the second one. The usable bound's height doesn't just get subtracted, it even crops the height of the middle display to 980. Result 4:Panel display: left
Here, everything seems correct. The panel size was added to x and subtracted from the width to get the usable bounds of the left display. Result 5:Panel display: middle or right
Here, the panel was ignored and the usable bounds are the same as the display bounds. Result 6:Panel display: left or middle
The panel was ignored again. Result 7:Panel display: right
This one seems correct again. It was subtracted from the right display's usable bound width. Result Summary:It seems like, if the panel is in between two displays, the panel is ignored and the usable bounds are the same as the display bounds. Were do these values come from?SDL seems to get the usable bounds for a display from an X11 function: SDL/src/video/x11/SDL_x11modes.c Lines 1017 to 1027 in 332fd82
I'm not sure if SDL has any influence on what X11 returns for the usable bounds. And Wayland?With Wayland the panel was always ignored and the returned usable bounds were always the same as the display bounds. |
@Sackzement, can you print out the value of rect and usable in each of those case, before the intersection? I'm guessing the usable rect is relative to the monitor rect, or something like that. |
@Kontrabant, do we expect Wayland to provide usable bounds here? |
No, unfortunately, there is no reliable way to query the usable desktop bounds. We do apply the toplevel window content size hints for resizable windows now though, so even if windows are slightly larger than the usable desktop space, they won't spill off of the edges. |
Here are the results with the rect and usable values right before the intersection: Results 2 and 3 are the problematic ones, because the usable bounds of other displays get cropped as well. Especially in result 3 they get cropped by a lot. This is an illustration of result 3: Panel size: 100 Result 1:Panel display: middle
Result 2:Panel display: left or middle or right
Result 3:Panel display: left or right
Result 4:Panel display: left
Result 5:Panel display: middle or right
Result 6:Panel display: left or middle
Result 7:Panel display: right
|
So that all makes sense. What's happening is that the usable bounds aren't per-monitor, they're a rectangle across all three monitors that is guaranteed not to intersect the panel. Unfortunately, this means that depending on the panel position, we're left with a small rectangle across otherwise completely open monitors. |
Here's someone asking about this on Stack Overflow: |
X-Tile solves this by taking the monitor bounds and subtracting the areas covered by strut windows: |
I'm not sure if this approach is a good one for our purposes or not. @Sackzement, do you want to prototype it up and see how it works on your desktop? In any case, changing how this works needs more testing time than we have for 3.2.0, so I'm bumping it out of the milestone. |
This goes a bit beyond my very little knowledge of X11 and this issue isn't really a priority of mine. |
Thank you for the research, it's very helpful. |
This is the layout (positions and sizes) of my 3 monitors that are side-by side in X11.
My layout is: 1 - 0 - 2 with 0 being my primary display with the taskbars on both top and right side (thus the work area) The issue is then the zeroes on Monitor 2, and I found that removing the right-hand side taskbar OR moving it to the left side, fixes the issue. More detailed environment versioning:
For now I just detect these values and return the screen size since I cannot rely on the error result. |
I'm currently on Ubuntu 24.04 LTS and have an application that is causing an assert due to an incorrect work area.
I am on 2.30.0 (I think this is the default on the OS?)
I tried to look through the logs / issues and did not see anything similar.
Issue:
I am calling SDL_GetDisplayUsableBounds and it returns 0 (success), yet the values are all 0,0,0,0 (SDL_GetError also returns no message)
I have three displays, and the issue seems to occur when I have a reserved area (task bar) on the right- hand side of the preceding display. (left-hand sides are fine)
On my main / middle display I also have a menu bar at the top, but then the side panel as well. And moving the side panel from the left (where SDL_GetDisplayUsableBounds returns the correct bounds for all displays) to the right, seems to break the following display's metrics.
The text was updated successfully, but these errors were encountered: