X11 message boxes should work with UTF-8 strings if possible.
authorRyan C. Gordon <icculus@icculus.org>
Fri, 07 Dec 2012 20:00:42 -0500
changeset 6723 7c464a9ecf48
parent 6722 37283d4416e0
child 6724 6c5ed0c4cc6d
X11 message boxes should work with UTF-8 strings if possible.
src/video/x11/SDL_x11messagebox.c
src/video/x11/SDL_x11sym.h
--- a/src/video/x11/SDL_x11messagebox.c	Fri Dec 07 19:59:30 2012 -0500
+++ b/src/video/x11/SDL_x11messagebox.c	Fri Dec 07 20:00:42 2012 -0500
@@ -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 <locale.h>
+
 #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 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 @@
 
 /* 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 @@
         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 @@
     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 @@
             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 @@
         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 @@
         }
     }
 
-    XFreeFontInfo( NULL, fontinfo, 1 );
     return 0;
 }
 
@@ -320,10 +339,16 @@
 static void
 X11_MessageBoxShutdown( SDL_MessageBoxDataX11 *data )
 {
-    if ( data->hfont != None )
+    if ( data->font_set != NULL )
     {
-        XUnloadFont( data->display, data->hfont );
-        data->hfont = None;
+        XFreeFontSet( data->display, data->font_set );
+        data->font_set = NULL;
+    }
+
+    if ( data->font_struct != NULL )
+    {
+        XFreeFont( data->display, data->font_struct );
+        data->font_struct = NULL;
     }
 
     if ( data->display )
@@ -434,9 +459,15 @@
     {
         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 @@
         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 @@
     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 @@
     int ret;
     SDL_MessageBoxDataX11 data;
 
-    SDL_memset( &data, 0, sizeof( data ) );
+    SDL_zero(data);
+
+    setlocale(LC_ALL, "");
 
     if ( !SDL_X11_LoadSymbols() )
         return -1;
--- a/src/video/x11/SDL_x11sym.h	Fri Dec 07 19:59:30 2012 -0500
+++ b/src/video/x11/SDL_x11sym.h	Fri Dec 07 20:00:42 2012 -0500
@@ -37,6 +37,7 @@
 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(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(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(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,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