From 36976ecb43132b25d7286d4fe386600922929207 Mon Sep 17 00:00:00 2001
From: eafton <[EMAIL REDACTED]>
Date: Fri, 21 Nov 2025 02:26:46 +0300
Subject: [PATCH] X11TK: Introduce Thai support and rewrite/cleanup messagebox
positioning code (#14474)
---
CMakeLists.txt | 3 +
cmake/sdlchecks.cmake | 25 +
include/build_config/SDL_build_config.h.cmake | 2 +
src/core/unix/SDL_libthai.c | 76 ++
src/core/unix/SDL_libthai.h | 43 +
src/video/x11/SDL_x11messagebox.c | 333 ++++----
src/video/x11/SDL_x11sym.h | 1 +
src/video/x11/SDL_x11toolkit.c | 742 ++++++++++++------
src/video/x11/SDL_x11toolkit.h | 29 +-
test/testmessage.c | 5 +
10 files changed, 829 insertions(+), 430 deletions(-)
create mode 100644 src/core/unix/SDL_libthai.c
create mode 100644 src/core/unix/SDL_libthai.h
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 150f76fe8e4ea..585119e84a82a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -349,6 +349,8 @@ dep_option(SDL_X11_XSYNC "Enable Xsync support" ON SDL_X11 OFF)
dep_option(SDL_X11_XTEST "Enable XTest support" ON SDL_X11 OFF)
dep_option(SDL_FRIBIDI "Enable Fribidi support" ON SDL_X11 OFF)
dep_option(SDL_FRIBIDI_SHARED "Dynamically load Fribidi support" ON "SDL_FRIBIDI;SDL_DEPS_SHARED" OFF)
+dep_option(SDL_LIBTHAI "Enable Thai support" ON SDL_X11 OFF)
+dep_option(SDL_LIBTHAI_SHARED "Dynamically load Thai support" ON "SDL_LIBTHAI;SDL_DEPS_SHARED" OFF)
dep_option(SDL_WAYLAND "Use Wayland video driver" ${UNIX_SYS} "SDL_VIDEO" OFF)
dep_option(SDL_WAYLAND_SHARED "Dynamically load Wayland support" ON "SDL_WAYLAND;SDL_DEPS_SHARED" OFF)
dep_option(SDL_WAYLAND_LIBDECOR "Use client-side window decorations on Wayland" ON "SDL_WAYLAND" OFF)
@@ -1813,6 +1815,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
CheckROCKCHIP()
CheckX11()
CheckFribidi()
+ CheckLibThai()
# Need to check for EGL first because KMSDRM and Wayland depend on it.
CheckEGL()
CheckKMSDRM()
diff --git a/cmake/sdlchecks.cmake b/cmake/sdlchecks.cmake
index 0180eaa124d0a..625c895a5e133 100644
--- a/cmake/sdlchecks.cmake
+++ b/cmake/sdlchecks.cmake
@@ -588,6 +588,31 @@ macro(CheckFribidi)
endif()
endmacro()
+macro(CheckLibThai)
+ if(SDL_LIBTHAI)
+ set(LIBTHAI_PKG_CONFIG_SPEC libthai)
+ set(PC_LIBTHAI_FOUND FALSE)
+ if(PKG_CONFIG_FOUND)
+ pkg_check_modules(PC_LIBTHAI IMPORTED_TARGET ${LIBTHAI_PKG_CONFIG_SPEC})
+ endif()
+ if(PC_LIBTHAI_FOUND)
+ set(HAVE_LIBTHAI TRUE)
+ set(HAVE_LIBTHAI_H 1)
+ if(SDL_LIBTHAI_SHARED AND NOT HAVE_SDL_LOADSO)
+ message(WARNING "You must have SDL_LoadObject() support for dynamic libthai loading")
+ endif()
+ FindLibraryAndSONAME("thai" LIBDIRS ${PC_LIBTHAI_LIBRARY_DIRS})
+ if(SDL_LIBTHAI_SHARED AND THAI_LIB AND HAVE_SDL_LOADSO)
+ set(SDL_LIBTHAI_DYNAMIC "\"${THAI_LIB_SONAME}\"")
+ set(HAVE_LIBTHAI_SHARED TRUE)
+ sdl_include_directories(PRIVATE SYSTEM $<TARGET_PROPERTY:PkgConfig::PC_LIBTHAI,INTERFACE_INCLUDE_DIRECTORIES>)
+ else()
+ sdl_link_dependency(libthai LIBS PkgConfig::PC_LIBTHAI PKG_CONFIG_PREFIX PC_LIBTHAI PKG_CONFIG_SPECS ${LIBTHAI_PKG_CONFIG_SPEC})
+ endif()
+ endif()
+ endif()
+endmacro()
+
macro(WaylandProtocolGen _SCANNER _CODE_MODE _XML _PROTL)
set(_WAYLAND_PROT_C_CODE "${CMAKE_CURRENT_BINARY_DIR}/wayland-generated-protocols/${_PROTL}-protocol.c")
set(_WAYLAND_PROT_H_CODE "${CMAKE_CURRENT_BINARY_DIR}/wayland-generated-protocols/${_PROTL}-client-protocol.h")
diff --git a/include/build_config/SDL_build_config.h.cmake b/include/build_config/SDL_build_config.h.cmake
index 35560da940507..5501d4931021c 100644
--- a/include/build_config/SDL_build_config.h.cmake
+++ b/include/build_config/SDL_build_config.h.cmake
@@ -218,6 +218,8 @@
#cmakedefine HAVE_LIBURING_H 1
#cmakedefine HAVE_FRIBIDI_H 1
#cmakedefine SDL_FRIBIDI_DYNAMIC @SDL_FRIBIDI_DYNAMIC@
+#cmakedefine HAVE_LIBTHAI_H 1
+#cmakedefine SDL_LIBTHAI_DYNAMIC @SDL_LIBTHAI_DYNAMIC@
#cmakedefine HAVE_DDRAW_H 1
#cmakedefine HAVE_DSOUND_H 1
diff --git a/src/core/unix/SDL_libthai.c b/src/core/unix/SDL_libthai.c
new file mode 100644
index 0000000000000..022db50409eb6
--- /dev/null
+++ b/src/core/unix/SDL_libthai.c
@@ -0,0 +1,76 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "SDL_internal.h"
+
+#ifdef HAVE_LIBTHAI_H
+
+#include "SDL_libthai.h"
+
+#ifdef SDL_LIBTHAI_DYNAMIC
+SDL_ELF_NOTE_DLOPEN(
+ "Thai",
+ "Thai language support",
+ SDL_ELF_NOTE_DLOPEN_PRIORITY_SUGGESTED,
+ SDL_LIBTHAI_DYNAMIC
+);
+#endif
+
+
+SDL_LibThai *SDL_LibThai_Create(void)
+{
+ SDL_LibThai *th;
+
+ th = (SDL_LibThai *)SDL_malloc(sizeof(SDL_LibThai));
+ if (!th) {
+ return NULL;
+ }
+
+#ifdef SDL_LIBTHAI_DYNAMIC
+ #define SDL_LIBTHAI_LOAD_SYM(a, x, n, t) x = ((t)SDL_LoadFunction(a->lib, n)); if (!x) { SDL_UnloadObject(a->lib); SDL_free(a); return NULL; }
+
+ th->lib = SDL_LoadObject(SDL_LIBTHAI_DYNAMIC);
+ if (!th->lib) {
+ SDL_free(th);
+ return NULL;
+ }
+
+ SDL_LIBTHAI_LOAD_SYM(th, th->make_cells, "th_make_cells", SDL_LibThaiMakeCells);
+#else
+ th->make_cells = th_make_cells;
+#endif
+
+ return th;
+}
+
+void SDL_LibThai_Destroy(SDL_LibThai *th)
+{
+ if (!th) {
+ return;
+ }
+
+#ifdef SDL_LIBTHAI_DYNAMIC
+ SDL_UnloadObject(th->lib);
+#endif
+
+ SDL_free(th);
+}
+
+#endif
diff --git a/src/core/unix/SDL_libthai.h b/src/core/unix/SDL_libthai.h
new file mode 100644
index 0000000000000..05a3c06fc6643
--- /dev/null
+++ b/src/core/unix/SDL_libthai.h
@@ -0,0 +1,43 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "SDL_internal.h"
+
+#ifndef SDL_libthai_h_
+#define SDL_libthai_h_
+
+#ifdef HAVE_LIBTHAI_H
+#include <thai/thcell.h>
+
+typedef size_t (*SDL_LibThaiMakeCells)(const thchar_t *s, size_t, struct thcell_t cells[], size_t *, int);
+
+typedef struct SDL_LibThai {
+ SDL_SharedObject *lib;
+
+ SDL_LibThaiMakeCells make_cells;
+} SDL_LibThai;
+
+extern SDL_LibThai *SDL_LibThai_Create(void);
+extern void SDL_LibThai_Destroy(SDL_LibThai *th);
+
+#endif // HAVE_LIBTHAI_H
+
+#endif // SDL_libthai_h_
diff --git a/src/video/x11/SDL_x11messagebox.c b/src/video/x11/SDL_x11messagebox.c
index 158a65b45e268..8486c7a292d6d 100644
--- a/src/video/x11/SDL_x11messagebox.c
+++ b/src/video/x11/SDL_x11messagebox.c
@@ -28,7 +28,7 @@
#include "SDL_x11toolkit.h"
#ifndef SDL_FORK_MESSAGEBOX
-#define SDL_FORK_MESSAGEBOX 1
+#define SDL_FORK_MESSAGEBOX 0
#endif
#if SDL_FORK_MESSAGEBOX
@@ -38,246 +38,181 @@
#include <errno.h>
#endif
-typedef struct SDL_MessageBoxCallbackDataX11
-{
- int *buttonID;
- SDL_ToolkitWindowX11 *window;
-} SDL_MessageBoxCallbackDataX11;
-
-typedef struct SDL_MessageBoxControlsX11
+typedef struct SDL_MessageBoxX11
{
SDL_ToolkitWindowX11 *window;
SDL_ToolkitControlX11 *icon;
- SDL_ToolkitControlX11 fake_icon;
SDL_ToolkitControlX11 *message;
SDL_ToolkitControlX11 **buttons;
const SDL_MessageBoxData *messageboxdata;
-} SDL_MessageBoxControlsX11;
+ int *buttonID;
+} SDL_MessageBoxX11;
static void X11_MessageBoxButtonCallback(SDL_ToolkitControlX11 *control, void *data)
{
- SDL_MessageBoxCallbackDataX11 *cbdata;
+ SDL_MessageBoxX11 *cbdata;
- cbdata = (SDL_MessageBoxCallbackDataX11 *)data;
+ cbdata = data;
*cbdata->buttonID = X11Toolkit_GetButtonControlData(control)->buttonID;
X11Toolkit_SignalWindowClose(cbdata->window);
}
-static void X11_PositionMessageBox(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;
+static void X11_PositionMessageBox(SDL_MessageBoxX11 *controls, int *wp, int *hp) {
+ int first_line_width;
+ int first_line_height;
+ int second_line_width;
+ int second_line_height;
+ int max_button_width;
+ int max_button_height;
+ int window_width;
+ int window_height;
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.x = controls->icon->rect.y = 0;
- }
-
- if (controls->icon) {
- controls->message->rect.x = (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale) + controls->icon->rect.x + controls->icon->rect.w;
- controls->message->rect.y = X11Toolkit_GetIconControlCharY(controls->icon);
+ bool rtl;
+
+ /* window size */
+ window_width = 1;
+ window_height = 1;
+
+ /* rtl */
+ if (controls->messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) {
+ rtl = true;
+ } else if (controls->messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_LEFT_TO_RIGHT) {
+ rtl = false;
} else {
+ rtl = controls->window->flip_interface;
+ }
+
+ /* first line */
+ first_line_width = first_line_height = 0;
+ if (controls->icon && controls->message) {
+ controls->icon->rect.y = 0;
+
+ first_line_width = controls->icon->rect.w + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale + controls->message->rect.w;
+
+ if (!controls->window->flip_interface) {
+ controls->message->rect.x = controls->icon->rect.w + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
+ controls->icon->rect.x = 0;
+ } else {
+ controls->message->rect.x = 0;
+ controls->icon->rect.x = controls->message->rect.w + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;;
+ }
+
+ if (controls->message->rect.h > controls->icon->rect.h) {
+ controls->message->rect.y = (controls->icon->rect.h - X11Toolkit_GetLabelControlFirstLineHeight(controls->message))/2;
+ first_line_height = controls->message->rect.y + controls->message->rect.h;
+ } else {
+ controls->message->rect.y = (controls->icon->rect.h - controls->message->rect.h)/2;
+ first_line_height = controls->icon->rect.h;
+ }
+ } else if (!controls->icon && controls->message) {
+ first_line_width = controls->message->rect.w;
+ first_line_height = controls->message->rect.h;
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->message->rect.y = 0;
+ } else if (controls->icon && !controls->message) {
+ first_line_width = controls->icon->rect.w;
+ first_line_height = controls->icon->rect.h;
controls->icon->rect.x = 0;
- controls->icon->rect.y = 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;
+
+ /* second line */
+ max_button_width = 50;
+ max_button_height = 0;
+ second_line_width = second_line_height = 0;
+
+ for (i = 0; i < controls->messageboxdata->numbuttons; i++) {
+ max_button_width = SDL_max(max_button_width, controls->buttons[i]->rect.w);
+ max_button_height = SDL_max(max_button_height, controls->buttons[i]->rect.h);
+ controls->buttons[i]->rect.x = 0;
+ controls->buttons[i]->rect.y = 0;
+ }
+
+ if (rtl) {
+ for (i = (controls->messageboxdata->numbuttons - 1); i != -1; i--) {
+ controls->buttons[i]->rect.w = max_button_width;
+ controls->buttons[i]->rect.h = max_button_height;
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);
+ if (first_line_height) {
+ controls->buttons[i]->rect.y = first_line_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_4 * controls->window->iscale;
+ second_line_height = max_button_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_4 * controls->window->iscale;
} else {
- controls->buttons[i]->rect.y = controls->message->rect.h + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
+ second_line_height = max_button_height;
}
-
- 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);
+
+ if ((i + 1) < controls->messageboxdata->numbuttons) {
+ 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;
+ controls->buttons[i]->rect.w = max_button_width;
+ controls->buttons[i]->rect.h = max_button_height;
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);
+ if (first_line_height) {
+ controls->buttons[i]->rect.y = first_line_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_4 * controls->window->iscale;
+ second_line_height = max_button_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_4 * controls->window->iscale;
} else {
- controls->buttons[i]->rect.y = controls->message->rect.h + (SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale);
+ second_line_height = max_button_height;
}
-
+
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.x + controls->message->rect.w;
- 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_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->numbuttons) {
+ if (rtl) {
+ second_line_width = controls->buttons[0]->rect.x + controls->buttons[0]->rect.w;
+ } else {
+ second_line_width = controls->buttons[controls->messageboxdata->numbuttons - 1]->rect.x + controls->buttons[controls->messageboxdata->numbuttons - 1]->rect.w;
+ }
}
- 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);
- }
+ /* center lines */
+ if (second_line_width > first_line_width) {
+ int pad;
+
+ pad = (second_line_width - first_line_width)/2;
+ if (controls->message) {
+ controls->message->rect.x += pad;
+ }
+ if (controls->icon) {
+ controls->icon->rect.x += pad;
}
} else {
+ int pad;
+
+ pad = (first_line_width - second_line_width)/2;
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);
- }
+ controls->buttons[i]->rect.x += pad;
}
}
- 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;
+
+ /* window size and final padding */
+ window_width = SDL_max(first_line_width, second_line_width) + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * 2 * controls->window->iscale;
+ window_height = first_line_height + second_line_height + SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * 2 * controls->window->iscale;
+ *wp = window_width;
+ *hp = window_height;
+ if (controls->message) {
+ controls->message->rect.x += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
+ controls->message->rect.y += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
}
- 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;
+ if (controls->icon) {
+ controls->icon->rect.x += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
+ controls->icon->rect.y += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
}
- 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);
+ controls->buttons[i]->rect.x += SDL_TOOLKIT_X11_ELEMENT_PADDING_2 * controls->window->iscale;
+ 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) {
- SDL_MessageBoxControlsX11 *controls;
+ SDL_MessageBoxX11 *controls;
int w;
int h;
@@ -290,8 +225,7 @@ static bool X11_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int
{
SDL_VideoDevice *video = SDL_GetVideoDevice();
SDL_Window *parent_window = NULL;
- SDL_MessageBoxControlsX11 controls;
- SDL_MessageBoxCallbackDataX11 data;
+ SDL_MessageBoxX11 controls;
const SDL_MessageBoxColor *colorhints;
int i;
int w;
@@ -323,22 +257,17 @@ static bool X11_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int
}
/* Create controls */
+ controls.buttonID = buttonID;
controls.buttons = SDL_calloc(messageboxdata->numbuttons, sizeof(SDL_ToolkitControlX11 *));
controls.icon = X11Toolkit_CreateIconControl(controls.window, messageboxdata->flags);
controls.message = X11Toolkit_CreateLabelControl(controls.window, (char *)messageboxdata->message);
- data.buttonID = buttonID;
- data.window = controls.window;
for (i = 0; i < messageboxdata->numbuttons; i++) {
controls.buttons[i] = X11Toolkit_CreateButtonControl(controls.window, &messageboxdata->buttons[i]);
- X11Toolkit_RegisterCallbackForButtonControl(controls.buttons[i], &data, X11_MessageBoxButtonCallback);
+ X11Toolkit_RegisterCallbackForButtonControl(controls.buttons[i], &controls, X11_MessageBoxButtonCallback);
}
/* Positioning */
- if (data.window->flip_interface) {
- X11_PositionMessageBoxFlipped(&controls, &w, &h);
- } else {
- X11_PositionMessageBox(&controls, &w, &h);
- }
+ X11_PositionMessageBox(&controls, &w, &h);
/* Actually create window, do event loop, cleanup */
X11Toolkit_CreateWindowRes(controls.window, w, h, 0, 0, (char *)messageboxdata->title);
diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h
index 62c3e00237ff3..1e0db473cf217 100644
--- a/src/video/x11/SDL_x11sym.h
+++ b/src/video/x11/SDL_x11sym.h
@@ -56,6 +56,7 @@ SDL_X11_SYM(int,XDeleteProperty,(Display* a,Window b,Atom c))
SDL_X11_SYM(int,XDestroyWindow,(Display* a,Window b))
SDL_X11_SYM(int,XDisplayKeycodes,(Display* a,int* b,int* c))
SDL_X11_SYM(int,XDrawRectangle,(Display* a,Drawable b,GC c,int d,int e,unsigned int f,unsigned int g))
+SDL_X11_SYM(int,XFontsOfFontSet,(XFontSet a,XFontStruct ***b,char ***c))
SDL_X11_SYM(int,XFillArc,(Display* a,Drawable b,GC c,int d,int e,unsigned int f,unsigned int g, int h, int i))
SDL_X11_SYM(char*,XDisplayName,(_Xconst char* a))
SDL_X11_SYM(int,XDrawString,(Display* a,Drawable b,GC c,int d,int e,_Xconst char* f,int g))
diff --git a/src/video/x11/SDL_x11toolkit.c b/src/video/x11/SDL_x11toolkit.c
index 6f895fbd784d8..f690c72cca5db 100644
--- a/src/video/x11/SDL_x11toolkit.c
+++ b/src/video/x11/SDL_x11toolkit.c
@@ -42,6 +42,35 @@
#define SDL_SET_LOCALE 1
#define SDL_GRAB 1
+typedef enum SDL_ToolkitTextTypeX11
+{
+ SDL_TOOLKIT_TEXT_TYPE_X11_GENERIC,
+ SDL_TOOLKIT_TEXT_TYPE_X11_THAI
+} SDL_ToolkitTextTypeX11;
+
+#ifdef HAVE_LIBTHAI_H
+typedef struct SDL_ToolkitThaiOverlayX11
+{
+ bool top;
+ char *str;
+ size_t sz;
+ SDL_Rect rect;
+} SDL_ToolkitThaiOverlayX11;
+#endif
+
+typedef struct SDL_ToolkitTextElementX11
+{
+ SDL_ToolkitTextTypeX11 type;
+ char *str;
+ size_t sz;
+ SDL_Rect rect;
+ int font_h;
+ void (*str_free)(void *);
+#ifdef HAVE_LIBTHAI_H
+ SDL_ListNode *thai_overlays;
+#endif
+} SDL_ToolkitTextElementX11;
+
typedef struct SDL_ToolkitIconControlX11
{
SDL_ToolkitControlX11 parent;
@@ -75,25 +104,28 @@ typedef struct SDL_ToolkitButtonControlX11
const SDL_MessageBoxButtonData *data;
/* Text */
+ SDL_ListNode *text;
SDL_Rect text_rect;
- int text_a;
- int text_d;
- int str_sz;
-#ifdef HAVE_FRIBIDI_H
- char *text;
- bool free_text;
-#endif
-
+
/* Callback */
void *cb_data;
void (*cb)(struct SDL_ToolkitControlX11 *, void *);
} SDL_ToolkitButtonControlX11;
+typedef struct SDL_ToolkitLabelControlLineX11
+{
+ SDL_ListNode *text;
+ SDL_Rect rect;
+#ifdef HAVE_FRIBIDI_H
+ FriBidiParType par;
+#endif
+} SDL_ToolkitLabelControlLineX11;
+
typedef struct SDL_ToolkitLabelControlX11
{
SDL_ToolkitControlX11 parent;
- char **lines;
+ /* char **lines;
int *y;
size_t *szs;
size_t sz;
@@ -102,7 +134,9 @@ typedef struct SDL_ToolkitLabelControlX11
int *w;
bool *free_lines;
FriBidiParType *par_types;
-#endif
+#endif*/
+ SDL_ToolkitLabelControlLineX11 *lines;
+ size_t sz;
} SDL_ToolkitLabelControlX11;
typedef struct SDL_ToolkitMenuBarControlX11
@@ -258,7 +292,9 @@ static void X11Toolkit_InitWindowPixmap(SDL_ToolkitWindowX11 *data) {
}
static void X11Toolkit_InitWindowFonts(SDL_ToolkitWindowX11 *window)
-{
+{
+ window->thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_NONE;
+ window->thai_font = SDL_TOOLKIT_THAI_FONT_X11_CELL;
#ifdef X_HAVE_UTF8_STRING
window->utf8 = true;
window->font_set = NULL;
@@ -301,9 +337,56 @@ static void X11Toolkit_InitWindowFonts(SDL_ToolkitWindowX11 *window)
if (!window->font_set) {
goto load_font_traditional;
} else {
+ XFontStruct **font_structs;
+ char **font_names;
+ int font_sz;
+ int i;
+
#ifdef HAVE_FRIBIDI_H
window->do_shaping = !X11_XContextDependentDrawing(window->font_set);
#endif
+ /* TODO: What to do the XFontSet happens to have more than one Thai font? */
+ font_sz = X11_XFontsOfFontSet(window->font_set, &font_structs, &font_names);
+ for (i = 0; i < font_sz; i++) {
+ SDL_ToolkitThaiEncodingX11 thai_encoding;
+
+ thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_NONE;
+ if (SDL_strstr(font_names[i], "tis620-0")) {
+ thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_TIS;
+ } else if (SDL_strstr(font_names[i], "tis620-1")) {
+ thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_TIS_MAC;
+ } else if (SDL_strstr(font_names[i], "tis620-2")) {
+ thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_TIS_WIN;
+ } else if (SDL_strstr(font_names[i], "iso8859-11")) {
+ thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_8859;
+ } else if (SDL_strstr(font_names[i], "iso10646-1")) {
+ thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_UNICODE;
+ }
+
+
(Patch may be truncated, please check the link at the top of this post.)