X11TK: Flip the positioning of the UI if the locale is RTL (#14183)

This commit is contained in:
eafton
2025-10-09 17:48:10 +03:00
committed by GitHub
parent 09bd8e8a5a
commit 2c0094ead6
3 changed files with 165 additions and 10 deletions

View File

@@ -96,7 +96,7 @@ static void X11_PositionMessageBox(SDL_MessageBoxControlsX11 *controls, int *wp,
controls->message->rect.y = X11Toolkit_GetIconControlCharY(controls->icon); controls->message->rect.y = X11Toolkit_GetIconControlCharY(controls->icon);
} else { } else {
controls->message->rect.x = 0; controls->message->rect.x = 0;
controls->message->rect.y = -2; controls->message->rect.y = -2 * controls->window->iscale;
controls->icon = &controls->fake_icon; controls->icon = &controls->fake_icon;
controls->icon->rect.w = 0; controls->icon->rect.w = 0;
controls->icon->rect.h = 0; controls->icon->rect.h = 0;
@@ -168,6 +168,114 @@ static void X11_PositionMessageBox(SDL_MessageBoxControlsX11 *controls, int *wp,
*hp = h; *hp = h;
} }
static void X11_PositionMessageBoxFlipped(SDL_MessageBoxControlsX11 *controls, int *wp, int *hp)
{
int max_button_w;
int max_button_h;
int total_button_w;
int total_text_and_icon_w;
int w;
int h;
int i;
int t;
/* Init vars */
max_button_w = 50;
max_button_h = 0;
w = h = 2;
i = t = total_button_w = total_text_and_icon_w = 0;
max_button_w *= controls->window->iscale;
/* Positioning and sizing */
for (i = 0; i < controls->messageboxdata->numbuttons; i++) {
max_button_w = SDL_max(max_button_w, controls->buttons[i]->rect.w);
max_button_h = SDL_max(max_button_h, controls->buttons[i]->rect.h);
controls->buttons[i]->rect.x = 0;
}
if (controls->icon) {
controls->icon->rect.y = 0;
}
if (controls->icon) {
controls->message->rect.x = 0;
controls->message->rect.y = X11Toolkit_GetIconControlCharY(controls->icon);
controls->icon->rect.x = (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale) + controls->message->rect.w + controls->message->rect.x;
} else {
controls->message->rect.x = 0;
controls->message->rect.y = -2 * controls->window->iscale;
controls->icon = &controls->fake_icon;
controls->icon->rect.w = 0;
controls->icon->rect.h = 0;
controls->icon->rect.x = 0;
controls->icon->rect.y = 0;
}
if (controls->messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) {
for (i = controls->messageboxdata->numbuttons; i != -1; i--) {
controls->buttons[i]->rect.w = max_button_w;
controls->buttons[i]->rect.h = max_button_h;
X11Toolkit_NotifyControlOfSizeChange(controls->buttons[i]);
if (controls->icon->rect.h > controls->message->rect.h) {
controls->buttons[i]->rect.y = controls->icon->rect.h + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 *controls-> window->iscale);
} else {
controls->buttons[i]->rect.y = controls->message->rect.h + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
}
if (i) {
controls->buttons[i]->rect.x = controls->buttons[i-1]->rect.x + controls->buttons[i-1]->rect.w + (SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * controls->window->iscale);
}
}
} else {
for (i = 0; i < controls->messageboxdata->numbuttons; i++) {
controls->buttons[i]->rect.w = max_button_w;
controls->buttons[i]->rect.h = max_button_h;
X11Toolkit_NotifyControlOfSizeChange(controls->buttons[i]);
if (controls->icon->rect.h > controls->message->rect.h) {
controls->buttons[i]->rect.y = controls->icon->rect.h + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
} else {
controls->buttons[i]->rect.y = controls->message->rect.h + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
}
if (i) {
controls->buttons[i]->rect.x = controls->buttons[i-1]->rect.x + controls->buttons[i-1]->rect.w + (SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * controls->window->iscale);
}
}
}
total_button_w = controls->buttons[controls->messageboxdata->numbuttons-1]->rect.x + controls->buttons[controls->messageboxdata->numbuttons-1]->rect.w;
total_text_and_icon_w = controls->message->rect.w + controls->icon->rect.w + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
if (total_button_w > total_text_and_icon_w) {
w = total_button_w;
} else {
w = total_text_and_icon_w;
}
w += (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale) * 2;
if (controls->message->rect.h > controls->icon->rect.h) {
h = controls->message->rect.h;
} else {
h = controls->icon->rect.h;
}
h += max_button_h + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale) * 3;
t = (w - total_text_and_icon_w) / 2;
controls->icon->rect.x += t;
controls->message->rect.x += t;
controls->icon->rect.y += (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
controls->message->rect.y += (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
t = (w - total_button_w) / 2;
for (i = 0; i < controls->messageboxdata->numbuttons; i++) {
controls->buttons[i]->rect.x += t;
controls->buttons[i]->rect.y += (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
}
if (!controls->messageboxdata->message) {
controls->icon->rect.x = (w - controls->icon->rect.w)/2;
}
*wp = w;
*hp = h;
}
static void X11_OnMessageBoxScaleChange(SDL_ToolkitWindowX11 *window, void *data) { static void X11_OnMessageBoxScaleChange(SDL_ToolkitWindowX11 *window, void *data) {
SDL_MessageBoxControlsX11 *controls; SDL_MessageBoxControlsX11 *controls;
int w; int w;
@@ -220,7 +328,11 @@ static bool X11_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int
} }
/* Positioning */ /* Positioning */
X11_PositionMessageBox(&controls, &w, &h); if (data.window->flip_interface) {
X11_PositionMessageBoxFlipped(&controls, &w, &h);
} else {
X11_PositionMessageBox(&controls, &w, &h);
}
/* Actually create window, do event loop, cleanup */ /* Actually create window, do event loop, cleanup */
X11Toolkit_CreateWindowRes(controls.window, w, h, 0, 0, (char *)messageboxdata->title); X11Toolkit_CreateWindowRes(controls.window, w, h, 0, 0, (char *)messageboxdata->title);

View File

@@ -603,6 +603,42 @@ static void X11Toolkit_GetTextWidthHeight(SDL_ToolkitWindowX11 *data, const char
} }
} }
static bool X11Toolkit_ShouldFlipUI(void)
{
SDL_Locale **current_locales;
static const SDL_Locale rtl_locales[] = {
{ "ar", NULL, },
{ "fa", "AF", },
{ "fa", "IR", },
{ "he", NULL, },
{ "iw", NULL, },
{ "yi", NULL, },
{ "ur", NULL, },
{ "ug", NULL, },
{ "kd", NULL, },
{ "pk", "PK", },
{ "ps", NULL, }
};
int current_locales_sz;
int i;
current_locales = SDL_GetPreferredLocales(&current_locales_sz);
if (current_locales_sz <= 0) {
return false;
}
for (i = 0; i < SDL_arraysize(rtl_locales); ++i) {
if (SDL_startswith(current_locales[0]->language, rtl_locales[i].language)) {
if (!rtl_locales[i].country) {
return true;
} else {
return SDL_startswith(current_locales[0]->country, rtl_locales[i].country);
}
}
}
return false;
}
SDL_ToolkitWindowX11 *X11Toolkit_CreateWindowStruct(SDL_Window *parent, SDL_ToolkitWindowX11 *tkparent, SDL_ToolkitWindowModeX11 mode, const SDL_MessageBoxColor *colorhints, bool create_new_display) SDL_ToolkitWindowX11 *X11Toolkit_CreateWindowStruct(SDL_Window *parent, SDL_ToolkitWindowX11 *tkparent, SDL_ToolkitWindowModeX11 mode, const SDL_MessageBoxColor *colorhints, bool create_new_display)
{ {
SDL_ToolkitWindowX11 *window; SDL_ToolkitWindowX11 *window;
@@ -809,9 +845,14 @@ SDL_ToolkitWindowX11 *X11Toolkit_CreateWindowStruct(SDL_Window *parent, SDL_Tool
/* Menu windows */ /* Menu windows */
window->popup_windows = NULL; window->popup_windows = NULL;
/* BIDI engine */
#ifdef HAVE_FRIBIDI_H #ifdef HAVE_FRIBIDI_H
window->fribidi = SDL_FriBidi_Create(); window->fribidi = SDL_FriBidi_Create();
#endif #endif
/* Interface direction */
window->flip_interface = X11Toolkit_ShouldFlipUI();
return window; return window;
} }

View File

@@ -72,9 +72,9 @@ typedef struct SDL_ToolkitWindowX11
Window window; Window window;
Drawable drawable; Drawable drawable;
#ifndef NO_SHARED_MEMORY #ifndef NO_SHARED_MEMORY
XImage *image; XImage *image;
XShmSegmentInfo shm_info; XShmSegmentInfo shm_info;
int shm_bytes_per_line; int shm_bytes_per_line;
#endif #endif
/* Visuals and drawing */ /* Visuals and drawing */
@@ -94,8 +94,8 @@ typedef struct SDL_ToolkitWindowX11
bool xrandr; // Whether Xrandr is present or not bool xrandr; // Whether Xrandr is present or not
#endif #endif
#ifndef NO_SHARED_MEMORY #ifndef NO_SHARED_MEMORY
bool shm; bool shm;
Bool shm_pixmap; Bool shm_pixmap;
#endif #endif
bool utf8; bool utf8;
/* Atoms */ /* Atoms */
@@ -160,9 +160,11 @@ typedef struct SDL_ToolkitWindowX11
#ifdef HAVE_FRIBIDI_H #ifdef HAVE_FRIBIDI_H
/* BIDI engine */ /* BIDI engine */
SDL_FriBidi *fribidi; SDL_FriBidi *fribidi;
bool do_shaping; bool do_shaping;
#endif #endif
bool flip_interface;
} SDL_ToolkitWindowX11; } SDL_ToolkitWindowX11;
typedef enum SDL_ToolkitControlStateX11 typedef enum SDL_ToolkitControlStateX11
@@ -183,7 +185,7 @@ typedef struct SDL_ToolkitControlX11
bool dynamic; bool dynamic;
bool is_default_enter; bool is_default_enter;
bool is_default_esc; bool is_default_esc;
bool do_size; bool do_size;
/* User data */ /* User data */
void *data; void *data;