X11TK: Introduce Thai support and rewrite/cleanup messagebox positioning code (#14474)

This commit is contained in:
eafton
2025-11-21 02:26:46 +03:00
committed by GitHub
parent 92eaa34277
commit 36976ecb43
10 changed files with 840 additions and 441 deletions

View File

@@ -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()

View File

@@ -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")

View File

@@ -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

View File

@@ -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

View File

@@ -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_

View File

@@ -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);
} 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;
}
bool rtl;
/* window size */
window_width = 1;
window_height = 1;
/* rtl */
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;
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 = 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;
}
/* 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;
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;
}
}
*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->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);

View File

@@ -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))

View File

@@ -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;
}
/* TODO: Set encoding to none if the font does not actually have any Thai codepoints */
if (thai_encoding != SDL_TOOLKIT_THAI_ENCODING_X11_NONE) {
XFontStruct *font_struct;
/* We have to load the font again because the font_struct supplied by FontsOfFontSet does not have the per_char member set */
font_struct = X11_XLoadQueryFont(window->display, font_names[i]);
if (font_struct) {
if (font_struct->per_char) {
int glyphs_sz;
int j;
glyphs_sz = (font_struct->max_char_or_byte2 - font_struct->min_char_or_byte2 + 1) * (font_struct->max_byte1 - font_struct->min_byte1 + 1);
for (j = 0; j < glyphs_sz; j++) {
if (font_struct->per_char[j].lbearing < 0) {
window->thai_font = SDL_TOOLKIT_THAI_FONT_X11_OFFSET;
}
}
}
X11_XFreeFont(window->display, font_struct);
}
}
window->thai_encoding = thai_encoding;
}
}
} else
#endif
@@ -445,16 +528,18 @@ static void X11Toolkit_SettingsNotify(const char *name, XSettingsAction action,
}
}
static void X11Toolkit_GetTextWidthHeightForFont(XFontStruct *font, const char *str, int nbytes, int *pwidth, int *pheight, int *ascent)
static void X11Toolkit_GetTextWidthHeightForFont(XFontStruct *font, const char *str, int nbytes, int *pwidth, int *pheight, int *ascent, int *font_height)
{
XCharStruct text_structure;
int font_direction, font_ascent, font_descent;
X11_XTextExtents(font, str, nbytes,
&font_direction, &font_ascent, &font_descent,
&text_structure);
X11_XTextExtents(font, str, nbytes, &font_direction, &font_ascent, &font_descent, &text_structure);
*pwidth = text_structure.width;
*pheight = text_structure.ascent + text_structure.descent;
*ascent = text_structure.ascent;
if (font_height) {
*font_height = font_ascent + font_descent;
}
}
static void X11Toolkit_GetTextWidthHeight(SDL_ToolkitWindowX11 *data, const char *str, int nbytes, int *pwidth, int *pheight, int *ascent, int *descent, int *font_height)
@@ -494,6 +579,335 @@ static void X11Toolkit_GetTextWidthHeight(SDL_ToolkitWindowX11 *data, const char
}
}
#ifdef HAVE_FRIBIDI_H
SDL_ListNode *X11Toolkit_MakeTextElements(SDL_ToolkitWindowX11 *data, char *txt, size_t sz, FriBidiParType *par)
#else
SDL_ListNode *X11Toolkit_MakeTextElements(SDL_ToolkitWindowX11 *data, char *txt, size_t sz)
#endif
{
SDL_ListNode *list;
char *str;
char *buffer;
Uint32 cp;
bool thai;
bool free_txt;
free_txt = false;
list = NULL;
thai = 0;
str = txt;
buffer = SDL_malloc(1);
buffer[0] = 0;
#ifdef HAVE_FRIBIDI_H
if (par) {
*par = FRIBIDI_PAR_LTR;
}
if (data->fribidi) {
char *fstr;
fstr = SDL_FriBidi_Process(data->fribidi, str, sz, data->do_shaping, par);
if (fstr) {
txt = fstr;
str = fstr;
sz = SDL_strlen(str);
free_txt = true;
}
}
#endif
while (1) {
char *new;
char utf8[5];
size_t csz;
bool cond;
SDL_memset(utf8, 0, 5);
cp = SDL_StepUTF8((const char **)&str, &sz);
cond = (0xe00 <= cp && cp <= 0xe7f) ? true : false;
if (cp == 0 || cond == (thai ? false : true)) {
SDL_ToolkitTextElementX11 *element;
element = SDL_malloc(sizeof(SDL_ToolkitTextElementX11));
if (thai) {
element->type = SDL_TOOLKIT_TEXT_TYPE_X11_THAI;
} else {
element->type = SDL_TOOLKIT_TEXT_TYPE_X11_GENERIC;
}
element->str = SDL_strdup(buffer);
element->sz = SDL_strlen(buffer);
element->str_free = SDL_free;
SDL_ListAdd(&list, element);
SDL_free(buffer);
buffer = SDL_malloc(1);
buffer[0] = 0;
thai = thai ? false : true;
}
if (!cp) {
break;
}
SDL_UCS4ToUTF8(cp, utf8);
csz = SDL_strlen(buffer) + SDL_strlen(utf8) + 1;
new = SDL_malloc(csz);
SDL_strlcpy(new, buffer, csz);
SDL_strlcat(new, utf8, csz);
SDL_free(buffer);
buffer = new;
}
SDL_free(buffer);
if (free_txt) {
SDL_free(txt);
}
return list;
}
void X11Toolkit_ShapeTextElements(SDL_ToolkitWindowX11 *data, SDL_ListNode *list)
{
SDL_ListNode *cursor;
SDL_ToolkitTextElementX11 *prev;
int temp;
/* Shape and calculate bounding box */
cursor = list;
while (cursor) {
SDL_ToolkitTextElementX11 *element;
element = cursor->entry;
#ifdef HAVE_LIBTHAI_H
element->thai_overlays = NULL;
#endif
if (element->type == SDL_TOOLKIT_TEXT_TYPE_X11_THAI) {
if (data->thai_font == SDL_TOOLKIT_THAI_FONT_X11_OFFSET) {
X11Toolkit_GetTextWidthHeight(data, element->str, element->sz, &element->rect.w, &element->rect.h, &element->rect.y, &temp, NULL);
} else {
#ifdef HAVE_LIBTHAI_H
if (data->th) {
struct thcell_t *cells;
char *tis_str;
char *base_tis_str;
size_t cells_sz;
size_t base_tis_str_sz;
size_t tis_str_sz;
tis_str = SDL_iconv_string("TIS-620", "UTF-8", element->str, element->sz);
cells_sz = tis_str_sz = SDL_strlen(tis_str);
cells = SDL_calloc(cells_sz, sizeof(struct thcell_t));
data->th->make_cells((const thchar_t *)tis_str, tis_str_sz, cells, &cells_sz, 0);
base_tis_str_sz = cells_sz;
base_tis_str = SDL_malloc(base_tis_str_sz + 1);
for (temp = 0; temp < cells_sz; temp++) {
base_tis_str[temp] = cells[temp].base;
if (cells[temp].hilo) {
SDL_ToolkitThaiOverlayX11 *overlay;
char *pre;
int temp2;
overlay = SDL_malloc(sizeof(SDL_ToolkitThaiOverlayX11));
pre = SDL_iconv_string("UTF-8", "TIS-620", base_tis_str, temp);
overlay->str = SDL_iconv_string("UTF-8", "TIS-620", (const char *)&cells[temp].hilo, 1);
overlay->sz = SDL_strlen(overlay->str);
overlay->top = false;
X11Toolkit_GetTextWidthHeight(data, pre, SDL_strlen(pre), &overlay->rect.x, &temp2, &temp2, &temp2, NULL);
X11Toolkit_GetTextWidthHeight(data, overlay->str, overlay->sz, &overlay->rect.w, &overlay->rect.h, &overlay->rect.y, &temp2, NULL);
SDL_ListAdd(&element->thai_overlays, overlay);
SDL_free(pre);
}
if (cells[temp].top) {
SDL_ToolkitThaiOverlayX11 *overlay;
char *pre;
int temp2;
overlay = SDL_malloc(sizeof(SDL_ToolkitThaiOverlayX11));
pre = SDL_iconv_string("UTF-8", "TIS-620", base_tis_str, temp);
overlay->str = SDL_iconv_string("UTF-8", "TIS-620", (const char *)&cells[temp].top, 1);
overlay->sz = SDL_strlen(overlay->str);
overlay->top = true;
X11Toolkit_GetTextWidthHeight(data, pre, SDL_strlen(pre), &overlay->rect.x, &temp2, &temp2, &temp2, NULL);
X11Toolkit_GetTextWidthHeight(data, overlay->str, overlay->sz, &overlay->rect.w, &overlay->rect.h, &overlay->rect.y, &temp2, NULL);
SDL_ListAdd(&element->thai_overlays, overlay);
SDL_free(pre);
}
}
base_tis_str[base_tis_str_sz] = '\0';
element->str_free(element->str);
element->str = SDL_iconv_string("UTF-8", "TIS-620", base_tis_str, base_tis_str_sz);
element->sz = SDL_strlen(element->str);
X11Toolkit_GetTextWidthHeight(data, element->str, element->sz, &element->rect.w, &element->rect.h, &element->rect.y, &temp, &element->font_h);
SDL_free(tis_str);
SDL_free(cells);
SDL_free(base_tis_str);
}
#else
X11Toolkit_GetTextWidthHeight(data, element->str, element->sz, &element->rect.w, &element->rect.h, &element->rect.y, &temp, &element->font_h);
#endif
}
} else {
X11Toolkit_GetTextWidthHeight(data, element->str, element->sz, &element->rect.w, &element->rect.h, &element->rect.y, &temp, &element->font_h);
}
cursor = cursor->next;
}
/* Add offsets */
prev = NULL;
cursor = list;
while (cursor) {
SDL_ToolkitTextElementX11 *element;
element = cursor->entry;
if (prev) {
element->rect.x = prev->rect.x + prev->rect.w;
} else {
element->rect.x = 0;
}
prev = element;
cursor = cursor->next;
}
}
void X11Toolkit_DrawTextElements(SDL_ToolkitWindowX11 *data, SDL_ListNode *list, int x, int y)
{
SDL_ListNode *cursor;
cursor = list;
while (cursor) {
SDL_ToolkitTextElementX11 *element;
element = cursor->entry;
if (element->type == SDL_TOOLKIT_TEXT_TYPE_X11_THAI) {
if (data->thai_font == SDL_TOOLKIT_THAI_FONT_X11_OFFSET) {
#ifdef X_HAVE_UTF8_STRING
if (data->utf8) {
X11_Xutf8DrawString(data->display, data->drawable, data->font_set, data->ctx, x + element->rect.x, y + element->rect.y, element->str, element->sz);
} else
#endif
{
X11_XDrawString(data->display, data->drawable, data->ctx, x + element->rect.x, y + element->rect.y, element->str, element->sz);
}
} else {
#ifdef HAVE_LIBTHAI_H
SDL_ListNode *overlay_cursor;
/* Draw the base string */
#ifdef X_HAVE_UTF8_STRING
if (data->utf8) {
X11_Xutf8DrawString(data->display, data->drawable, data->font_set, data->ctx, x + element->rect.x, y + element->rect.y, element->str, element->sz);
} else
#endif
{
X11_XDrawString(data->display, data->drawable, data->ctx, x + element->rect.x, y + element->rect.y, element->str, element->sz);
}
/* Draw overlays */
overlay_cursor = element->thai_overlays;
while (overlay_cursor) {
SDL_ToolkitThaiOverlayX11 *overlay;
overlay = overlay_cursor->entry;
#ifdef X_HAVE_UTF8_STRING
if (data->utf8) {
X11_Xutf8DrawString(data->display, data->drawable, data->font_set, data->ctx, x + element->rect.x + overlay->rect.x, y + overlay->rect.y, overlay->str, overlay->sz);
} else
#endif
{
X11_XDrawString(data->display, data->drawable, data->ctx, x + element->rect.x + overlay->rect.x, y + element->rect.y + overlay->rect.y, overlay->str, overlay->sz);
}
overlay_cursor = overlay_cursor->next;
}
#endif
}
} else {
#ifdef X_HAVE_UTF8_STRING
if (data->utf8) {
X11_Xutf8DrawString(data->display, data->drawable, data->font_set, data->ctx, x + element->rect.x, y + element->rect.y, element->str, element->sz);
} else
#endif
{
X11_XDrawString(data->display, data->drawable, data->ctx, x + element->rect.x, y + element->rect.y, element->str, element->sz);
}
}
cursor = cursor->next;
}
}
int X11Toolkit_GetTextElementsRect(SDL_ListNode *list, SDL_Rect *out)
{
SDL_ListNode *cursor;
int ret;
ret = 0;
out->x = out->y = 0;
out->w = out->h = 0;
cursor = list;
while (cursor) {
SDL_ToolkitTextElementX11 *element;
element = cursor->entry;
out->w += element->rect.w;
out->h = SDL_max(out->h, element->rect.h);
ret = SDL_max(ret, element->font_h);
cursor = cursor->next;
}
return ret;
}
void X11Toolkit_FreeTextElementsListContents(SDL_ListNode *list)
{
SDL_ListNode *cursor;
cursor = list;
while (cursor) {
SDL_ToolkitTextElementX11 *element;
#ifdef HAVE_LIBTHAI_H
SDL_ListNode *overlay_cursor;
#endif
element = cursor->entry;
if (element->str_free) {
element->str_free(element->str);
}
#ifdef HAVE_LIBTHAI_H
overlay_cursor = element->thai_overlays;
while (overlay_cursor) {
SDL_ToolkitThaiOverlayX11 *overlay;
overlay = overlay_cursor->entry;
SDL_free(overlay->str);
SDL_free(overlay);
overlay_cursor = overlay_cursor->next;
}
SDL_ListClear(&element->thai_overlays);
#endif
SDL_free(element);
cursor = cursor->next;
}
}
#define X11Toolkit_FreeTextElements(x) X11Toolkit_FreeTextElementsListContents(x); SDL_ListClear(&x)
static bool X11Toolkit_ShouldFlipUI(void)
{
SDL_Locale **current_locales;
@@ -744,6 +1158,10 @@ SDL_ToolkitWindowX11 *X11Toolkit_CreateWindowStruct(SDL_Window *parent, SDL_Tool
window->fribidi = SDL_FriBidi_Create();
#endif
#ifdef HAVE_LIBTHAI_H
window->th = SDL_LibThai_Create();
#endif
/* Interface direction */
window->flip_interface = X11Toolkit_ShouldFlipUI();
@@ -1466,7 +1884,7 @@ static void X11Toolkit_CalculateIconControl(SDL_ToolkitControlX11 *base_control)
int icon_wh;
control = (SDL_ToolkitIconControlX11 *)base_control;
X11Toolkit_GetTextWidthHeightForFont(control->icon_char_font, &control->icon_char, 1, &icon_char_w, &control->icon_char_h, &control->icon_char_a);
X11Toolkit_GetTextWidthHeightForFont(control->icon_char_font, &control->icon_char, 1, &icon_char_w, &control->icon_char_h, &control->icon_char_a, NULL);
base_control->rect.w = icon_char_w;
base_control->rect.h = control->icon_char_h;
icon_wh = SDL_max(icon_char_w, control->icon_char_h) + SDL_TOOLKIT_X11_ELEMENT_PADDING * 2 * base_control->window->iscale;
@@ -1632,31 +2050,23 @@ bool X11Toolkit_NotifyControlOfSizeChange(SDL_ToolkitControlX11 *control) {
static void X11Toolkit_CalculateButtonControl(SDL_ToolkitControlX11 *control) {
SDL_ToolkitButtonControlX11 *button_control;
int text_d;
button_control = (SDL_ToolkitButtonControlX11 *)control;
X11Toolkit_GetTextWidthHeight(control->window, button_control->data->text, button_control->str_sz, &button_control->text_rect.w, &button_control->text_rect.h, &button_control->text_a, &text_d, NULL);
X11Toolkit_GetTextElementsRect(button_control->text, &button_control->text_rect);
if (control->do_size) {
control->rect.w = SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * 2 * control->window->iscale + button_control->text_rect.w;
control->rect.h = SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * 2 * control->window->iscale + button_control->text_rect.h;
}
button_control->text_rect.x = (control->rect.w - button_control->text_rect.w)/2;
button_control->text_rect.y = button_control->text_a + (control->rect.h - button_control->text_rect.h)/2;
button_control->text_rect.y = (control->rect.h - button_control->text_rect.h)/2;
}
static void X11Toolkit_DrawButtonControl(SDL_ToolkitControlX11 *control) {
SDL_ToolkitButtonControlX11 *button_control;
char *text;
button_control = (SDL_ToolkitButtonControlX11 *)control;
#ifdef HAVE_FRIBIDI_H
text = button_control->text;
#else
text = (char *)button_control->data->text;
#endif
X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].pixel);
/* Draw bevel */
if (control->state == SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED || control->state == SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED_HELD) {
@@ -1738,20 +2148,8 @@ static void X11Toolkit_DrawButtonControl(SDL_ToolkitControlX11 *control) {
}
}
X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].pixel);
#ifdef X_HAVE_UTF8_STRING
if (control->window->utf8) {
X11_Xutf8DrawString(control->window->display, control->window->drawable, control->window->font_set, control->window->ctx,
control->rect.x + button_control->text_rect.x,
control->rect.y + button_control->text_rect.y,
text, button_control->str_sz);
} else
#endif
{
X11_XDrawString(control->window->display, control->window->drawable, control->window->ctx,
control->rect.x + button_control->text_rect.x, control->rect.y + button_control->text_rect.y,
text, button_control->str_sz);
}
X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].pixel);
X11Toolkit_DrawTextElements(control->window, button_control->text, control->rect.x + button_control->text_rect.x, control->rect.y + button_control->text_rect.y);
}
static void X11Toolkit_OnButtonControlStateChange(SDL_ToolkitControlX11 *control) {
@@ -1764,21 +2162,18 @@ static void X11Toolkit_OnButtonControlStateChange(SDL_ToolkitControlX11 *control
}
static void X11Toolkit_DestroyButtonControl(SDL_ToolkitControlX11 *control) {
#ifdef HAVE_FRIBIDI_H
SDL_ToolkitButtonControlX11 *button_control;
button_control = (SDL_ToolkitButtonControlX11 *)control;
if (button_control->free_text) {
SDL_free(button_control->text);
}
#endif
X11Toolkit_FreeTextElements(button_control->text);
SDL_free(control);
}
SDL_ToolkitControlX11 *X11Toolkit_CreateButtonControl(SDL_ToolkitWindowX11 *window, const SDL_MessageBoxButtonData *data) {
SDL_ToolkitButtonControlX11 *control;
SDL_ToolkitControlX11 *base_control;
int text_d;
control = (SDL_ToolkitButtonControlX11 *)SDL_malloc(sizeof(SDL_ToolkitButtonControlX11));
base_control = (SDL_ToolkitControlX11 *)control;
@@ -1805,30 +2200,19 @@ SDL_ToolkitControlX11 *X11Toolkit_CreateButtonControl(SDL_ToolkitWindowX11 *wind
base_control->is_default_enter = true;
base_control->selected = true;
}
base_control->do_size = false;
control->data = data;
control->str_sz = SDL_strlen(control->data->text);
#ifdef HAVE_FRIBIDI_H
if (base_control->window->fribidi) {
control->text = SDL_FriBidi_Process(base_control->window->fribidi, (char *)control->data->text, control->str_sz, base_control->window->do_shaping, NULL);
if (control->text) {
control->free_text = true;
control->str_sz = SDL_strlen(control->text);
} else {
control->text = (char *)control->data->text;
control->free_text = false;
}
} else {
control->text = (char *)control->data->text;
control->free_text = false;
}
#endif
control->cb = NULL;
X11Toolkit_GetTextWidthHeight(base_control->window, control->data->text, control->str_sz, &control->text_rect.w, &control->text_rect.h, &control->text_a, &text_d, NULL);
base_control->rect.w = SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * 2 * window->iscale + control->text_rect.w;
base_control->rect.h = SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * 2 * window->iscale + control->text_rect.h;
control->text_rect.x = control->text_rect.y = 0;
control->data = data;
#ifdef HAVE_FRIBIDI_H
control->text = X11Toolkit_MakeTextElements(base_control->window, (char *)control->data->text, SDL_strlen(control->data->text), NULL);
#else
control->text = X11Toolkit_MakeTextElements(base_control->window, (char *)control->data->text, SDL_strlen(control->data->text));
#endif
X11Toolkit_ShapeTextElements(base_control->window, control->text);
base_control->do_size = true;
X11Toolkit_CalculateButtonControl(base_control);
base_control->do_size = false;
X11Toolkit_AddControlToWindow(window, base_control);
return base_control;
}
@@ -1936,6 +2320,10 @@ void X11Toolkit_DestroyWindow(SDL_ToolkitWindowX11 *data) {
SDL_FriBidi_Destroy(data->fribidi);
#endif
#ifdef HAVE_LIBTHAI_H
SDL_LibThai_Destroy(data->th);
#endif
SDL_free(data);
}
@@ -1953,143 +2341,112 @@ static int X11Toolkit_CountLinesOfText(const char *text)
static void X11Toolkit_DrawLabelControl(SDL_ToolkitControlX11 *control) {
SDL_ToolkitLabelControlX11 *label_control;
int i;
int x;
label_control = (SDL_ToolkitLabelControlX11 *)control;
X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].pixel);
for (i = 0; i < label_control->sz; i++) {
x = control->rect.x;
#ifdef HAVE_FRIBIDI_H
if (control->window->fribidi) {
x += label_control->x[i];
}
#endif
#ifdef X_HAVE_UTF8_STRING
if (control->window->utf8) {
X11_Xutf8DrawString(control->window->display, control->window->drawable, control->window->font_set, control->window->ctx,
x, control->rect.y + label_control->y[i],
label_control->lines[i], label_control->szs[i]);
} else
#endif
{
X11_XDrawString(control->window->display, control->window->drawable, control->window->ctx,
x, control->rect.y + label_control->y[i],
label_control->lines[i], label_control->szs[i]);
}
X11Toolkit_DrawTextElements(control->window, label_control->lines[i].text, control->rect.x + label_control->lines[i].rect.x, control->rect.y + label_control->lines[i].rect.y);
}
}
static void X11Toolkit_DestroyLabelControl(SDL_ToolkitControlX11 *control) {
SDL_ToolkitLabelControlX11 *label_control;
int i;
label_control = (SDL_ToolkitLabelControlX11 *)control;
#ifdef HAVE_FRIBIDI_H
if (control->window->fribidi) {
int i;
for (i = 0; i < label_control->sz; i++) {
if (label_control->free_lines[i]) {
SDL_free(label_control->lines[i]);
}
}
SDL_free(label_control->x);
SDL_free(label_control->free_lines);
SDL_free(label_control->w);
SDL_free(label_control->par_types);
for (i = 0; i < label_control->sz; i++) {
X11Toolkit_FreeTextElements(label_control->lines[i].text);
}
#endif
SDL_free(label_control->lines);
SDL_free(label_control->szs);
SDL_free(label_control->y);
SDL_free(label_control);
}
static void X11Toolkit_CalculateLabelControl(SDL_ToolkitControlX11 *base_control) {
SDL_ToolkitLabelControlX11 *control;
int last_h;
int ascent;
int descent;
int font_h;
int w;
int h;
int i;
#ifdef HAVE_FRIBIDI_H
FriBidiParType first_ndn_dir;
int last_ndn;
#endif
last_h = 0;
control = (SDL_ToolkitLabelControlX11 *)base_control;
for (i = 0; i < control->sz; i++) {
X11Toolkit_GetTextWidthHeight(base_control->window, control->lines[i], control->szs[i], &w, &h, &ascent, &descent, &font_h);
base_control->rect.w = SDL_max(base_control->rect.w, w);
if (i > 0) {
control->y[i] = font_h + control->y[i-1];
} else {
control->y[i] = ascent;
}
last_h = h;
if (base_control->do_size) {
base_control->rect.w = 0;
base_control->rect.h = 0;
}
for (i = 0; i < control->sz; i++) {
int font_h;
font_h = X11Toolkit_GetTextElementsRect(control->lines[i].text, &control->lines[i].rect);
if (base_control->do_size) {
base_control->rect.w = SDL_max(base_control->rect.w, control->lines[i].rect.w);
}
if (i > 0) {
control->lines[i].rect.y = font_h + control->lines[i - 1].rect.y;
} else {
control->lines[i].rect.y = 0;
}
}
base_control->rect.h = control->y[control->sz -1] + last_h;
#ifdef HAVE_FRIBIDI_H
if (base_control->window->fribidi) {
FriBidiParType first_ndn_dir;
int last_ndn;
first_ndn_dir = FRIBIDI_PAR_LTR;
for (i = 0; i < control->sz; i++) {
if (control->par_types[i] != FRIBIDI_PAR_ON) {
first_ndn_dir = control->par_types[i];
if (control->lines[i].par != FRIBIDI_PAR_ON) {
first_ndn_dir = control->lines[i].par;
}
}
last_ndn = -1;
for (i = 0; i < control->sz; i++) {
switch (control->par_types[i]) {
switch (control->lines[i].par) {
case FRIBIDI_PAR_LTR:
control->x[i] = 0;
control->lines[i].rect.x = 0;
last_ndn = i;
break;
case FRIBIDI_PAR_RTL:
control->x[i] = base_control->rect.w - control->w[i];
control->lines[i].rect.x = base_control->rect.w - control->lines[i].rect.w;
last_ndn = i;
break;
default:
if (last_ndn != -1) {
if (control->par_types[last_ndn] == FRIBIDI_PAR_RTL) {
control->x[i] = base_control->rect.w - control->w[i];
if (control->lines[last_ndn].par == FRIBIDI_PAR_RTL) {
control->lines[i].rect.x = base_control->rect.w - control->lines[i].rect.w;
} else {
control->x[i] = 0;
control->lines[i].rect.x = 0;
}
} else {
if (first_ndn_dir == FRIBIDI_PAR_RTL) {
control->x[i] = base_control->rect.w - control->w[i];
control->lines[i].rect.x = base_control->rect.w - control->lines[i].rect.w;
} else {
control->x[i] = 0;
control->lines[i].rect.x = 0;
}
}
}
}
}
#endif
if (base_control->do_size && control->sz) {
base_control->rect.h = control->lines[control->sz - 1].rect.y + control->lines[control->sz - 1].rect.h;
}
}
SDL_ToolkitControlX11 *X11Toolkit_CreateLabelControl(SDL_ToolkitWindowX11 *window, char *utf8) {
SDL_ToolkitLabelControlX11 *control;
SDL_ToolkitControlX11 *base_control;
#ifdef HAVE_FRIBIDI_H
FriBidiParType first_ndn_dir;
int last_ndn;
#endif
int font_h;
int last_h;
int ascent;
int descent;
int i;
if (!utf8) {
return NULL;
}
if (!SDL_strcmp(utf8, "")) {
return NULL;
}
control = (SDL_ToolkitLabelControlX11 *)SDL_malloc(sizeof(SDL_ToolkitLabelControlX11));
base_control = (SDL_ToolkitControlX11 *)control;
if (!control) {
@@ -2109,113 +2466,46 @@ SDL_ToolkitControlX11 *X11Toolkit_CreateLabelControl(SDL_ToolkitWindowX11 *windo
base_control->rect.h = 0;
base_control->is_default_enter = false;
base_control->is_default_esc = false;
control->sz = X11Toolkit_CountLinesOfText(utf8);
control->lines = (char **)SDL_malloc(sizeof(char *) * control->sz);
control->y = (int *)SDL_calloc(control->sz, sizeof(int));
control->szs = (size_t *)SDL_calloc(control->sz, sizeof(size_t));
#ifdef HAVE_FRIBIDI_H
if (base_control->window->fribidi) {
control->x = (int *)SDL_calloc(control->sz, sizeof(int));
control->free_lines = (bool *)SDL_calloc(control->sz, sizeof(bool));
control->par_types = (FriBidiParType *)SDL_calloc(control->sz, sizeof(FriBidiParType));
control->w = (int *)SDL_calloc(control->sz, sizeof(int));
}
#endif
last_h = 0;
control->lines = SDL_calloc(control->sz, sizeof(SDL_ToolkitLabelControlLineX11));
for (i = 0; i < control->sz; i++) {
const char *lf = SDL_strchr(utf8, '\n');
const int length = lf ? (lf - utf8) : SDL_strlen(utf8);
int w;
int h;
#ifdef HAVE_FRIBIDI_H
if (base_control->window->fribidi) {
control->lines[i] = SDL_FriBidi_Process(base_control->window->fribidi, utf8, length, base_control->window->do_shaping, &control->par_types[i]);
control->szs[i] = SDL_strlen(control->lines[i]);
control->free_lines[i] = true;
} else
#endif
{
control->lines[i] = utf8;
control->szs[i] = length;
#ifdef HAVE_FRIBIDI_H
control->free_lines[i] = false;
#endif
}
X11Toolkit_GetTextWidthHeight(window, control->lines[i], control->szs[i], &w, &h, &ascent, &descent, &font_h);
#ifdef HAVE_FRIBIDI_H
if (base_control->window->fribidi) {
control->w[i] = w;
}
#endif
base_control->rect.w = SDL_max(base_control->rect.w, w);
if (lf && (lf > control->lines[i]) && (lf[-1] == '\r')) {
control->szs[i]--;
int sz;
sz = length;
if (lf && (lf > utf8) && (lf[-1] == '\r')) {
sz--;
}
if (i > 0) {
control->y[i] = font_h + control->y[i-1];
} else {
control->y[i] = ascent;
}
last_h = h;
#ifdef HAVE_FRIBIDI_H
control->lines[i].text = X11Toolkit_MakeTextElements(base_control->window, (char *)utf8, sz, &control->lines[i].par);
#else
control->lines[i].text = X11Toolkit_MakeTextElements(base_control->window, (char *)utf8, sz);
#endif
X11Toolkit_ShapeTextElements(base_control->window, control->lines[i].text);
utf8 += length + 1;
if (!lf) {
break;
}
}
base_control->rect.h = control->y[control->sz -1] + last_h;
#ifdef HAVE_FRIBIDI_H
if (base_control->window->fribidi) {
first_ndn_dir = FRIBIDI_PAR_LTR;
for (i = 0; i < control->sz; i++) {
if (control->par_types[i] != FRIBIDI_PAR_ON) {
first_ndn_dir = control->par_types[i];
}
}
last_ndn = -1;
for (i = 0; i < control->sz; i++) {
switch (control->par_types[i]) {
case FRIBIDI_PAR_LTR:
control->x[i] = 0;
last_ndn = i;
break;
case FRIBIDI_PAR_RTL:
control->x[i] = base_control->rect.w - control->w[i];
last_ndn = i;
break;
default:
if (last_ndn != -1) {
if (control->par_types[last_ndn] == FRIBIDI_PAR_RTL) {
control->x[i] = base_control->rect.w - control->w[i];
} else {
control->x[i] = 0;
}
} else {
if (first_ndn_dir == FRIBIDI_PAR_RTL) {
control->x[i] = base_control->rect.w - control->w[i];
} else {
control->x[i] = 0;
}
}
}
}
}
#endif
base_control->do_size = true;
X11Toolkit_CalculateLabelControl(base_control);
base_control->do_size = false;
X11Toolkit_AddControlToWindow(window, base_control);
return base_control;
}
int X11Toolkit_GetIconControlCharY(SDL_ToolkitControlX11 *control) {
SDL_ToolkitIconControlX11 *icon_control;
int X11Toolkit_GetLabelControlFirstLineHeight(SDL_ToolkitControlX11 *control) {
SDL_ToolkitLabelControlX11 *label_control;
icon_control = (SDL_ToolkitIconControlX11 *)control;
return icon_control->icon_char_y - icon_control->icon_char_a + icon_control->icon_char_h/4;
label_control = (SDL_ToolkitLabelControlX11 *)control;
return label_control->lines[0].rect.h;
}
void X11Toolkit_SignalWindowClose(SDL_ToolkitWindowX11 *data) {

View File

@@ -32,6 +32,9 @@
#ifdef HAVE_FRIBIDI_H
#include "../../core/unix/SDL_fribidi.h"
#endif
#ifdef HAVE_LIBTHAI_H
#include "../../core/unix/SDL_libthai.h"
#endif
#ifdef SDL_VIDEO_DRIVER_X11
@@ -50,6 +53,22 @@ typedef enum SDL_ToolkitChildModeX11
SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP
} SDL_ToolkitWindowModeX11;
typedef enum SDL_ToolkitThaiEncodingX11
{
SDL_TOOLKIT_THAI_ENCODING_X11_NONE,
SDL_TOOLKIT_THAI_ENCODING_X11_TIS, /* -0 */
SDL_TOOLKIT_THAI_ENCODING_X11_TIS_WIN, /* -2 */
SDL_TOOLKIT_THAI_ENCODING_X11_TIS_MAC, /* -1 */
SDL_TOOLKIT_THAI_ENCODING_X11_8859,
SDL_TOOLKIT_THAI_ENCODING_X11_UNICODE
} SDL_ToolkitThaiEncodingX11;
typedef enum SDL_ToolkitThaiFontX11
{
SDL_TOOLKIT_THAI_FONT_X11_OFFSET,
SDL_TOOLKIT_THAI_FONT_X11_CELL
} SDL_ToolkitThaiFontX11;
typedef struct SDL_ToolkitWindowX11
{
/* Locale */
@@ -119,7 +138,9 @@ typedef struct SDL_ToolkitWindowX11
/* Font */
XFontSet font_set; // for UTF-8 systems
XFontStruct *font_struct; // Latin1 (ASCII) fallback.
SDL_ToolkitThaiEncodingX11 thai_encoding;
SDL_ToolkitThaiFontX11 thai_font;
/* Control colors */
const SDL_MessageBoxColor *color_hints;
XColor xcolor[SDL_MESSAGEBOX_COLOR_COUNT];
@@ -164,6 +185,10 @@ typedef struct SDL_ToolkitWindowX11
bool do_shaping;
#endif
#ifdef HAVE_LIBTHAI_H
SDL_LibThai *th;
#endif
bool flip_interface;
} SDL_ToolkitWindowX11;
@@ -231,10 +256,10 @@ extern bool X11Toolkit_NotifyControlOfSizeChange(SDL_ToolkitControlX11 *control)
/* ICON CONTROL FUNCTIONS */
extern SDL_ToolkitControlX11 *X11Toolkit_CreateIconControl(SDL_ToolkitWindowX11 *window, SDL_MessageBoxFlags flags);
extern int X11Toolkit_GetIconControlCharY(SDL_ToolkitControlX11 *control);
/* LABEL CONTROL FUNCTIONS */
extern SDL_ToolkitControlX11 *X11Toolkit_CreateLabelControl(SDL_ToolkitWindowX11 *window, char *utf8);
extern int X11Toolkit_GetLabelControlFirstLineHeight(SDL_ToolkitControlX11 *control);
/* BUTTON CONTROL FUNCTIONS */
extern SDL_ToolkitControlX11 *X11Toolkit_CreateButtonControl(SDL_ToolkitWindowX11 *window, const SDL_MessageBoxButtonData *data);

View File

@@ -164,6 +164,11 @@ int main(int argc, char *argv[])
quit(1);
}
success = SDL_ShowSimpleMessageBox(0,
"No icon",
"This is a MessageBox with no icon!",
NULL);
/* Google says this is Traditional Chinese for "beef with broccoli" */
success = SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
"UTF-8 Simple MessageBox",