src/video/x11/SDL_x11messagebox.c
changeset 6602 533131e24aeb
child 6603 fc815cb0a2de
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/video/x11/SDL_x11messagebox.c	Tue Oct 23 17:11:22 2012 -0700
     1.3 @@ -0,0 +1,642 @@
     1.4 +/*
     1.5 +  Simple DirectMedia Layer
     1.6 +  Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     1.7 +
     1.8 +  This software is provided 'as-is', without any express or implied
     1.9 +  warranty.  In no event will the authors be held liable for any damages
    1.10 +  arising from the use of this software.
    1.11 +
    1.12 +  Permission is granted to anyone to use this software for any purpose,
    1.13 +  including commercial applications, and to alter it and redistribute it
    1.14 +  freely, subject to the following restrictions:
    1.15 +
    1.16 +  1. The origin of this software must not be misrepresented; you must not
    1.17 +     claim that you wrote the original software. If you use this software
    1.18 +     in a product, an acknowledgment in the product documentation would be
    1.19 +     appreciated but is not required.
    1.20 +  2. Altered source versions must be plainly marked as such, and must not be
    1.21 +     misrepresented as being the original software.
    1.22 +  3. This notice may not be removed or altered from any source distribution.
    1.23 +*/
    1.24 +#include "SDL_config.h"
    1.25 +
    1.26 +#if SDL_VIDEO_DRIVER_X11
    1.27 +
    1.28 +#include "SDL.h"
    1.29 +#include "SDL_x11video.h"
    1.30 +#include "SDL_x11dyn.h"
    1.31 +
    1.32 +#define MAX_BUTTONS             8       /* Maximum number of buttons supported */
    1.33 +#define MAX_TEXT_LINES          32      /* Maximum number of text lines supported */
    1.34 +#define MIN_BUTTON_WIDTH        64      /* Minimum button width */
    1.35 +#define MIN_DIALOG_WIDTH        200     /* Minimum dialog width */
    1.36 +#define MIN_DIALOG_HEIGHT       100     /* Minimum dialog height */
    1.37 +
    1.38 +static const char g_MessageBoxFont[] = "-*-*-medium-r-normal--0-120-*-*-p-0-iso8859-1";
    1.39 +
    1.40 +static const SDL_MessageBoxColor g_default_colors[ SDL_MESSAGEBOX_COLOR_MAX ] =
    1.41 +{
    1.42 +	{ 56,  54,  53  }, // SDL_MESSAGEBOX_COLOR_BACKGROUND,       
    1.43 +	{ 209, 207, 205 }, // SDL_MESSAGEBOX_COLOR_TEXT,             
    1.44 +	{ 140, 135, 129 }, // SDL_MESSAGEBOX_COLOR_BUTTON_BORDER,    
    1.45 +	{ 105, 102, 99  }, // SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND,
    1.46 +	{ 205, 202, 53  }, // SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED,  
    1.47 +};
    1.48 +
    1.49 +#define SDL_MAKE_RGB( _r, _g, _b )  ( ( ( Uint32 )( _r ) << 16 ) | \
    1.50 +                                      ( ( Uint32 )( _g ) << 8 ) |  \
    1.51 +                                      ( ( Uint32 )( _b ) ) )
    1.52 +
    1.53 +typedef struct SDL_MessageBoxButtonDataX11
    1.54 +{
    1.55 +    int x, y;                           /* Text position */
    1.56 +    int length;                         /* Text length */
    1.57 +    int text_width;                     /* Text width */
    1.58 +
    1.59 +    SDL_Rect rect;                      /* Rectangle for entire button */
    1.60 +
    1.61 +    const SDL_MessageBoxButtonData *buttondata;   /* Button data from caller */
    1.62 +} SDL_MessageBoxButtonDataX11;
    1.63 +
    1.64 +typedef struct TextLineData
    1.65 +{
    1.66 +    int width;                          /* Width of this text line */
    1.67 +    int length;                         /* String length of this text line */
    1.68 +    const char *text;                   /* Text for this line */
    1.69 +} TextLineData;
    1.70 +
    1.71 +typedef struct SDL_MessageBoxDataX11
    1.72 +{
    1.73 +    Font hfont;
    1.74 +    Window window;
    1.75 +    Display *display;
    1.76 +	long event_mask;
    1.77 +    Atom wm_protocols;
    1.78 +    Atom wm_delete_message;
    1.79 +
    1.80 +    int dialog_width;                   /* Dialog box width. */
    1.81 +    int dialog_height;                  /* Dialog box height. */
    1.82 +
    1.83 +    int xtext, ytext;                   /* Text position to start drawing at. */
    1.84 +    int numlines;                       /* Count of Text lines. */
    1.85 +    int text_height;                    /* Height for text lines. */
    1.86 +    TextLineData linedata[ MAX_TEXT_LINES ];
    1.87 +
    1.88 +    int *pbuttonid;                     /* Pointer to user return buttonid value. */
    1.89 +
    1.90 +    int button_press_index;             /* Index into buttondata/buttonpos for button which is pressed (or -1). */
    1.91 +    int mouse_over_index;               /* Index into buttondata/buttonpos for button mouse is over (or -1). */
    1.92 +
    1.93 +    int numbuttons;                     /* Count of buttons. */
    1.94 +    const SDL_MessageBoxButtonData *buttondata;
    1.95 +    SDL_MessageBoxButtonDataX11 buttonpos[ MAX_BUTTONS ];
    1.96 +
    1.97 +	Uint32 color[ SDL_MESSAGEBOX_COLOR_MAX ];
    1.98 +
    1.99 +    const SDL_MessageBoxData *messageboxdata;
   1.100 +} SDL_MessageBoxDataX11;
   1.101 +
   1.102 +/* Maximum helper for ints. */
   1.103 +static __inline__ int
   1.104 +IntMax( int a, int b )
   1.105 +{
   1.106 +    return ( a > b  ) ? a : b;
   1.107 +}
   1.108 +
   1.109 +/* Return width and height for a string. */
   1.110 +static void
   1.111 +GetTextWidthHeight( XFontStruct *font_struct, const char *str, int nchars, int *pwidth, int *pheight )
   1.112 +{
   1.113 +    XCharStruct text_structure;
   1.114 +    int font_direction, font_ascent, font_descent;
   1.115 +
   1.116 +    XTextExtents( font_struct, str, nchars,
   1.117 +                     &font_direction, &font_ascent, &font_descent,
   1.118 +                     &text_structure );
   1.119 +
   1.120 +    *pwidth = text_structure.width;
   1.121 +    *pheight = text_structure.ascent + text_structure.descent;
   1.122 +}
   1.123 +
   1.124 +/* Return index of button if position x,y is contained therein. */
   1.125 +static int
   1.126 +GetHitButtonIndex( SDL_MessageBoxDataX11 *data, int x, int y )
   1.127 +{
   1.128 +    int i;
   1.129 +    int numbuttons = data->numbuttons;
   1.130 +    SDL_MessageBoxButtonDataX11 *buttonpos = data->buttonpos;
   1.131 +
   1.132 +    for ( i = 0; i < numbuttons; i++ )
   1.133 +    {
   1.134 +        SDL_Rect *rect = &buttonpos[ i ].rect;
   1.135 +
   1.136 +        if ( ( x >= rect->x ) &&
   1.137 +            ( x <= ( rect->x + rect->w ) ) &&
   1.138 +            ( y >= rect->y ) &&
   1.139 +            ( y <= ( rect->y + rect->h ) ) )
   1.140 +        {
   1.141 +            return i;
   1.142 +        }
   1.143 +    }
   1.144 +
   1.145 +    return -1;
   1.146 +}
   1.147 +
   1.148 +/* Initialize SDL_MessageBoxData structure and Display, etc. */
   1.149 +static int
   1.150 +X11_MessageBoxInit( SDL_MessageBoxDataX11 *data, const SDL_MessageBoxData * messageboxdata, int * pbuttonid )
   1.151 +{
   1.152 +	int i;
   1.153 +    int numbuttons = messageboxdata->numbuttons;
   1.154 +    const SDL_MessageBoxButtonData *buttondata = messageboxdata->buttons;
   1.155 +	const SDL_MessageBoxColor *colorhints;
   1.156 +
   1.157 +    if ( numbuttons > MAX_BUTTONS ) {
   1.158 +        SDL_SetError("Too many buttons (%d max allowed)", MAX_BUTTONS);
   1.159 +        return -1;
   1.160 +    }
   1.161 +
   1.162 +    data->dialog_width = MIN_DIALOG_WIDTH;
   1.163 +    data->dialog_height = MIN_DIALOG_HEIGHT;
   1.164 +    data->messageboxdata = messageboxdata;
   1.165 +    data->buttondata = buttondata;
   1.166 +    data->numbuttons = numbuttons;
   1.167 +    data->pbuttonid = pbuttonid;
   1.168 +
   1.169 +    data->display = XOpenDisplay( NULL );
   1.170 +    if ( !data->display ) {
   1.171 +        SDL_SetError("Couldn't open X11 display");
   1.172 +        return -1;
   1.173 +    }
   1.174 +
   1.175 +    data->hfont = XLoadFont( data->display, g_MessageBoxFont );
   1.176 +    if ( data->hfont == None ) {
   1.177 +        SDL_SetError("Couldn't load font %s", g_MessageBoxFont);
   1.178 +        return -1;
   1.179 +    }
   1.180 +
   1.181 +	if ( messageboxdata->colorScheme ) {
   1.182 +		colorhints = messageboxdata->colorScheme->colors;
   1.183 +	} else {
   1.184 +		colorhints = g_default_colors;
   1.185 +	}
   1.186 +
   1.187 +	/* Convert our SDL_MessageBoxColor r,g,b values to packed RGB format. */
   1.188 +	for ( i = 0; i < SDL_MESSAGEBOX_COLOR_MAX; i++ ) {
   1.189 +		data->color[ i ] = SDL_MAKE_RGB( colorhints[ i ].r, colorhints[ i ].g, colorhints[ i ].b );
   1.190 +	}
   1.191 +
   1.192 +    return 0;
   1.193 +}
   1.194 +
   1.195 +/* Calculate and initialize text and button locations. */
   1.196 +static int
   1.197 +X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *data )
   1.198 +{
   1.199 +    int i;
   1.200 +    int ybuttons;
   1.201 +    int text_width_max = 0;
   1.202 +    int button_text_height = 0;
   1.203 +    int button_width = MIN_BUTTON_WIDTH;
   1.204 +    const SDL_MessageBoxData *messageboxdata = data->messageboxdata;
   1.205 +
   1.206 +    XFontStruct *fontinfo = XQueryFont( data->display, data->hfont );
   1.207 +    if ( !fontinfo ) {
   1.208 +        SDL_SetError("Couldn't get font info");
   1.209 +        return -1;
   1.210 +    }
   1.211 +
   1.212 +    /* Go over text and break linefeeds into separate lines. */
   1.213 +    if ( messageboxdata->message && messageboxdata->message[ 0 ] )
   1.214 +    {
   1.215 +        const char *text = messageboxdata->message;
   1.216 +        TextLineData *plinedata = data->linedata;
   1.217 +
   1.218 +        for ( i = 0; i < MAX_TEXT_LINES; i++, plinedata++ )
   1.219 +        {
   1.220 +            int height;
   1.221 +            char *lf = SDL_strchr( ( char * )text, '\n' );
   1.222 +
   1.223 +            data->numlines++;
   1.224 +
   1.225 +            /* Only grab length up to lf if it exists and isn't the last line. */
   1.226 +            plinedata->length = ( lf && ( i < MAX_TEXT_LINES - 1 ) ) ? ( lf - text ) : SDL_strlen( text );
   1.227 +            plinedata->text = text;
   1.228 +
   1.229 +            GetTextWidthHeight( fontinfo, text, plinedata->length, &plinedata->width, &height );
   1.230 +
   1.231 +            /* Text and widths are the largest we've ever seen. */
   1.232 +            data->text_height = IntMax( data->text_height, height );
   1.233 +            text_width_max = IntMax( text_width_max, plinedata->width );
   1.234 +
   1.235 +            text += plinedata->length + 1;
   1.236 +
   1.237 +            /* Break if there are no more linefeeds. */
   1.238 +            if ( !lf )
   1.239 +                break;
   1.240 +        }
   1.241 +
   1.242 +        /* Bump up the text height slightly. */
   1.243 +        data->text_height += 2;
   1.244 +    }
   1.245 +
   1.246 +    /* Loop through all buttons and calculate the button widths and height. */
   1.247 +    for ( i = 0; i < data->numbuttons; i++ )
   1.248 +    {
   1.249 +        int height;
   1.250 +
   1.251 +        data->buttonpos[ i ].buttondata = &data->buttondata[ i ];
   1.252 +        data->buttonpos[ i ].length = SDL_strlen( data->buttondata[ i ].text );
   1.253 +
   1.254 +        GetTextWidthHeight( fontinfo, data->buttondata[ i ].text, SDL_strlen( data->buttondata[ i ].text ),
   1.255 +                            &data->buttonpos[ i ].text_width, &height );
   1.256 +
   1.257 +        button_width = IntMax( button_width, data->buttonpos[ i ].text_width );
   1.258 +        button_text_height = IntMax( button_text_height, height );
   1.259 +    }
   1.260 +
   1.261 +    if ( data->numlines )
   1.262 +    {
   1.263 +        /* x,y for this line of text. */
   1.264 +        data->xtext = data->text_height;
   1.265 +        data->ytext = data->text_height + data->text_height;
   1.266 +
   1.267 +        /* Bump button y down to bottom of text. */
   1.268 +        ybuttons = 3 * data->ytext / 2 + ( data->numlines - 1 ) * data->text_height;
   1.269 +
   1.270 +        /* Bump the dialog box width and height up if needed. */
   1.271 +        data->dialog_width = IntMax( data->dialog_width, 2 * data->xtext + text_width_max );
   1.272 +        data->dialog_height = IntMax( data->dialog_height, ybuttons );
   1.273 +    }
   1.274 +    else
   1.275 +    {
   1.276 +        /* Button y starts at height of button text. */
   1.277 +        ybuttons = button_text_height;
   1.278 +    }
   1.279 +
   1.280 +    if ( data->numbuttons )
   1.281 +    {
   1.282 +        int x, y;
   1.283 +        int width_of_buttons;
   1.284 +        int button_spacing = button_text_height;
   1.285 +        int button_height = 2 * button_text_height;
   1.286 +
   1.287 +        /* Bump button width up a bit. */
   1.288 +        button_width += button_text_height;
   1.289 +
   1.290 +        /* Get width of all buttons lined up. */
   1.291 +        width_of_buttons = data->numbuttons * button_width + ( data->numbuttons - 1 ) * button_spacing;
   1.292 +
   1.293 +        /* Bump up dialog width and height if buttons are wider than text. */
   1.294 +        data->dialog_width = IntMax( data->dialog_width, width_of_buttons + 2 * button_spacing );
   1.295 +        data->dialog_height = IntMax( data->dialog_height, ybuttons + 2 * button_height );
   1.296 +
   1.297 +        /* Location for first button. */
   1.298 +        x = ( data->dialog_width - width_of_buttons ) / 2;
   1.299 +        y = ybuttons + ( data->dialog_height - ybuttons - button_height ) / 2;
   1.300 +
   1.301 +        for ( i = 0; i < data->numbuttons; i++ )
   1.302 +        {
   1.303 +            /* Button coordinates. */
   1.304 +            data->buttonpos[ i ].rect.x = x;
   1.305 +            data->buttonpos[ i ].rect.y = y;
   1.306 +            data->buttonpos[ i ].rect.w = button_width;
   1.307 +            data->buttonpos[ i ].rect.h = button_height;
   1.308 +
   1.309 +            /* Button text coordinates. */
   1.310 +            data->buttonpos[ i ].x = x + ( button_width - data->buttonpos[ i ].text_width ) / 2;
   1.311 +            data->buttonpos[ i ].y = y + ( button_height - button_text_height - 1 ) / 2 + button_text_height;
   1.312 +
   1.313 +            /* Scoot over for next button. */
   1.314 +            x += button_width + button_text_height;
   1.315 +        }
   1.316 +    }
   1.317 +
   1.318 +    XFreeFontInfo( NULL, fontinfo, 1 );
   1.319 +    return 0;
   1.320 +}
   1.321 +
   1.322 +/* Free SDL_MessageBoxData data. */
   1.323 +static void
   1.324 +X11_MessageBoxShutdown( SDL_MessageBoxDataX11 *data )
   1.325 +{
   1.326 +    if ( data->hfont != None )
   1.327 +    {
   1.328 +        XUnloadFont( data->display, data->hfont );
   1.329 +        data->hfont = None;
   1.330 +    }
   1.331 +
   1.332 +    if ( data->display )
   1.333 +    {
   1.334 +        if ( data->window != None )
   1.335 +        {
   1.336 +            XUnmapWindow( data->display, data->window );
   1.337 +            XDestroyWindow( data->display, data->window );
   1.338 +            data->window = None;
   1.339 +        }
   1.340 +
   1.341 +        XCloseDisplay( data->display );
   1.342 +        data->display = NULL;
   1.343 +    }
   1.344 +}
   1.345 +
   1.346 +/* Create and set up our X11 dialog box indow. */
   1.347 +static int
   1.348 +X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data )
   1.349 +{
   1.350 +    int x, y;
   1.351 +    XSizeHints *sizehints;
   1.352 +    XSetWindowAttributes wnd_attr;
   1.353 +    Display *display = data->display;
   1.354 +    SDL_WindowData *windowdata = NULL;
   1.355 +    const SDL_MessageBoxData *messageboxdata = data->messageboxdata;
   1.356 +
   1.357 +    if ( messageboxdata->window ) {
   1.358 +        windowdata = (SDL_WindowData *)messageboxdata->window->driverdata;
   1.359 +    }
   1.360 +
   1.361 +    data->event_mask = ExposureMask |
   1.362 +        ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
   1.363 +        StructureNotifyMask | FocusChangeMask | PointerMotionMask;
   1.364 +	wnd_attr.event_mask = data->event_mask;
   1.365 +
   1.366 +    data->window = XCreateWindow(
   1.367 +                            display, DefaultRootWindow( display ),
   1.368 +                            0, 0,
   1.369 +                            data->dialog_width, data->dialog_height,
   1.370 +                            0, CopyFromParent, InputOutput, CopyFromParent,
   1.371 +                            CWEventMask, &wnd_attr );
   1.372 +    if ( data->window == None ) {
   1.373 +        SDL_SetError("Couldn't create X window");
   1.374 +        return -1;
   1.375 +    }
   1.376 +
   1.377 +    if ( windowdata ) {
   1.378 +        /* http://tronche.com/gui/x/icccm/sec-4.html#WM_TRANSIENT_FOR */
   1.379 +        XSetTransientForHint( display, data->window, windowdata->xwindow );
   1.380 +    }
   1.381 +
   1.382 +    XStoreName( display, data->window, messageboxdata->title );
   1.383 +
   1.384 +    /* Allow the window to be deleted by the window manager */
   1.385 +    data->wm_protocols = XInternAtom( display, "WM_PROTOCOLS", False );
   1.386 +    data->wm_delete_message = XInternAtom( display, "WM_DELETE_WINDOW", False );
   1.387 +    XSetWMProtocols( display, data->window, &data->wm_delete_message, 1 );
   1.388 +
   1.389 +    if ( windowdata ) {
   1.390 +        XWindowAttributes attrib;
   1.391 +        Window dummy;
   1.392 +
   1.393 +        XGetWindowAttributes(display, windowdata->xwindow, &attrib);
   1.394 +        x = attrib.x + ( attrib.width - data->dialog_width ) / 2;
   1.395 +        y = attrib.y + ( attrib.height - data->dialog_height ) / 3 ;
   1.396 +        XTranslateCoordinates(display, windowdata->xwindow, DefaultRootWindow( display ), x, y, &x, &y, &dummy);
   1.397 +    } else {
   1.398 +        int screen = DefaultScreen( display );
   1.399 +        x = ( DisplayWidth( display, screen ) - data->dialog_width ) / 2;
   1.400 +        y = ( DisplayHeight( display, screen ) - data->dialog_height ) / 3 ;
   1.401 +    }
   1.402 +    XMoveWindow( display, data->window, x, y );
   1.403 +
   1.404 +    sizehints = XAllocSizeHints();
   1.405 +    if ( sizehints ) {
   1.406 +        sizehints->flags = USPosition | USSize | PMaxSize | PMinSize;
   1.407 +        sizehints->x = x;
   1.408 +        sizehints->y = y;
   1.409 +        sizehints->width = data->dialog_width;
   1.410 +        sizehints->height = data->dialog_height;
   1.411 +
   1.412 +        sizehints->min_width = sizehints->max_width = data->dialog_width;
   1.413 +        sizehints->min_height = sizehints->max_height = data->dialog_height;
   1.414 +
   1.415 +        XSetWMNormalHints( display, data->window, sizehints );
   1.416 +
   1.417 +        XFree( sizehints );
   1.418 +    }
   1.419 +
   1.420 +    XMapRaised( display, data->window );
   1.421 +    return 0;
   1.422 +}
   1.423 +
   1.424 +/* Draw our message box. */
   1.425 +static void
   1.426 +X11_MessageBoxDraw( SDL_MessageBoxDataX11 *data, GC ctx )
   1.427 +{
   1.428 +    int i;
   1.429 +    Window window = data->window;
   1.430 +    Display *display = data->display;
   1.431 +
   1.432 +    XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ] );
   1.433 +    XFillRectangle( display, window, ctx, 0, 0, data->dialog_width, data->dialog_height );
   1.434 +
   1.435 +    XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_TEXT ] );
   1.436 +    for ( i = 0; i < data->numlines; i++ )
   1.437 +    {
   1.438 +        TextLineData *plinedata = &data->linedata[ i ];
   1.439 +
   1.440 +        XDrawString( display, window, ctx,
   1.441 +                     data->xtext, data->ytext + i * data->text_height,
   1.442 +                     plinedata->text, plinedata->length );
   1.443 +    }
   1.444 +
   1.445 +    for ( i = 0; i < data->numbuttons; i++ )
   1.446 +    {
   1.447 +        SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[ i ];
   1.448 +        const SDL_MessageBoxButtonData *buttondata = buttondatax11->buttondata;
   1.449 +        int border = ( buttondata->flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT ) ? 2 : 0;
   1.450 +        int offset = ( ( data->mouse_over_index == i ) && ( data->button_press_index == data->mouse_over_index ) ) ? 1 : 0;
   1.451 +
   1.452 +        XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND ] );
   1.453 +        XFillRectangle( display, window, ctx,
   1.454 +                        buttondatax11->rect.x - border, buttondatax11->rect.y - border,
   1.455 +                        buttondatax11->rect.w + 2 * border, buttondatax11->rect.h + 2 * border );
   1.456 +
   1.457 +        XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BUTTON_BORDER ] );
   1.458 +        XDrawRectangle( display, window, ctx,
   1.459 +                        buttondatax11->rect.x, buttondatax11->rect.y,
   1.460 +                        buttondatax11->rect.w, buttondatax11->rect.h );
   1.461 +
   1.462 +        XSetForeground( display, ctx, ( data->mouse_over_index == i ) ?
   1.463 +                        data->color[ SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED ] :
   1.464 +						data->color[ SDL_MESSAGEBOX_COLOR_TEXT ] );
   1.465 +        XDrawString( display, window, ctx,
   1.466 +            buttondatax11->x + offset, buttondatax11->y + offset,
   1.467 +            buttondata->text, buttondatax11->length );
   1.468 +    }
   1.469 +}
   1.470 +
   1.471 +/* Loop and handle message box event messages until something kills it. */
   1.472 +static int
   1.473 +X11_MessageBoxLoop( SDL_MessageBoxDataX11 *data )
   1.474 +{
   1.475 +    GC ctx;
   1.476 +    XGCValues ctx_vals;
   1.477 +    SDL_bool close_dialog = SDL_FALSE;
   1.478 +    SDL_bool has_focus = SDL_TRUE;
   1.479 +    KeySym last_key_pressed = XK_VoidSymbol;
   1.480 +
   1.481 +    ctx_vals.font = data->hfont;
   1.482 +    ctx_vals.foreground = data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ];
   1.483 +    ctx_vals.background = data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ];
   1.484 +
   1.485 +    ctx = XCreateGC( data->display, data->window, GCForeground | GCBackground | GCFont, &ctx_vals );
   1.486 +    if ( ctx == None ) {
   1.487 +        SDL_SetError("Couldn't create graphics context");
   1.488 +        return -1;
   1.489 +    }
   1.490 +
   1.491 +    data->button_press_index = -1;  /* Reset what button is currently depressed. */
   1.492 +    data->mouse_over_index = -1;    /* Reset what button the mouse is over. */
   1.493 +
   1.494 +    while( !close_dialog ) {
   1.495 +        XEvent e;
   1.496 +        SDL_bool draw = SDL_TRUE;
   1.497 +
   1.498 +		XWindowEvent( data->display, data->window, data->event_mask, &e );
   1.499 +
   1.500 +        /* If XFilterEvent returns True, then some input method has filtered the
   1.501 +           event, and the client should discard the event. */
   1.502 +        if ( ( e.type != Expose ) && XFilterEvent( &e, None ) )
   1.503 +            continue;
   1.504 +
   1.505 +        switch( e.type ) {
   1.506 +        case Expose:
   1.507 +            if ( e.xexpose.count > 0 ) {
   1.508 +                draw = SDL_FALSE;
   1.509 +            }
   1.510 +            break;
   1.511 +
   1.512 +        case FocusIn:
   1.513 +            /* Got focus. */
   1.514 +            has_focus = SDL_TRUE;
   1.515 +            break;
   1.516 +
   1.517 +        case FocusOut:
   1.518 +            /* lost focus. Reset button and mouse info. */
   1.519 +            has_focus = SDL_FALSE;
   1.520 +            data->button_press_index = -1;
   1.521 +            data->mouse_over_index = -1;
   1.522 +            break;
   1.523 +
   1.524 +        case MotionNotify:
   1.525 +            if ( has_focus ) {
   1.526 +                /* Mouse moved... */
   1.527 +                data->mouse_over_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
   1.528 +            }
   1.529 +            break;
   1.530 +
   1.531 +        case ClientMessage:
   1.532 +            if ( e.xclient.message_type == data->wm_protocols &&
   1.533 +                 e.xclient.format == 32 &&
   1.534 +                 e.xclient.data.l[ 0 ] == data->wm_delete_message ) {
   1.535 +                close_dialog = SDL_TRUE;
   1.536 +            }
   1.537 +            break;
   1.538 +
   1.539 +        case KeyPress:
   1.540 +            /* Store key press - we make sure in key release that we got both. */
   1.541 +            last_key_pressed = XLookupKeysym( &e.xkey, 0 );
   1.542 +            break;
   1.543 +
   1.544 +        case KeyRelease:
   1.545 +        {
   1.546 +            Uint32 mask = 0;
   1.547 +            KeySym key = XLookupKeysym( &e.xkey, 0 );
   1.548 +
   1.549 +            /* If this is a key release for something we didn't get the key down for, then bail. */
   1.550 +            if ( key != last_key_pressed )
   1.551 +                break;
   1.552 +
   1.553 +            if ( key == XK_Escape )
   1.554 +                mask = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
   1.555 +            else if ( ( key == XK_Return ) || ( key == XK_KP_Enter ) )
   1.556 +                mask = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
   1.557 +
   1.558 +            if ( mask ) {
   1.559 +                int i;
   1.560 +
   1.561 +                /* Look for first button with this mask set, and return it if found. */
   1.562 +                for ( i = 0; i < data->numbuttons; i++ ) {
   1.563 +                    SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[ i ];
   1.564 +
   1.565 +                    if ( buttondatax11->buttondata->flags & mask ) {
   1.566 +                        *data->pbuttonid = buttondatax11->buttondata->buttonid;
   1.567 +                        close_dialog = SDL_TRUE;
   1.568 +                        break;
   1.569 +                    }
   1.570 +                }
   1.571 +            }
   1.572 +            break;
   1.573 +        }
   1.574 +
   1.575 +        case ButtonPress:
   1.576 +            data->button_press_index = -1;
   1.577 +            if ( e.xbutton.button == Button1 ) {
   1.578 +                /* Find index of button they clicked on. */
   1.579 +                data->button_press_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
   1.580 +            }
   1.581 +            break;
   1.582 +
   1.583 +        case ButtonRelease:
   1.584 +            /* If button is released over the same button that was clicked down on, then return it. */
   1.585 +            if ( ( e.xbutton.button == Button1 ) && ( data->button_press_index >= 0 ) ) {
   1.586 +                int button = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
   1.587 +
   1.588 +                if ( data->button_press_index == button ) {
   1.589 +                    SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[ button ];
   1.590 +
   1.591 +                    *data->pbuttonid = buttondatax11->buttondata->buttonid;
   1.592 +                    close_dialog = SDL_TRUE;
   1.593 +                }
   1.594 +            }
   1.595 +            data->button_press_index = -1;
   1.596 +            break;
   1.597 +        }
   1.598 +
   1.599 +        if ( draw ) {
   1.600 +            /* Draw our dialog box. */
   1.601 +            X11_MessageBoxDraw( data, ctx );
   1.602 +        }
   1.603 +    }
   1.604 +
   1.605 +    XFreeGC( data->display, ctx );
   1.606 +    return 0;
   1.607 +}
   1.608 +
   1.609 +/* Display an x11 message box. */
   1.610 +int
   1.611 +X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
   1.612 +{
   1.613 +    int ret;
   1.614 +    SDL_MessageBoxDataX11 data;
   1.615 +
   1.616 +    SDL_memset( &data, 0, sizeof( data ) );
   1.617 +
   1.618 +    if ( !SDL_X11_LoadSymbols() )
   1.619 +        return -1;
   1.620 +
   1.621 +    /* This code could get called from multiple threads maybe? */
   1.622 +    XInitThreads();
   1.623 +
   1.624 +    /* Initialize the return buttonid value to -1 (for error or dialogbox closed). */
   1.625 +    *buttonid = -1;
   1.626 +
   1.627 +    /* Init and display the message box. */
   1.628 +    ret = X11_MessageBoxInit( &data, messageboxdata, buttonid );
   1.629 +    if ( ret != -1 ) {
   1.630 +        ret = X11_MessageBoxInitPositions( &data );
   1.631 +        if ( ret != -1 ) {
   1.632 +            ret = X11_MessageBoxCreateWindow( &data );
   1.633 +            if ( ret != -1 ) {
   1.634 +                ret = X11_MessageBoxLoop( &data );
   1.635 +            }
   1.636 +        }
   1.637 +    }
   1.638 +
   1.639 +    X11_MessageBoxShutdown( &data );
   1.640 +    return ret;
   1.641 +}
   1.642 +
   1.643 +#endif /* SDL_VIDEO_DRIVER_X11 */
   1.644 +
   1.645 +/* vi: set ts=4 sw=4 expandtab: */