From b824049cd02a2d1b2c039ec784ac36bb4a05b643 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Fri, 7 Dec 2012 20:00:42 -0500 Subject: [PATCH] X11 message boxes should work with UTF-8 strings if possible. --- src/video/x11/SDL_x11messagebox.c | 121 +++++++++++++++++++++--------- src/video/x11/SDL_x11sym.h | 10 ++- 2 files changed, 91 insertions(+), 40 deletions(-) diff --git a/src/video/x11/SDL_x11messagebox.c b/src/video/x11/SDL_x11messagebox.c index 7b1956145..afb51adef 100644 --- a/src/video/x11/SDL_x11messagebox.c +++ b/src/video/x11/SDL_x11messagebox.c @@ -18,6 +18,9 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ + +/* !!! FIXME: clean up differences in coding style in this file. */ + #include "SDL_config.h" #if SDL_VIDEO_DRIVER_X11 @@ -26,13 +29,16 @@ #include "SDL_x11video.h" #include "SDL_x11dyn.h" +#include + #define MAX_BUTTONS 8 /* Maximum number of buttons supported */ #define MAX_TEXT_LINES 32 /* Maximum number of text lines supported */ #define MIN_BUTTON_WIDTH 64 /* Minimum button width */ #define MIN_DIALOG_WIDTH 200 /* Minimum dialog width */ #define MIN_DIALOG_HEIGHT 100 /* Minimum dialog height */ -static const char g_MessageBoxFont[] = "-*-*-medium-r-normal--0-120-*-*-p-0-iso8859-1"; +static const char g_MessageBoxFontLatin1[] = "-*-*-medium-r-normal--0-120-*-*-p-0-iso8859-1"; +static const char g_MessageBoxFont[] = "-*-*-*-*-*-*-*-*-*-*-*-*-*-*"; static const SDL_MessageBoxColor g_default_colors[ SDL_MESSAGEBOX_COLOR_MAX ] = { @@ -67,7 +73,8 @@ typedef struct TextLineData typedef struct SDL_MessageBoxDataX11 { - Font hfont; + XFontSet font_set; /* for UTF-8 systems */ + XFontStruct *font_struct; /* Latin1 (ASCII) fallback. */ Window window; Display *display; long event_mask; @@ -105,17 +112,22 @@ IntMax( int a, int b ) /* Return width and height for a string. */ static void -GetTextWidthHeight( XFontStruct *font_struct, const char *str, int nchars, int *pwidth, int *pheight ) +GetTextWidthHeight( SDL_MessageBoxDataX11 *data, const char *str, int nbytes, int *pwidth, int *pheight ) { - XCharStruct text_structure; - int font_direction, font_ascent, font_descent; - - XTextExtents( font_struct, str, nchars, - &font_direction, &font_ascent, &font_descent, - &text_structure ); - - *pwidth = text_structure.width; - *pheight = text_structure.ascent + text_structure.descent; + if (SDL_X11_HAVE_UTF8) { + XRectangle overall_ink, overall_logical; + Xutf8TextExtents(data->font_set, str, nbytes, &overall_ink, &overall_logical); + *pwidth = overall_logical.width; + *pheight = overall_logical.height; + } else { + XCharStruct text_structure; + int font_direction, font_ascent, font_descent; + XTextExtents( data->font_struct, str, nbytes, + &font_direction, &font_ascent, &font_descent, + &text_structure ); + *pwidth = text_structure.width; + *pheight = text_structure.ascent + text_structure.descent; + } } /* Return index of button if position x,y is contained therein. */ @@ -169,10 +181,24 @@ X11_MessageBoxInit( SDL_MessageBoxDataX11 *data, const SDL_MessageBoxData * mess return -1; } - data->hfont = XLoadFont( data->display, g_MessageBoxFont ); - if ( data->hfont == None ) { - SDL_SetError("Couldn't load font %s", g_MessageBoxFont); - return -1; + if (SDL_X11_HAVE_UTF8) { + char **missing = NULL; + int num_missing = 0; + data->font_set = XCreateFontSet(data->display, g_MessageBoxFont, + &missing, &num_missing, NULL); + if ( missing != NULL ) { + XFreeStringList(missing); + } + if ( data->font_set == NULL ) { + SDL_SetError("Couldn't load font %s", g_MessageBoxFont); + return -1; + } + } else { + data->font_struct = XLoadQueryFont( data->display, g_MessageBoxFontLatin1 ); + if ( data->font_struct == NULL ) { + SDL_SetError("Couldn't load font %s", g_MessageBoxFontLatin1); + return -1; + } } if ( messageboxdata->colorScheme ) { @@ -200,12 +226,6 @@ X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *data ) int button_width = MIN_BUTTON_WIDTH; const SDL_MessageBoxData *messageboxdata = data->messageboxdata; - XFontStruct *fontinfo = XQueryFont( data->display, data->hfont ); - if ( !fontinfo ) { - SDL_SetError("Couldn't get font info"); - return -1; - } - /* Go over text and break linefeeds into separate lines. */ if ( messageboxdata->message && messageboxdata->message[ 0 ] ) { @@ -223,7 +243,7 @@ X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *data ) plinedata->length = ( lf && ( i < MAX_TEXT_LINES - 1 ) ) ? ( lf - text ) : SDL_strlen( text ); plinedata->text = text; - GetTextWidthHeight( fontinfo, text, plinedata->length, &plinedata->width, &height ); + GetTextWidthHeight( data, text, plinedata->length, &plinedata->width, &height ); /* Text and widths are the largest we've ever seen. */ data->text_height = IntMax( data->text_height, height ); @@ -248,7 +268,7 @@ X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *data ) data->buttonpos[ i ].buttondata = &data->buttondata[ i ]; data->buttonpos[ i ].length = SDL_strlen( data->buttondata[ i ].text ); - GetTextWidthHeight( fontinfo, data->buttondata[ i ].text, SDL_strlen( data->buttondata[ i ].text ), + GetTextWidthHeight( data, data->buttondata[ i ].text, SDL_strlen( data->buttondata[ i ].text ), &data->buttonpos[ i ].text_width, &height ); button_width = IntMax( button_width, data->buttonpos[ i ].text_width ); @@ -312,7 +332,6 @@ X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *data ) } } - XFreeFontInfo( NULL, fontinfo, 1 ); return 0; } @@ -320,10 +339,16 @@ X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *data ) static void X11_MessageBoxShutdown( SDL_MessageBoxDataX11 *data ) { - if ( data->hfont != None ) + if ( data->font_set != NULL ) + { + XFreeFontSet( data->display, data->font_set ); + data->font_set = NULL; + } + + if ( data->font_struct != NULL ) { - XUnloadFont( data->display, data->hfont ); - data->hfont = None; + XFreeFont( data->display, data->font_struct ); + data->font_struct = NULL; } if ( data->display ) @@ -434,9 +459,15 @@ X11_MessageBoxDraw( SDL_MessageBoxDataX11 *data, GC ctx ) { TextLineData *plinedata = &data->linedata[ i ]; - XDrawString( display, window, ctx, - data->xtext, data->ytext + i * data->text_height, - plinedata->text, plinedata->length ); + if (SDL_X11_HAVE_UTF8) { + Xutf8DrawString( display, window, data->font_set, ctx, + data->xtext, data->ytext + i * data->text_height, + plinedata->text, plinedata->length ); + } else { + XDrawString( display, window, ctx, + data->xtext, data->ytext + i * data->text_height, + plinedata->text, plinedata->length ); + } } for ( i = 0; i < data->numbuttons; i++ ) @@ -459,9 +490,17 @@ X11_MessageBoxDraw( SDL_MessageBoxDataX11 *data, GC ctx ) XSetForeground( display, ctx, ( data->mouse_over_index == i ) ? data->color[ SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED ] : data->color[ SDL_MESSAGEBOX_COLOR_TEXT ] ); - XDrawString( display, window, ctx, - buttondatax11->x + offset, buttondatax11->y + offset, - buttondata->text, buttondatax11->length ); + + if (SDL_X11_HAVE_UTF8) { + Xutf8DrawString( display, window, data->font_set, ctx, + buttondatax11->x + offset, + buttondatax11->y + offset, + buttondata->text, buttondatax11->length ); + } else { + XDrawString( display, window, ctx, + buttondatax11->x + offset, buttondatax11->y + offset, + buttondata->text, buttondatax11->length ); + } } } @@ -474,12 +513,18 @@ X11_MessageBoxLoop( SDL_MessageBoxDataX11 *data ) SDL_bool close_dialog = SDL_FALSE; SDL_bool has_focus = SDL_TRUE; KeySym last_key_pressed = XK_VoidSymbol; + unsigned long gcflags = GCForeground | GCBackground; - ctx_vals.font = data->hfont; + SDL_zero(ctx_vals); ctx_vals.foreground = data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ]; ctx_vals.background = data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ]; - ctx = XCreateGC( data->display, data->window, GCForeground | GCBackground | GCFont, &ctx_vals ); + if (!SDL_X11_HAVE_UTF8) { + gcflags |= GCFont; + ctx_vals.font = data->font_struct->fid; + } + + ctx = XCreateGC( data->display, data->window, gcflags, &ctx_vals ); if ( ctx == None ) { SDL_SetError("Couldn't create graphics context"); return -1; @@ -610,7 +655,9 @@ X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) int ret; SDL_MessageBoxDataX11 data; - SDL_memset( &data, 0, sizeof( data ) ); + SDL_zero(data); + + setlocale(LC_ALL, ""); if ( !SDL_X11_LoadSymbols() ) return -1; diff --git a/src/video/x11/SDL_x11sym.h b/src/video/x11/SDL_x11sym.h index 394a39707..673142e3c 100644 --- a/src/video/x11/SDL_x11sym.h +++ b/src/video/x11/SDL_x11sym.h @@ -37,6 +37,7 @@ SDL_X11_SYM(Pixmap,XCreateBitmapFromData,(Display *dpy,Drawable d,_Xconst char * SDL_X11_SYM(Colormap,XCreateColormap,(Display* a,Window b,Visual* c,int d),(a,b,c,d),return) SDL_X11_SYM(Cursor,XCreatePixmapCursor,(Display* a,Pixmap b,Pixmap c,XColor* d,XColor* e,unsigned int f,unsigned int g),(a,b,c,d,e,f,g),return) SDL_X11_SYM(Cursor,XCreateFontCursor,(Display* a,unsigned int b),(a,b),return) +SDL_X11_SYM(XFontSet,XCreateFontSet,(Display* a, _Xconst char* b, char*** c, int* d, char** e),(a,b,c,d,e),return) SDL_X11_SYM(GC,XCreateGC,(Display* a,Drawable b,unsigned long c,XGCValues* d),(a,b,c,d),return) SDL_X11_SYM(XImage*,XCreateImage,(Display* a,Visual* b,unsigned int c,int d,int e,char* f,unsigned int g,unsigned int h,int i,int j),(a,b,c,d,e,f,g,h,i,j),return) SDL_X11_SYM(Window,XCreateWindow,(Display* a,Window b,int c,int d,unsigned int e,unsigned int f,unsigned int g,int h,unsigned int i,Visual* j,unsigned long k,XSetWindowAttributes* l),(a,b,c,d,e,f,g,h,i,j,k,l),return) @@ -53,10 +54,12 @@ SDL_X11_SYM(Bool,XFilterEvent,(XEvent *event,Window w),(event,w),return) SDL_X11_SYM(int,XFlush,(Display* a),(a),return) SDL_X11_SYM(int,XFree,(void*a),(a),return) SDL_X11_SYM(int,XFreeCursor,(Display* a,Cursor b),(a,b),return) +SDL_X11_SYM(void,XFreeFontSet,(Display* a, XFontSet b),(a,b),) SDL_X11_SYM(int,XFreeGC,(Display* a,GC b),(a,b),return) -SDL_X11_SYM(int,XFreeFontInfo,(char** a,XFontStruct* b,int c),(a,b,c),return) +SDL_X11_SYM(int,XFreeFont,(Display* a, XFontStruct* b),(a,b),return) SDL_X11_SYM(int,XFreeModifiermap,(XModifierKeymap* a),(a),return) SDL_X11_SYM(int,XFreePixmap,(Display* a,Pixmap b),(a,b),return) +SDL_X11_SYM(void,XFreeStringList,(char** a),(a),) SDL_X11_SYM(char*,XGetAtomName,(Display *a,Atom b),(a,b),return) SDL_X11_SYM(int,XGetInputFocus,(Display *a,Window *b,int *c),(a,b,c),return) SDL_X11_SYM(int,XGetErrorDatabaseText,(Display* a,_Xconst char* b,_Xconst char* c,_Xconst char* d,char* e,int f),(a,b,c,d,e,f),return) @@ -78,7 +81,7 @@ SDL_X11_SYM(char*,XKeysymToString,(KeySym a),(a),return) SDL_X11_SYM(int,XInstallColormap,(Display* a,Colormap b),(a,b),return) SDL_X11_SYM(Atom,XInternAtom,(Display* a,_Xconst char* b,Bool c),(a,b,c),return) SDL_X11_SYM(XPixmapFormatValues*,XListPixmapFormats,(Display* a,int* b),(a,b),return) -SDL_X11_SYM(Font,XLoadFont,(Display* a,_Xconst char* b),(a,b),return) +SDL_X11_SYM(XFontStruct*,XLoadQueryFont,(Display* a,_Xconst char* b),(a,b),return) SDL_X11_SYM(KeySym,XLookupKeysym,(XKeyEvent* a,int b),(a,b),return) SDL_X11_SYM(int,XLookupString,(XKeyEvent* a,char* b,int c,KeySym* d,XComposeStatus* e),(a,b,c,d,e),return) SDL_X11_SYM(int,XMapRaised,(Display* a,Window b),(a,b),return) @@ -91,7 +94,6 @@ SDL_X11_SYM(Status,XInitThreads,(void),(),return) SDL_X11_SYM(int,XPeekEvent,(Display* a,XEvent* b),(a,b),return) SDL_X11_SYM(int,XPending,(Display* a),(a),return) SDL_X11_SYM(int,XPutImage,(Display* a,Drawable b,GC c,XImage* d,int e,int f,int g,int h,unsigned int i,unsigned int j),(a,b,c,d,e,f,g,h,i,j),return) -SDL_X11_SYM(XFontStruct*,XQueryFont,(Display* a,XID b),(a,b),return) SDL_X11_SYM(int,XQueryKeymap,(Display* a,char *b),(a,b),return) SDL_X11_SYM(Bool,XQueryPointer,(Display* a,Window b,Window* c,Window* d,int* e,int* f,int* g,int* h,unsigned int* i),(a,b,c,d,e,f,g,h,i),return) SDL_X11_SYM(int,XRaiseWindow,(Display* a,Window b),(a,b),return) @@ -181,6 +183,8 @@ SDL_X11_SYM(void,XSetICFocus,(XIC a),(a),) SDL_X11_SYM(void,XUnsetICFocus,(XIC a),(a),) SDL_X11_SYM(XIM,XOpenIM,(Display* a,struct _XrmHashBucketRec* b,char* c,char* d),(a,b,c,d),return) SDL_X11_SYM(Status,XCloseIM,(XIM a),(a),return) +SDL_X11_SYM(void,Xutf8DrawString,(Display *a, Drawable b, XFontSet c, GC d, int e, int f, _Xconst char *g, int h),(a,b,c,d,e,f,g,h),) +SDL_X11_SYM(int,Xutf8TextExtents,(XFontSet a, _Xconst char* b, int c, XRectangle* d, XRectangle* e),(a,b,c,d,e),return) #endif #ifndef NO_SHARED_MEMORY