Added API for simple messagebox, courtesy of Mike Sartain
authorSam Lantinga <slouken@libsdl.org>
Tue, 23 Oct 2012 17:11:22 -0700
changeset 6602 533131e24aeb
parent 6601 0d0946905eb2
child 6603 fc815cb0a2de
Added API for simple messagebox, courtesy of Mike Sartain
include/SDL.h
include/SDL_messagebox.h
src/video/SDL_sysvideo.h
src/video/SDL_video.c
src/video/x11/SDL_x11messagebox.c
src/video/x11/SDL_x11sym.h
test/common.c
--- a/include/SDL.h	Tue Oct 23 17:10:09 2012 -0700
+++ b/include/SDL.h	Tue Oct 23 17:11:22 2012 -0700
@@ -82,6 +82,7 @@
 #include "SDL_hints.h"
 #include "SDL_loadso.h"
 #include "SDL_log.h"
+#include "SDL_messagebox.h"
 #include "SDL_mutex.h"
 #include "SDL_power.h"
 #include "SDL_render.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/SDL_messagebox.h	Tue Oct 23 17:11:22 2012 -0700
@@ -0,0 +1,140 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2012 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.
+*/
+
+#ifndef _SDL_messagebox_h
+#define _SDL_messagebox_h
+
+#include "SDL_stdinc.h"
+#include "SDL_video.h"      /* For SDL_Window */
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C" {
+/* *INDENT-ON* */
+#endif
+
+/**
+ * \brief SDL_MessageBox flags. If supported will display warning icon, etc.
+ */
+typedef enum
+{
+    SDL_MESSAGEBOX_ERROR        = 0x00000010,   /**< error dialog */
+    SDL_MESSAGEBOX_WARNING      = 0x00000020,   /**< warning dialog */
+    SDL_MESSAGEBOX_INFORMATION  = 0x00000040,   /**< informational dialog */
+} SDL_MessageBoxFlags;
+
+/**
+ * \brief Flags for SDL_MessageBoxButtonData.
+ */
+typedef enum
+{
+    SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT = 0x00000001,  /**< Marks the default button when return is hit */
+    SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT = 0x00000002,  /**< Marks the default button when escape is hit */
+} SDL_MessageBoxButtonFlags;
+
+/**
+ *  \brief Individual button data.
+ */
+typedef struct
+{
+    Uint32 flags;       /**< ::SDL_MessageBoxButtonFlags */
+    int buttonid;       /**< User defined button id (value returned via SDL_MessageBox) */
+    const char * text;  /**< The UTF-8 button text */
+} SDL_MessageBoxButtonData;
+
+/**
+ * \brief RGB value used in a message box color scheme
+ */
+typedef struct
+{
+    Uint8 r, g, b;
+} SDL_MessageBoxColor;
+
+typedef enum
+{
+	SDL_MESSAGEBOX_COLOR_BACKGROUND,
+	SDL_MESSAGEBOX_COLOR_TEXT,
+	SDL_MESSAGEBOX_COLOR_BUTTON_BORDER,
+	SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND,
+	SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED,
+	SDL_MESSAGEBOX_COLOR_MAX
+} SDL_MessageBoxColorType;
+
+/**
+ * \brief A set of colors to use for message box dialogs
+ */
+typedef struct
+{
+    SDL_MessageBoxColor colors[SDL_MESSAGEBOX_COLOR_MAX];
+} SDL_MessageBoxColorScheme;
+
+/**
+ *  \brief MessageBox structure containing title, text, window, etc.
+ */
+typedef struct
+{
+    Uint32 flags;                       /**< ::SDL_MessageBoxFlags */
+    SDL_Window *window;                 /**< Parent window, can be NULL */
+    const char *title;                  /**< UTF-8 title */
+    const char *message;                /**< UTF-8 message text */
+
+    int numbuttons;
+    const SDL_MessageBoxButtonData *buttons;
+
+    const SDL_MessageBoxColorScheme *colorScheme;   /**< ::SDL_MessageBoxColorScheme, can be NULL to use system settings */
+} SDL_MessageBoxData;
+
+/**
+ *  \brief Create a modal message box.
+ *
+ *  \param messagebox The SDL_MessageBox structure with title, text, etc.
+ *
+ *  \return -1 on error, otherwise 0 and buttonid contains user id of button
+ *          hit or -1 if dialog was closed.
+ */
+extern DECLSPEC int SDLCALL SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
+
+/**
+ *  \brief Create a simple modal message box
+ *
+ *  \param flags    ::SDL_MessageBoxFlags
+ *  \param title    UTF-8 title text
+ *  \param message  UTF-8 message text
+ *  \param window   The parent window, or NULL for no parent
+ *
+ *  \return 0 on success, -1 on error
+ */
+extern DECLSPEC int SDLCALL SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_messagebox_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/SDL_sysvideo.h	Tue Oct 23 17:10:09 2012 -0700
+++ b/src/video/SDL_sysvideo.h	Tue Oct 23 17:11:22 2012 -0700
@@ -23,6 +23,7 @@
 #ifndef _SDL_sysvideo_h
 #define _SDL_sysvideo_h
 
+#include "SDL_messagebox.h"
 #include "SDL_shape.h"
 
 /* The SDL video driver */
@@ -246,6 +247,9 @@
     char * (*GetClipboardText) (_THIS);
     SDL_bool (*HasClipboardText) (_THIS);
 
+    /* MessageBox */
+    int (*ShowMessageBox) (_THIS, const SDL_MessageBoxData *messageboxdata, int *buttonid);
+
     /* * * */
     /* Data common to all drivers */
     SDL_bool suspend_screensaver;
--- a/src/video/SDL_video.c	Tue Oct 23 17:10:09 2012 -0700
+++ b/src/video/SDL_video.c	Tue Oct 23 17:11:22 2012 -0700
@@ -2839,4 +2839,55 @@
     return SDL_FALSE;
 }
 
+#if SDL_VIDEO_DRIVER_X11
+extern int X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid);
+#endif
+
+int
+SDL_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
+{
+    int dummybutton;
+
+    if (!buttonid) {
+        buttonid = &dummybutton;
+    }
+    if (_this && _this->ShowMessageBox) {
+        if (_this->ShowMessageBox(_this, messageboxdata, buttonid) == 0) {
+            return 0;
+        }
+    }
+
+    /* It's completely fine to call this function before video is initialized */
+#if SDL_VIDEO_DRIVER_X11
+    if (X11_ShowMessageBox(messageboxdata, buttonid) == 0) {
+        return 0;
+    }
+#endif
+
+    SDL_SetError("No message system available");
+    return -1;
+}
+
+int
+SDL_ShowSimpleMessageBox(Uint32 flags, const char *title, const char *message, SDL_Window *window)
+{
+    SDL_MessageBoxData data;
+    SDL_MessageBoxButtonData button;
+
+    SDL_zero(data);
+    data.flags = flags;
+    data.title = title;
+    data.message = message;
+    data.numbuttons = 1;
+    data.buttons = &button;
+    data.window = window;
+
+    SDL_zero(button);
+    button.flags |= SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
+    button.flags |= SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
+    button.text = "OK";
+
+    return SDL_ShowMessageBox(&data, NULL);
+}
+
 /* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/x11/SDL_x11messagebox.c	Tue Oct 23 17:11:22 2012 -0700
@@ -0,0 +1,642 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2012 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_config.h"
+
+#if SDL_VIDEO_DRIVER_X11
+
+#include "SDL.h"
+#include "SDL_x11video.h"
+#include "SDL_x11dyn.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 SDL_MessageBoxColor g_default_colors[ SDL_MESSAGEBOX_COLOR_MAX ] =
+{
+	{ 56,  54,  53  }, // SDL_MESSAGEBOX_COLOR_BACKGROUND,       
+	{ 209, 207, 205 }, // SDL_MESSAGEBOX_COLOR_TEXT,             
+	{ 140, 135, 129 }, // SDL_MESSAGEBOX_COLOR_BUTTON_BORDER,    
+	{ 105, 102, 99  }, // SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND,
+	{ 205, 202, 53  }, // SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED,  
+};
+
+#define SDL_MAKE_RGB( _r, _g, _b )  ( ( ( Uint32 )( _r ) << 16 ) | \
+                                      ( ( Uint32 )( _g ) << 8 ) |  \
+                                      ( ( Uint32 )( _b ) ) )
+
+typedef struct SDL_MessageBoxButtonDataX11
+{
+    int x, y;                           /* Text position */
+    int length;                         /* Text length */
+    int text_width;                     /* Text width */
+
+    SDL_Rect rect;                      /* Rectangle for entire button */
+
+    const SDL_MessageBoxButtonData *buttondata;   /* Button data from caller */
+} SDL_MessageBoxButtonDataX11;
+
+typedef struct TextLineData
+{
+    int width;                          /* Width of this text line */
+    int length;                         /* String length of this text line */
+    const char *text;                   /* Text for this line */
+} TextLineData;
+
+typedef struct SDL_MessageBoxDataX11
+{
+    Font hfont;
+    Window window;
+    Display *display;
+	long event_mask;
+    Atom wm_protocols;
+    Atom wm_delete_message;
+
+    int dialog_width;                   /* Dialog box width. */
+    int dialog_height;                  /* Dialog box height. */
+
+    int xtext, ytext;                   /* Text position to start drawing at. */
+    int numlines;                       /* Count of Text lines. */
+    int text_height;                    /* Height for text lines. */
+    TextLineData linedata[ MAX_TEXT_LINES ];
+
+    int *pbuttonid;                     /* Pointer to user return buttonid value. */
+
+    int button_press_index;             /* Index into buttondata/buttonpos for button which is pressed (or -1). */
+    int mouse_over_index;               /* Index into buttondata/buttonpos for button mouse is over (or -1). */
+
+    int numbuttons;                     /* Count of buttons. */
+    const SDL_MessageBoxButtonData *buttondata;
+    SDL_MessageBoxButtonDataX11 buttonpos[ MAX_BUTTONS ];
+
+	Uint32 color[ SDL_MESSAGEBOX_COLOR_MAX ];
+
+    const SDL_MessageBoxData *messageboxdata;
+} SDL_MessageBoxDataX11;
+
+/* Maximum helper for ints. */
+static __inline__ int
+IntMax( int a, int b )
+{
+    return ( a > b  ) ? a : b;
+}
+
+/* Return width and height for a string. */
+static void
+GetTextWidthHeight( XFontStruct *font_struct, const char *str, int nchars, 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;
+}
+
+/* Return index of button if position x,y is contained therein. */
+static int
+GetHitButtonIndex( SDL_MessageBoxDataX11 *data, int x, int y )
+{
+    int i;
+    int numbuttons = data->numbuttons;
+    SDL_MessageBoxButtonDataX11 *buttonpos = data->buttonpos;
+
+    for ( i = 0; i < numbuttons; i++ )
+    {
+        SDL_Rect *rect = &buttonpos[ i ].rect;
+
+        if ( ( x >= rect->x ) &&
+            ( x <= ( rect->x + rect->w ) ) &&
+            ( y >= rect->y ) &&
+            ( y <= ( rect->y + rect->h ) ) )
+        {
+            return i;
+        }
+    }
+
+    return -1;
+}
+
+/* Initialize SDL_MessageBoxData structure and Display, etc. */
+static int
+X11_MessageBoxInit( SDL_MessageBoxDataX11 *data, const SDL_MessageBoxData * messageboxdata, int * pbuttonid )
+{
+	int i;
+    int numbuttons = messageboxdata->numbuttons;
+    const SDL_MessageBoxButtonData *buttondata = messageboxdata->buttons;
+	const SDL_MessageBoxColor *colorhints;
+
+    if ( numbuttons > MAX_BUTTONS ) {
+        SDL_SetError("Too many buttons (%d max allowed)", MAX_BUTTONS);
+        return -1;
+    }
+
+    data->dialog_width = MIN_DIALOG_WIDTH;
+    data->dialog_height = MIN_DIALOG_HEIGHT;
+    data->messageboxdata = messageboxdata;
+    data->buttondata = buttondata;
+    data->numbuttons = numbuttons;
+    data->pbuttonid = pbuttonid;
+
+    data->display = XOpenDisplay( NULL );
+    if ( !data->display ) {
+        SDL_SetError("Couldn't open X11 display");
+        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 ( messageboxdata->colorScheme ) {
+		colorhints = messageboxdata->colorScheme->colors;
+	} else {
+		colorhints = g_default_colors;
+	}
+
+	/* Convert our SDL_MessageBoxColor r,g,b values to packed RGB format. */
+	for ( i = 0; i < SDL_MESSAGEBOX_COLOR_MAX; i++ ) {
+		data->color[ i ] = SDL_MAKE_RGB( colorhints[ i ].r, colorhints[ i ].g, colorhints[ i ].b );
+	}
+
+    return 0;
+}
+
+/* Calculate and initialize text and button locations. */
+static int
+X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *data )
+{
+    int i;
+    int ybuttons;
+    int text_width_max = 0;
+    int button_text_height = 0;
+    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 ] )
+    {
+        const char *text = messageboxdata->message;
+        TextLineData *plinedata = data->linedata;
+
+        for ( i = 0; i < MAX_TEXT_LINES; i++, plinedata++ )
+        {
+            int height;
+            char *lf = SDL_strchr( ( char * )text, '\n' );
+
+            data->numlines++;
+
+            /* Only grab length up to lf if it exists and isn't the last line. */
+            plinedata->length = ( lf && ( i < MAX_TEXT_LINES - 1 ) ) ? ( lf - text ) : SDL_strlen( text );
+            plinedata->text = text;
+
+            GetTextWidthHeight( fontinfo, text, plinedata->length, &plinedata->width, &height );
+
+            /* Text and widths are the largest we've ever seen. */
+            data->text_height = IntMax( data->text_height, height );
+            text_width_max = IntMax( text_width_max, plinedata->width );
+
+            text += plinedata->length + 1;
+
+            /* Break if there are no more linefeeds. */
+            if ( !lf )
+                break;
+        }
+
+        /* Bump up the text height slightly. */
+        data->text_height += 2;
+    }
+
+    /* Loop through all buttons and calculate the button widths and height. */
+    for ( i = 0; i < data->numbuttons; i++ )
+    {
+        int height;
+
+        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 ),
+                            &data->buttonpos[ i ].text_width, &height );
+
+        button_width = IntMax( button_width, data->buttonpos[ i ].text_width );
+        button_text_height = IntMax( button_text_height, height );
+    }
+
+    if ( data->numlines )
+    {
+        /* x,y for this line of text. */
+        data->xtext = data->text_height;
+        data->ytext = data->text_height + data->text_height;
+
+        /* Bump button y down to bottom of text. */
+        ybuttons = 3 * data->ytext / 2 + ( data->numlines - 1 ) * data->text_height;
+
+        /* Bump the dialog box width and height up if needed. */
+        data->dialog_width = IntMax( data->dialog_width, 2 * data->xtext + text_width_max );
+        data->dialog_height = IntMax( data->dialog_height, ybuttons );
+    }
+    else
+    {
+        /* Button y starts at height of button text. */
+        ybuttons = button_text_height;
+    }
+
+    if ( data->numbuttons )
+    {
+        int x, y;
+        int width_of_buttons;
+        int button_spacing = button_text_height;
+        int button_height = 2 * button_text_height;
+
+        /* Bump button width up a bit. */
+        button_width += button_text_height;
+
+        /* Get width of all buttons lined up. */
+        width_of_buttons = data->numbuttons * button_width + ( data->numbuttons - 1 ) * button_spacing;
+
+        /* Bump up dialog width and height if buttons are wider than text. */
+        data->dialog_width = IntMax( data->dialog_width, width_of_buttons + 2 * button_spacing );
+        data->dialog_height = IntMax( data->dialog_height, ybuttons + 2 * button_height );
+
+        /* Location for first button. */
+        x = ( data->dialog_width - width_of_buttons ) / 2;
+        y = ybuttons + ( data->dialog_height - ybuttons - button_height ) / 2;
+
+        for ( i = 0; i < data->numbuttons; i++ )
+        {
+            /* Button coordinates. */
+            data->buttonpos[ i ].rect.x = x;
+            data->buttonpos[ i ].rect.y = y;
+            data->buttonpos[ i ].rect.w = button_width;
+            data->buttonpos[ i ].rect.h = button_height;
+
+            /* Button text coordinates. */
+            data->buttonpos[ i ].x = x + ( button_width - data->buttonpos[ i ].text_width ) / 2;
+            data->buttonpos[ i ].y = y + ( button_height - button_text_height - 1 ) / 2 + button_text_height;
+
+            /* Scoot over for next button. */
+            x += button_width + button_text_height;
+        }
+    }
+
+    XFreeFontInfo( NULL, fontinfo, 1 );
+    return 0;
+}
+
+/* Free SDL_MessageBoxData data. */
+static void
+X11_MessageBoxShutdown( SDL_MessageBoxDataX11 *data )
+{
+    if ( data->hfont != None )
+    {
+        XUnloadFont( data->display, data->hfont );
+        data->hfont = None;
+    }
+
+    if ( data->display )
+    {
+        if ( data->window != None )
+        {
+            XUnmapWindow( data->display, data->window );
+            XDestroyWindow( data->display, data->window );
+            data->window = None;
+        }
+
+        XCloseDisplay( data->display );
+        data->display = NULL;
+    }
+}
+
+/* Create and set up our X11 dialog box indow. */
+static int
+X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data )
+{
+    int x, y;
+    XSizeHints *sizehints;
+    XSetWindowAttributes wnd_attr;
+    Display *display = data->display;
+    SDL_WindowData *windowdata = NULL;
+    const SDL_MessageBoxData *messageboxdata = data->messageboxdata;
+
+    if ( messageboxdata->window ) {
+        windowdata = (SDL_WindowData *)messageboxdata->window->driverdata;
+    }
+
+    data->event_mask = ExposureMask |
+        ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
+        StructureNotifyMask | FocusChangeMask | PointerMotionMask;
+	wnd_attr.event_mask = data->event_mask;
+
+    data->window = XCreateWindow(
+                            display, DefaultRootWindow( display ),
+                            0, 0,
+                            data->dialog_width, data->dialog_height,
+                            0, CopyFromParent, InputOutput, CopyFromParent,
+                            CWEventMask, &wnd_attr );
+    if ( data->window == None ) {
+        SDL_SetError("Couldn't create X window");
+        return -1;
+    }
+
+    if ( windowdata ) {
+        /* http://tronche.com/gui/x/icccm/sec-4.html#WM_TRANSIENT_FOR */
+        XSetTransientForHint( display, data->window, windowdata->xwindow );
+    }
+
+    XStoreName( display, data->window, messageboxdata->title );
+
+    /* Allow the window to be deleted by the window manager */
+    data->wm_protocols = XInternAtom( display, "WM_PROTOCOLS", False );
+    data->wm_delete_message = XInternAtom( display, "WM_DELETE_WINDOW", False );
+    XSetWMProtocols( display, data->window, &data->wm_delete_message, 1 );
+
+    if ( windowdata ) {
+        XWindowAttributes attrib;
+        Window dummy;
+
+        XGetWindowAttributes(display, windowdata->xwindow, &attrib);
+        x = attrib.x + ( attrib.width - data->dialog_width ) / 2;
+        y = attrib.y + ( attrib.height - data->dialog_height ) / 3 ;
+        XTranslateCoordinates(display, windowdata->xwindow, DefaultRootWindow( display ), x, y, &x, &y, &dummy);
+    } else {
+        int screen = DefaultScreen( display );
+        x = ( DisplayWidth( display, screen ) - data->dialog_width ) / 2;
+        y = ( DisplayHeight( display, screen ) - data->dialog_height ) / 3 ;
+    }
+    XMoveWindow( display, data->window, x, y );
+
+    sizehints = XAllocSizeHints();
+    if ( sizehints ) {
+        sizehints->flags = USPosition | USSize | PMaxSize | PMinSize;
+        sizehints->x = x;
+        sizehints->y = y;
+        sizehints->width = data->dialog_width;
+        sizehints->height = data->dialog_height;
+
+        sizehints->min_width = sizehints->max_width = data->dialog_width;
+        sizehints->min_height = sizehints->max_height = data->dialog_height;
+
+        XSetWMNormalHints( display, data->window, sizehints );
+
+        XFree( sizehints );
+    }
+
+    XMapRaised( display, data->window );
+    return 0;
+}
+
+/* Draw our message box. */
+static void
+X11_MessageBoxDraw( SDL_MessageBoxDataX11 *data, GC ctx )
+{
+    int i;
+    Window window = data->window;
+    Display *display = data->display;
+
+    XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ] );
+    XFillRectangle( display, window, ctx, 0, 0, data->dialog_width, data->dialog_height );
+
+    XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_TEXT ] );
+    for ( i = 0; i < data->numlines; i++ )
+    {
+        TextLineData *plinedata = &data->linedata[ i ];
+
+        XDrawString( display, window, ctx,
+                     data->xtext, data->ytext + i * data->text_height,
+                     plinedata->text, plinedata->length );
+    }
+
+    for ( i = 0; i < data->numbuttons; i++ )
+    {
+        SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[ i ];
+        const SDL_MessageBoxButtonData *buttondata = buttondatax11->buttondata;
+        int border = ( buttondata->flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT ) ? 2 : 0;
+        int offset = ( ( data->mouse_over_index == i ) && ( data->button_press_index == data->mouse_over_index ) ) ? 1 : 0;
+
+        XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND ] );
+        XFillRectangle( display, window, ctx,
+                        buttondatax11->rect.x - border, buttondatax11->rect.y - border,
+                        buttondatax11->rect.w + 2 * border, buttondatax11->rect.h + 2 * border );
+
+        XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BUTTON_BORDER ] );
+        XDrawRectangle( display, window, ctx,
+                        buttondatax11->rect.x, buttondatax11->rect.y,
+                        buttondatax11->rect.w, buttondatax11->rect.h );
+
+        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 );
+    }
+}
+
+/* Loop and handle message box event messages until something kills it. */
+static int
+X11_MessageBoxLoop( SDL_MessageBoxDataX11 *data )
+{
+    GC ctx;
+    XGCValues ctx_vals;
+    SDL_bool close_dialog = SDL_FALSE;
+    SDL_bool has_focus = SDL_TRUE;
+    KeySym last_key_pressed = XK_VoidSymbol;
+
+    ctx_vals.font = data->hfont;
+    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 ( ctx == None ) {
+        SDL_SetError("Couldn't create graphics context");
+        return -1;
+    }
+
+    data->button_press_index = -1;  /* Reset what button is currently depressed. */
+    data->mouse_over_index = -1;    /* Reset what button the mouse is over. */
+
+    while( !close_dialog ) {
+        XEvent e;
+        SDL_bool draw = SDL_TRUE;
+
+		XWindowEvent( data->display, data->window, data->event_mask, &e );
+
+        /* If XFilterEvent returns True, then some input method has filtered the
+           event, and the client should discard the event. */
+        if ( ( e.type != Expose ) && XFilterEvent( &e, None ) )
+            continue;
+
+        switch( e.type ) {
+        case Expose:
+            if ( e.xexpose.count > 0 ) {
+                draw = SDL_FALSE;
+            }
+            break;
+
+        case FocusIn:
+            /* Got focus. */
+            has_focus = SDL_TRUE;
+            break;
+
+        case FocusOut:
+            /* lost focus. Reset button and mouse info. */
+            has_focus = SDL_FALSE;
+            data->button_press_index = -1;
+            data->mouse_over_index = -1;
+            break;
+
+        case MotionNotify:
+            if ( has_focus ) {
+                /* Mouse moved... */
+                data->mouse_over_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
+            }
+            break;
+
+        case ClientMessage:
+            if ( e.xclient.message_type == data->wm_protocols &&
+                 e.xclient.format == 32 &&
+                 e.xclient.data.l[ 0 ] == data->wm_delete_message ) {
+                close_dialog = SDL_TRUE;
+            }
+            break;
+
+        case KeyPress:
+            /* Store key press - we make sure in key release that we got both. */
+            last_key_pressed = XLookupKeysym( &e.xkey, 0 );
+            break;
+
+        case KeyRelease:
+        {
+            Uint32 mask = 0;
+            KeySym key = XLookupKeysym( &e.xkey, 0 );
+
+            /* If this is a key release for something we didn't get the key down for, then bail. */
+            if ( key != last_key_pressed )
+                break;
+
+            if ( key == XK_Escape )
+                mask = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
+            else if ( ( key == XK_Return ) || ( key == XK_KP_Enter ) )
+                mask = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
+
+            if ( mask ) {
+                int i;
+
+                /* Look for first button with this mask set, and return it if found. */
+                for ( i = 0; i < data->numbuttons; i++ ) {
+                    SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[ i ];
+
+                    if ( buttondatax11->buttondata->flags & mask ) {
+                        *data->pbuttonid = buttondatax11->buttondata->buttonid;
+                        close_dialog = SDL_TRUE;
+                        break;
+                    }
+                }
+            }
+            break;
+        }
+
+        case ButtonPress:
+            data->button_press_index = -1;
+            if ( e.xbutton.button == Button1 ) {
+                /* Find index of button they clicked on. */
+                data->button_press_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
+            }
+            break;
+
+        case ButtonRelease:
+            /* If button is released over the same button that was clicked down on, then return it. */
+            if ( ( e.xbutton.button == Button1 ) && ( data->button_press_index >= 0 ) ) {
+                int button = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
+
+                if ( data->button_press_index == button ) {
+                    SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[ button ];
+
+                    *data->pbuttonid = buttondatax11->buttondata->buttonid;
+                    close_dialog = SDL_TRUE;
+                }
+            }
+            data->button_press_index = -1;
+            break;
+        }
+
+        if ( draw ) {
+            /* Draw our dialog box. */
+            X11_MessageBoxDraw( data, ctx );
+        }
+    }
+
+    XFreeGC( data->display, ctx );
+    return 0;
+}
+
+/* Display an x11 message box. */
+int
+X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
+{
+    int ret;
+    SDL_MessageBoxDataX11 data;
+
+    SDL_memset( &data, 0, sizeof( data ) );
+
+    if ( !SDL_X11_LoadSymbols() )
+        return -1;
+
+    /* This code could get called from multiple threads maybe? */
+    XInitThreads();
+
+    /* Initialize the return buttonid value to -1 (for error or dialogbox closed). */
+    *buttonid = -1;
+
+    /* Init and display the message box. */
+    ret = X11_MessageBoxInit( &data, messageboxdata, buttonid );
+    if ( ret != -1 ) {
+        ret = X11_MessageBoxInitPositions( &data );
+        if ( ret != -1 ) {
+            ret = X11_MessageBoxCreateWindow( &data );
+            if ( ret != -1 ) {
+                ret = X11_MessageBoxLoop( &data );
+            }
+        }
+    }
+
+    X11_MessageBoxShutdown( &data );
+    return ret;
+}
+
+#endif /* SDL_VIDEO_DRIVER_X11 */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/x11/SDL_x11sym.h	Tue Oct 23 17:10:09 2012 -0700
+++ b/src/video/x11/SDL_x11sym.h	Tue Oct 23 17:11:22 2012 -0700
@@ -43,13 +43,17 @@
 SDL_X11_SYM(int,XDeleteProperty,(Display* a,Window b,Atom c),(a,b,c),return)
 SDL_X11_SYM(int,XDestroyWindow,(Display* a,Window b),(a,b),return)
 SDL_X11_SYM(int,XDisplayKeycodes,(Display* a,int* b,int* c),(a,b,c),return)
+SDL_X11_SYM(int,XDrawRectangle,(Display* a,Drawable b,GC c,int d,int e,unsigned int f,unsigned int g),(a,b,c,d,e,f,g),return)
 SDL_X11_SYM(char*,XDisplayName,(_Xconst char* a),(a),return)
+SDL_X11_SYM(int,XDrawString,(Display* a,Drawable b,GC c,int d,int e,_Xconst char* f,int g),(a,b,c,d,e,f,g),return)
 SDL_X11_SYM(int,XEventsQueued,(Display* a,int b),(a,b),return)
+SDL_X11_SYM(int,XFillRectangle,(Display* a,Drawable b,GC c,int d,int e,unsigned int f,unsigned int g),(a,b,c,d,e,f,g),return)
 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(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,XFreeModifiermap,(XModifierKeymap* a),(a),return)
 SDL_X11_SYM(int,XFreePixmap,(Display* a,Pixmap b),(a,b),return)
 SDL_X11_SYM(char*,XGetAtomName,(Display *a,Atom b),(a,b),return)
@@ -73,6 +77,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(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)
@@ -85,6 +90,7 @@
 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)
@@ -94,6 +100,7 @@
 SDL_X11_SYM(int,XSelectInput,(Display* a,Window b,long c),(a,b,c),return)
 SDL_X11_SYM(Status,XSendEvent,(Display* a,Window b,Bool c,long d,XEvent* e),(a,b,c,d,e),return)
 SDL_X11_SYM(XErrorHandler,XSetErrorHandler,(XErrorHandler a),(a),return)
+SDL_X11_SYM(int,XSetForeground,(Display* a,GC b,unsigned long c),(a,b,c),return)
 SDL_X11_SYM(XIOErrorHandler,XSetIOErrorHandler,(XIOErrorHandler a),(a),return)
 SDL_X11_SYM(int,XSetInputFocus,(Display *a,Window b,int c,Time d),(a,b,c,d),return)
 SDL_X11_SYM(int,XSetSelectionOwner,(Display* a,Atom b,Window c,Time d),(a,b,c,d),return)
@@ -104,15 +111,20 @@
 SDL_X11_SYM(void,XSetWMNormalHints,(Display* a,Window b,XSizeHints* c),(a,b,c),)
 SDL_X11_SYM(Status,XSetWMProtocols,(Display* a,Window b,Atom* c,int d),(a,b,c,d),return)
 SDL_X11_SYM(int,XStoreColors,(Display* a,Colormap b,XColor* c,int d),(a,b,c,d),return)
+SDL_X11_SYM(int,XStoreName,(Display* a,Window b,_Xconst char* c),(a,b,c),return)
 SDL_X11_SYM(Status,XStringListToTextProperty,(char** a,int b,XTextProperty* c),(a,b,c),return)
 SDL_X11_SYM(int,XSync,(Display* a,Bool b),(a,b),return)
+SDL_X11_SYM(int,XTextExtents,(XFontStruct* a,_Xconst char* b,int c,int* d,int* e,int* f,XCharStruct* g),(a,b,c,d,e,f,g),return)
+SDL_X11_SYM(Bool,XTranslateCoordinates,(Display *a,Window b,Window c,int d,int e,int* f,int* g,Window* h),(a,b,c,d,e,f,g,h),return)
 SDL_X11_SYM(int,XUndefineCursor,(Display* a,Window b),(a,b),return)
 SDL_X11_SYM(int,XUngrabKeyboard,(Display* a,Time b),(a,b),return)
 SDL_X11_SYM(int,XUngrabPointer,(Display* a,Time b),(a,b),return)
 SDL_X11_SYM(int,XUngrabServer,(Display* a),(a),return)
 SDL_X11_SYM(int,XUninstallColormap,(Display* a,Colormap b),(a,b),return)
+SDL_X11_SYM(int,XUnloadFont,(Display* a,Font b),(a,b),return)
 SDL_X11_SYM(int,XUnmapWindow,(Display* a,Window b),(a,b),return)
 SDL_X11_SYM(int,XWarpPointer,(Display* a,Window b,Window c,int d,int e,unsigned int f,unsigned int g,int h,int i),(a,b,c,d,e,f,g,h,i),return)
+SDL_X11_SYM(int,XWindowEvent,(Display* a,Window b,long c,XEvent* d),(a,b,c,d),return)
 SDL_X11_SYM(VisualID,XVisualIDFromVisual,(Visual* a),(a),return)
 #if SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY
 SDL_X11_SYM(XExtDisplayInfo*,XextAddDisplay,(XExtensionInfo* a,Display* b,_Xconst char* c,XExtensionHooks* d,int e,XPointer f),(a,b,c,d,e,f),return)
--- a/test/common.c	Tue Oct 23 17:10:09 2012 -0700
+++ b/test/common.c	Tue Oct 23 17:11:22 2012 -0700
@@ -1204,6 +1204,12 @@
                 }
             }
             break;
+        case SDLK_1:
+            if (event->key.keysym.mod & KMOD_CTRL) {
+                SDL_Window *window = SDL_GetWindowFromID(event->key.windowID);
+                SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_INFORMATION, "Test Message", "You're awesome!", window);
+            }
+            break;
         case SDLK_ESCAPE:
             *done = 1;
             break;