mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-10-05 09:26:25 +00:00
X11TK: Add Arabic/Hebrew/Farsi support by increasing font size slightly and using FriBidi. (#14134)
This commit is contained in:
@@ -347,6 +347,8 @@ dep_option(SDL_X11_XSCRNSAVER "Enable Xscrnsaver support" ON SDL_X11 OFF)
|
||||
dep_option(SDL_X11_XSHAPE "Enable XShape support" ON SDL_X11 OFF)
|
||||
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_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)
|
||||
@@ -1776,6 +1778,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
|
||||
# Need to check for ROCKCHIP platform and get rid of "Can't window GBM/EGL surfaces on window creation."
|
||||
CheckROCKCHIP()
|
||||
CheckX11()
|
||||
CheckFribidi()
|
||||
# Need to check for EGL first because KMSDRM and Wayland depend on it.
|
||||
CheckEGL()
|
||||
CheckKMSDRM()
|
||||
@@ -1925,7 +1928,6 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
|
||||
set(HAVE_LIBURING TRUE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if((FREEBSD OR NETBSD) AND NOT HAVE_INOTIFY)
|
||||
set(LibInotify_PKG_CONFIG_SPEC libinotify)
|
||||
pkg_check_modules(PC_LIBINOTIFY IMPORTED_TARGET ${LibInotify_PKG_CONFIG_SPEC})
|
||||
|
@@ -511,6 +511,35 @@ macro(CheckX11)
|
||||
cmake_pop_check_state()
|
||||
endmacro()
|
||||
|
||||
macro(CheckFribidi)
|
||||
if(SDL_FRIBIDI)
|
||||
set(FRIBIDI_PKG_CONFIG_SPEC fribidi)
|
||||
set(PC_FRIBIDI_FOUND FALSE)
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_FRIBIDI IMPORTED_TARGET ${FRIBIDI_PKG_CONFIG_SPEC})
|
||||
endif()
|
||||
if(PC_FRIBIDI_FOUND)
|
||||
set(HAVE_FRIBIDI TRUE)
|
||||
set(HAVE_FRIBIDI_H 1)
|
||||
sdl_sources(
|
||||
"${SDL3_SOURCE_DIR}/src/core/unix/SDL_fribidi.c"
|
||||
"${SDL3_SOURCE_DIR}/src/core/unix/SDL_fribidi.h"
|
||||
)
|
||||
if(SDL_FRIBIDI_SHARED AND NOT HAVE_SDL_LOADSO)
|
||||
message(WARNING "You must have SDL_LoadObject() support for dynamic fribidi loading")
|
||||
endif()
|
||||
FindLibraryAndSONAME("fribidi" LIBDIRS ${PC_FRIBIDI_LIBRARY_DIRS})
|
||||
if(SDL_FRIBIDI_SHARED AND FRIBIDI_LIB AND HAVE_SDL_LOADSO)
|
||||
set(SDL_FRIBIDI_DYNAMIC "\"${FRIBIDI_LIB_SONAME}\"")
|
||||
set(HAVE_FRIBIDI_SHARED TRUE)
|
||||
sdl_include_directories(PRIVATE SYSTEM $<TARGET_PROPERTY:PkgConfig::PC_FRIBIDI,INTERFACE_INCLUDE_DIRECTORIES>)
|
||||
else()
|
||||
sdl_link_dependency(fribidi LIBS PkgConfig::PC_FRIBIDI PKG_CONFIG_PREFIX PC_FRIBIDI PKG_CONFIG_SPECS ${FRIBIDI_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")
|
||||
|
@@ -216,6 +216,8 @@
|
||||
#cmakedefine HAVE_LIBUDEV_H 1
|
||||
#cmakedefine HAVE_LIBDECOR_H 1
|
||||
#cmakedefine HAVE_LIBURING_H 1
|
||||
#cmakedefine HAVE_FRIBIDI_H 1
|
||||
#cmakedefine SDL_FRIBIDI_DYNAMIC @SDL_FRIBIDI_DYNAMIC@
|
||||
|
||||
#cmakedefine HAVE_DDRAW_H 1
|
||||
#cmakedefine HAVE_DSOUND_H 1
|
||||
|
160
src/core/unix/SDL_fribidi.c
Normal file
160
src/core/unix/SDL_fribidi.c
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_FRIBIDI_H
|
||||
|
||||
#include "SDL_internal.h"
|
||||
#include "SDL_fribidi.h"
|
||||
#include <fribidi.h>
|
||||
|
||||
SDL_FriBidi *SDL_FriBidi_Create(void) {
|
||||
SDL_FriBidi *fribidi;
|
||||
|
||||
fribidi = (SDL_FriBidi *)SDL_malloc(sizeof(SDL_FriBidi));
|
||||
if (!fribidi) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef SDL_FRIBIDI_DYNAMIC
|
||||
#define SDL_FRIBIDI_LOAD_SYM(x, n, t) x = ((t)SDL_LoadFunction(fribidi->lib, n)); if (!x) { SDL_UnloadObject(fribidi->lib); SDL_free(fribidi); return NULL; }
|
||||
|
||||
fribidi->lib = SDL_LoadObject(SDL_FRIBIDI_DYNAMIC);
|
||||
if (!fribidi->lib) {
|
||||
SDL_free(fribidi);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SDL_FRIBIDI_LOAD_SYM(fribidi->unicode_to_charset, "fribidi_unicode_to_charset", SDL_FriBidiUnicodeToCharset);
|
||||
SDL_FRIBIDI_LOAD_SYM(fribidi->charset_to_unicode, "fribidi_charset_to_unicode", SDL_FriBidiCharsetToUnicode);
|
||||
SDL_FRIBIDI_LOAD_SYM(fribidi->get_bidi_types, "fribidi_get_bidi_types", SDL_FriBidiGetBidiTypes);
|
||||
SDL_FRIBIDI_LOAD_SYM(fribidi->get_par_direction, "fribidi_get_par_direction", SDL_FriBidiGetParDirection);
|
||||
SDL_FRIBIDI_LOAD_SYM(fribidi->get_par_embedding_levels, "fribidi_get_par_embedding_levels", SDL_FriBidiGetParEmbeddingLevels);
|
||||
SDL_FRIBIDI_LOAD_SYM(fribidi->get_joining_types, "fribidi_get_joining_types", SDL_FriBidiGetJoiningTypes);
|
||||
SDL_FRIBIDI_LOAD_SYM(fribidi->join_arabic, "fribidi_join_arabic", SDL_FriBidiJoinArabic);
|
||||
SDL_FRIBIDI_LOAD_SYM(fribidi->shape, "fribidi_shape", SDL_FriBidiShape);
|
||||
SDL_FRIBIDI_LOAD_SYM(fribidi->reorder_line, "fribidi_reorder_line", SDL_FriBidiReorderLine);
|
||||
#else
|
||||
fribidi->unicode_to_charset = fribidi_unicode_to_charset;
|
||||
fribidi->charset_to_unicode = fribidi_charset_to_unicode;
|
||||
fribidi->get_bidi_types = fribidi_get_bidi_types;
|
||||
fribidi->get_par_direction = fribidi_get_par_direction;
|
||||
fribidi->get_par_embedding_levels = fribidi_get_par_embedding_levels;
|
||||
fribidi->get_joining_types = fribidi_get_joining_types;
|
||||
fribidi->join_arabic = fribidi_join_arabic;
|
||||
fribidi->shape = fribidi_shape;
|
||||
fribidi->reorder_line = fribidi_reorder_line;
|
||||
#endif
|
||||
|
||||
return fribidi;
|
||||
}
|
||||
|
||||
char *SDL_FriBidi_Process(SDL_FriBidi *fribidi, char *utf8, ssize_t utf8_len, bool shaping, FriBidiParType *out_par_type) {
|
||||
FriBidiCharType *types;
|
||||
FriBidiLevel *levels;
|
||||
FriBidiArabicProp *props;
|
||||
FriBidiChar *str;
|
||||
char *result;
|
||||
FriBidiStrIndex len;
|
||||
FriBidiLevel max_level;
|
||||
FriBidiLevel start;
|
||||
FriBidiLevel end;
|
||||
FriBidiParType direction;
|
||||
FriBidiParType str_direction;
|
||||
unsigned int i;
|
||||
unsigned int c;
|
||||
|
||||
if (!fribidi || !utf8) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Convert to UTF32 */
|
||||
if (utf8_len < 0) {
|
||||
utf8_len = SDL_strlen(utf8);
|
||||
}
|
||||
str = SDL_calloc(SDL_utf8strnlen(utf8, utf8_len), sizeof(FriBidiChar));
|
||||
len = fribidi->charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, utf8, utf8_len, str);
|
||||
|
||||
/* Setup various BIDI structures */
|
||||
direction = FRIBIDI_PAR_LTR;
|
||||
types = NULL;
|
||||
levels = NULL;
|
||||
props = SDL_calloc(len + 1, sizeof(FriBidiArabicProp));
|
||||
levels = SDL_calloc(len + 1, sizeof(FriBidiLevel));
|
||||
types = SDL_calloc(len + 1, sizeof(FriBidiCharType));
|
||||
|
||||
/* Shape */
|
||||
fribidi->get_bidi_types(str, len, types);
|
||||
str_direction = fribidi->get_par_direction(types, len);
|
||||
max_level = fribidi->get_par_embedding_levels(types, len, &direction, levels);
|
||||
if (shaping) {
|
||||
fribidi->get_joining_types(str, len, props);
|
||||
fribidi->join_arabic(types, len, levels, props);
|
||||
fribidi->shape(FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC, levels, len, props, str);
|
||||
}
|
||||
|
||||
/* BIDI */
|
||||
for (end = 0, start = 0; end < len; end++) {
|
||||
if (str[end] == '\n' || str[end] == '\r' || str[end] == '\f' || str[end] == '\v' || end == len - 1) {
|
||||
max_level = fribidi->reorder_line(FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC, types, end - start + 1, start, direction, levels, str, NULL);
|
||||
start = end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Silence warning */
|
||||
(void)max_level;
|
||||
|
||||
/* Remove fillers */
|
||||
for (i = 0, c = 0; i < len; i++) {
|
||||
if (str[i] != FRIBIDI_CHAR_FILL) {
|
||||
str[c++] = str[i];
|
||||
}
|
||||
}
|
||||
len = c;
|
||||
|
||||
/* Convert back to UTF8 */
|
||||
result = SDL_malloc(len * 4 + 1);
|
||||
fribidi->unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, str, len, result);
|
||||
|
||||
/* Cleanup */
|
||||
SDL_free(levels);
|
||||
SDL_free(props);
|
||||
SDL_free(types);
|
||||
|
||||
/* Return */
|
||||
if (out_par_type) {
|
||||
*out_par_type = str_direction;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void SDL_FriBidi_Destroy(SDL_FriBidi *fribidi) {
|
||||
if (!fribidi) {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef SDL_FRIBIDI_DYNAMIC
|
||||
SDL_UnloadObject(fribidi->lib);
|
||||
#endif
|
||||
|
||||
SDL_free(fribidi);
|
||||
}
|
||||
|
||||
#endif
|
58
src/core/unix/SDL_fribidi.h
Normal file
58
src/core/unix/SDL_fribidi.h
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
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_FRIBIDI_H
|
||||
#include <fribidi.h>
|
||||
|
||||
#ifndef SDL_fribidi_h_
|
||||
#define SDL_fribidi_h_
|
||||
|
||||
typedef FriBidiStrIndex (*SDL_FriBidiUnicodeToCharset)(FriBidiCharSet, const FriBidiChar *, FriBidiStrIndex, char *);
|
||||
typedef FriBidiStrIndex (*SDL_FriBidiCharsetToUnicode)(FriBidiCharSet, const char *, FriBidiStrIndex, FriBidiChar *);
|
||||
typedef void (*SDL_FriBidiGetBidiTypes)(const FriBidiChar *, const FriBidiStrIndex, FriBidiCharType *);
|
||||
typedef FriBidiParType (*SDL_FriBidiGetParDirection)(const FriBidiCharType *, const FriBidiStrIndex);
|
||||
typedef FriBidiLevel (*SDL_FriBidiGetParEmbeddingLevels)(const FriBidiCharType *, const FriBidiStrIndex, FriBidiParType *, FriBidiLevel *);
|
||||
typedef void (*SDL_FriBidiGetJoiningTypes)(const FriBidiChar *, const FriBidiStrIndex, FriBidiJoiningType *);
|
||||
typedef void (*SDL_FriBidiJoinArabic)(const FriBidiCharType *, const FriBidiStrIndex, const FriBidiLevel *, FriBidiArabicProp *);
|
||||
typedef void (*SDL_FriBidiShape)(FriBidiFlags flags, const FriBidiLevel *, const FriBidiStrIndex, FriBidiArabicProp *, FriBidiChar *str);
|
||||
typedef FriBidiLevel (*SDL_FriBidiReorderLine)(FriBidiFlags flags, const FriBidiCharType *, const FriBidiStrIndex, const FriBidiStrIndex, const FriBidiParType, FriBidiLevel *, FriBidiChar *, FriBidiStrIndex *);
|
||||
|
||||
typedef struct SDL_FriBidi {
|
||||
SDL_SharedObject *lib;
|
||||
SDL_FriBidiUnicodeToCharset unicode_to_charset;
|
||||
SDL_FriBidiCharsetToUnicode charset_to_unicode;
|
||||
SDL_FriBidiGetBidiTypes get_bidi_types;
|
||||
SDL_FriBidiGetParDirection get_par_direction;
|
||||
SDL_FriBidiGetParEmbeddingLevels get_par_embedding_levels;
|
||||
SDL_FriBidiGetJoiningTypes get_joining_types;
|
||||
SDL_FriBidiJoinArabic join_arabic;
|
||||
SDL_FriBidiShape shape;
|
||||
SDL_FriBidiReorderLine reorder_line;
|
||||
} SDL_FriBidi;
|
||||
|
||||
extern SDL_FriBidi *SDL_FriBidi_Create(void);
|
||||
extern char *SDL_FriBidi_Process(SDL_FriBidi *fribidi, char *utf8, ssize_t utf8_len, bool shaping, FriBidiParType *out_par_type);
|
||||
extern void SDL_FriBidi_Destroy(SDL_FriBidi *fribidi);
|
||||
#endif
|
||||
|
||||
#endif // SDL_fribidi_h_
|
@@ -235,8 +235,10 @@ SDL_X11_SYM(int,Xutf8TextExtents,(XFontSet a, _Xconst char* b, int c, XRectangle
|
||||
SDL_X11_SYM(char*,XSetLocaleModifiers,(const char *a))
|
||||
SDL_X11_SYM(char*,Xutf8ResetIC,(XIC a))
|
||||
SDL_X11_SYM(XFontSetExtents*,XExtentsOfFontSet,(XFontSet a))
|
||||
SDL_X11_SYM(Bool,XContextDependentDrawing,(XFontSet a))
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef NO_SHARED_MEMORY
|
||||
SDL_X11_MODULE(SHM)
|
||||
SDL_X11_SYM(Status,XShmAttach,(Display* a,XShmSegmentInfo* b))
|
||||
|
@@ -28,6 +28,9 @@
|
||||
#ifdef SDL_USE_LIBDBUS
|
||||
#include "../../core/linux/SDL_system_theme.h"
|
||||
#endif
|
||||
#ifdef HAVE_FRIBIDI_H
|
||||
#include "../../core/unix/SDL_fribidi.h"
|
||||
#endif
|
||||
#include "SDL_x11dyn.h"
|
||||
#include "SDL_x11toolkit.h"
|
||||
#include "SDL_x11settings.h"
|
||||
@@ -76,6 +79,10 @@ typedef struct SDL_ToolkitButtonControlX11
|
||||
int text_a;
|
||||
int text_d;
|
||||
int str_sz;
|
||||
#ifdef HAVE_FRIBIDI_H
|
||||
char *text;
|
||||
bool free_text;
|
||||
#endif
|
||||
|
||||
/* Callback */
|
||||
void *cb_data;
|
||||
@@ -90,6 +97,12 @@ typedef struct SDL_ToolkitLabelControlX11
|
||||
int *y;
|
||||
size_t *szs;
|
||||
size_t sz;
|
||||
#ifdef HAVE_FRIBIDI_H
|
||||
int *x;
|
||||
int *w;
|
||||
bool *free_lines;
|
||||
FriBidiParType *par_types;
|
||||
#endif
|
||||
} SDL_ToolkitLabelControlX11;
|
||||
|
||||
typedef struct SDL_ToolkitMenuBarControlX11
|
||||
@@ -109,7 +122,7 @@ typedef struct SDL_ToolkitMenuControlX11
|
||||
|
||||
/* Font for icon control */
|
||||
static const char *g_IconFont = "-*-*-bold-r-normal-*-%d-*-*-*-*-*-iso8859-1[33 88 105]";
|
||||
#define G_ICONFONT_SIZE 18
|
||||
#define G_ICONFONT_SIZE 22
|
||||
|
||||
/* General UI font */
|
||||
static const char g_ToolkitFontLatin1[] =
|
||||
@@ -128,7 +141,7 @@ static const char *g_ToolkitFont[] = {
|
||||
"-*-*-*-*-*--*-*-*-*-*-*-iso8859-1,*", // just give me anything latin1.
|
||||
NULL
|
||||
};
|
||||
#define G_TOOLKITFONT_SIZE 120
|
||||
#define G_TOOLKITFONT_SIZE 140
|
||||
|
||||
static const SDL_MessageBoxColor g_default_colors[SDL_MESSAGEBOX_COLOR_COUNT] = {
|
||||
{ 191, 184, 191 }, // SDL_MESSAGEBOX_COLOR_BACKGROUND,
|
||||
@@ -399,6 +412,10 @@ static void X11Toolkit_InitWindowFonts(SDL_ToolkitWindowX11 *window)
|
||||
|
||||
if (!window->font_set) {
|
||||
goto load_font_traditional;
|
||||
} else {
|
||||
#ifdef HAVE_FRIBIDI_H
|
||||
window->do_shaping = !X11_XContextDependentDrawing(window->font_set);
|
||||
#endif
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
@@ -549,27 +566,40 @@ static void X11Toolkit_GetTextWidthHeightForFont(XFontStruct *font, const char *
|
||||
*ascent = text_structure.ascent;
|
||||
}
|
||||
|
||||
static void X11Toolkit_GetTextWidthHeight(SDL_ToolkitWindowX11 *data, const char *str, int nbytes, int *pwidth, int *pheight, int *ascent, int *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)
|
||||
{
|
||||
#ifdef X_HAVE_UTF8_STRING
|
||||
if (data->utf8) {
|
||||
XRectangle overall_ink, overall_logical;
|
||||
|
||||
X11_Xutf8TextExtents(data->font_set, str, nbytes, &overall_ink, &overall_logical);
|
||||
*pwidth = overall_logical.width;
|
||||
*pheight = overall_logical.height;
|
||||
*ascent = -overall_logical.y;
|
||||
*font_descent = overall_logical.height - *ascent;
|
||||
*descent = overall_logical.height - *ascent;
|
||||
|
||||
if (font_height) {
|
||||
XFontSetExtents *extents;
|
||||
|
||||
extents = X11_XExtentsOfFontSet(data->font_set);
|
||||
*font_height = extents->max_logical_extent.height;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
XCharStruct text_structure;
|
||||
int font_direction, font_ascent;
|
||||
int font_direction, font_ascent, font_descent;
|
||||
X11_XTextExtents(data->font_struct, str, nbytes,
|
||||
&font_direction, &font_ascent, font_descent,
|
||||
&font_direction, &font_ascent, &font_descent,
|
||||
&text_structure);
|
||||
*pwidth = text_structure.width;
|
||||
*pheight = text_structure.ascent + text_structure.descent;
|
||||
*ascent = text_structure.ascent;
|
||||
*descent = text_structure.descent;
|
||||
|
||||
if (font_height) {
|
||||
*font_height = font_ascent + font_descent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -779,6 +809,9 @@ SDL_ToolkitWindowX11 *X11Toolkit_CreateWindowStruct(SDL_Window *parent, SDL_Tool
|
||||
/* Menu windows */
|
||||
window->popup_windows = NULL;
|
||||
|
||||
#ifdef HAVE_FRIBIDI_H
|
||||
window->fribidi = SDL_FriBidi_Create();
|
||||
#endif
|
||||
return window;
|
||||
}
|
||||
|
||||
@@ -1653,7 +1686,7 @@ static void X11Toolkit_CalculateButtonControl(SDL_ToolkitControlX11 *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);
|
||||
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);
|
||||
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;
|
||||
@@ -1665,8 +1698,16 @@ static void X11Toolkit_CalculateButtonControl(SDL_ToolkitControlX11 *control) {
|
||||
|
||||
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) {
|
||||
@@ -1754,13 +1795,13 @@ static void X11Toolkit_DrawButtonControl(SDL_ToolkitControlX11 *control) {
|
||||
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,
|
||||
button_control->data->text, button_control->str_sz);
|
||||
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,
|
||||
button_control->data->text, button_control->str_sz);
|
||||
text, button_control->str_sz);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1773,7 +1814,15 @@ static void X11Toolkit_OnButtonControlStateChange(SDL_ToolkitControlX11 *control
|
||||
}
|
||||
}
|
||||
|
||||
static void X11Toolkit_DestroyGenericControl(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
|
||||
SDL_free(control);
|
||||
}
|
||||
|
||||
@@ -1793,7 +1842,7 @@ SDL_ToolkitControlX11 *X11Toolkit_CreateButtonControl(SDL_ToolkitWindowX11 *wind
|
||||
base_control->func_calc_size = X11Toolkit_CalculateButtonControl;
|
||||
base_control->func_draw = X11Toolkit_DrawButtonControl;
|
||||
base_control->func_on_state_change = X11Toolkit_OnButtonControlStateChange;
|
||||
base_control->func_free = X11Toolkit_DestroyGenericControl;
|
||||
base_control->func_free = X11Toolkit_DestroyButtonControl;
|
||||
base_control->func_on_scale_change = NULL;
|
||||
base_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL;
|
||||
base_control->selected = false;
|
||||
@@ -1810,8 +1859,23 @@ SDL_ToolkitControlX11 *X11Toolkit_CreateButtonControl(SDL_ToolkitWindowX11 *wind
|
||||
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);
|
||||
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;
|
||||
@@ -1923,6 +1987,10 @@ void X11Toolkit_DestroyWindow(SDL_ToolkitWindowX11 *data) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FRIBIDI_H
|
||||
SDL_FriBidi_Destroy(data->fribidi);
|
||||
#endif
|
||||
|
||||
SDL_free(data);
|
||||
}
|
||||
|
||||
@@ -1940,20 +2008,27 @@ 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,
|
||||
control->rect.x, control->rect.y + label_control->y[i],
|
||||
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,
|
||||
control->rect.x, control->rect.y + label_control->y[i],
|
||||
x, control->rect.y + label_control->y[i],
|
||||
label_control->lines[i], label_control->szs[i]);
|
||||
}
|
||||
}
|
||||
@@ -1963,6 +2038,21 @@ static void X11Toolkit_DestroyLabelControl(SDL_ToolkitControlX11 *control) {
|
||||
SDL_ToolkitLabelControlX11 *label_control;
|
||||
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
SDL_free(label_control->lines);
|
||||
SDL_free(label_control->szs);
|
||||
SDL_free(label_control->y);
|
||||
@@ -1974,17 +2064,23 @@ static void X11Toolkit_CalculateLabelControl(SDL_ToolkitControlX11 *base_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);
|
||||
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] = ascent + descent + control->y[i-1];
|
||||
control->y[i] = font_h + control->y[i-1];
|
||||
} else {
|
||||
control->y[i] = ascent;
|
||||
}
|
||||
@@ -1992,11 +2088,55 @@ static void X11Toolkit_CalculateLabelControl(SDL_ToolkitControlX11 *base_control
|
||||
last_h = h;
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -2028,6 +2168,14 @@ SDL_ToolkitControlX11 *X11Toolkit_CreateLabelControl(SDL_ToolkitWindowX11 *windo
|
||||
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;
|
||||
for (i = 0; i < control->sz; i++) {
|
||||
const char *lf = SDL_strchr(utf8, '\n');
|
||||
@@ -2035,17 +2183,34 @@ SDL_ToolkitControlX11 *X11Toolkit_CreateLabelControl(SDL_ToolkitWindowX11 *windo
|
||||
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;
|
||||
X11Toolkit_GetTextWidthHeight(window, utf8, length, &w, &h, &ascent, &descent);
|
||||
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);
|
||||
|
||||
control->szs[i] = length;
|
||||
if (lf && (lf > utf8) && (lf[-1] == '\r')) {
|
||||
if (lf && (lf > control->lines[i]) && (lf[-1] == '\r')) {
|
||||
control->szs[i]--;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
control->y[i] = ascent + descent + control->y[i-1];
|
||||
control->y[i] = font_h + control->y[i-1];
|
||||
} else {
|
||||
control->y[i] = ascent;
|
||||
}
|
||||
@@ -2057,6 +2222,44 @@ SDL_ToolkitControlX11 *X11Toolkit_CreateLabelControl(SDL_ToolkitWindowX11 *windo
|
||||
}
|
||||
}
|
||||
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
|
||||
|
||||
X11Toolkit_AddControlToWindow(window, base_control);
|
||||
|
||||
|
@@ -29,6 +29,9 @@
|
||||
#include "SDL_x11settings.h"
|
||||
#include "SDL_x11toolkit.h"
|
||||
#include "xsettings-client.h"
|
||||
#ifdef HAVE_FRIBIDI_H
|
||||
#include "../../core/unix/SDL_fribidi.h"
|
||||
#endif
|
||||
|
||||
#ifdef SDL_VIDEO_DRIVER_X11
|
||||
|
||||
@@ -95,7 +98,6 @@ typedef struct SDL_ToolkitWindowX11
|
||||
Bool shm_pixmap;
|
||||
#endif
|
||||
bool utf8;
|
||||
|
||||
/* Atoms */
|
||||
Atom wm_protocols;
|
||||
Atom wm_delete_message;
|
||||
@@ -155,6 +157,12 @@ typedef struct SDL_ToolkitWindowX11
|
||||
bool draw;
|
||||
bool close;
|
||||
long event_mask;
|
||||
|
||||
#ifdef HAVE_FRIBIDI_H
|
||||
/* BIDI engine */
|
||||
SDL_FriBidi *fribidi;
|
||||
bool do_shaping;
|
||||
#endif
|
||||
} SDL_ToolkitWindowX11;
|
||||
|
||||
typedef enum SDL_ToolkitControlStateX11
|
||||
|
@@ -213,6 +213,15 @@ int main(int argc, char *argv[])
|
||||
quit(1);
|
||||
}
|
||||
|
||||
success = SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
|
||||
"Arabic (multi line)",
|
||||
"سطر طويل جدًا من النص\nخط قصير\nسطر طويل للغاية من النص مذهل بشكل لا يصدق في اللغة العربية التي يتم التحدث بها في منطقة الشرق الأوسط وشمال أفريقيا",
|
||||
NULL);
|
||||
if (!success) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Error Presenting MessageBox: %s", SDL_GetError());
|
||||
quit(1);
|
||||
}
|
||||
|
||||
success = SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR,
|
||||
"Cyrillic (Ukranian)",
|
||||
"Для запису людської мови використовуються системи письма.",
|
||||
|
Reference in New Issue
Block a user