src/video/x11/SDL_x11messagebox.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 15 Oct 2018 00:46:43 -0400
changeset 12330 cf64a70ad02a
parent 11811 5d94cb6b24d3
child 12503 806492103856
permissions -rw-r--r--
x11: Don't hardcode limit on lines of text in message boxes.

Plus other text parsing fixes.

Fixes Bugzilla #4306.
slouken@6602
     1
/*
slouken@6602
     2
  Simple DirectMedia Layer
slouken@11811
     3
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
slouken@6602
     4
slouken@6602
     5
  This software is provided 'as-is', without any express or implied
slouken@6602
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@6602
     7
  arising from the use of this software.
slouken@6602
     8
slouken@6602
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@6602
    10
  including commercial applications, and to alter it and redistribute it
slouken@6602
    11
  freely, subject to the following restrictions:
slouken@6602
    12
slouken@6602
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@6602
    14
     claim that you wrote the original software. If you use this software
slouken@6602
    15
     in a product, an acknowledgment in the product documentation would be
slouken@6602
    16
     appreciated but is not required.
slouken@6602
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@6602
    18
     misrepresented as being the original software.
slouken@6602
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@6602
    20
*/
icculus@6723
    21
icculus@8093
    22
#include "../../SDL_internal.h"
slouken@6602
    23
slouken@6602
    24
#if SDL_VIDEO_DRIVER_X11
slouken@6602
    25
slouken@6602
    26
#include "SDL.h"
slouken@6602
    27
#include "SDL_x11video.h"
slouken@6602
    28
#include "SDL_x11dyn.h"
icculus@6726
    29
#include "SDL_assert.h"
slouken@10609
    30
#include "SDL_x11messagebox.h"
slouken@6602
    31
slouken@9733
    32
#include <X11/keysym.h>
icculus@6723
    33
#include <locale.h>
icculus@6723
    34
icculus@6726
    35
icculus@9423
    36
#define SDL_FORK_MESSAGEBOX 1
icculus@9423
    37
#define SDL_SET_LOCALE      1
icculus@6726
    38
icculus@6726
    39
#if SDL_FORK_MESSAGEBOX
icculus@6726
    40
#include <sys/types.h>
icculus@6726
    41
#include <sys/wait.h>
icculus@6726
    42
#include <unistd.h>
icculus@6726
    43
#include <errno.h>
icculus@6726
    44
#endif
icculus@6726
    45
slouken@6602
    46
#define MAX_BUTTONS             8       /* Maximum number of buttons supported */
slouken@6602
    47
#define MIN_BUTTON_WIDTH        64      /* Minimum button width */
slouken@6602
    48
#define MIN_DIALOG_WIDTH        200     /* Minimum dialog width */
slouken@6602
    49
#define MIN_DIALOG_HEIGHT       100     /* Minimum dialog height */
slouken@6602
    50
icculus@6723
    51
static const char g_MessageBoxFontLatin1[] = "-*-*-medium-r-normal--0-120-*-*-p-0-iso8859-1";
rverschelde@10862
    52
static const char g_MessageBoxFont[] = "-*-*-medium-r-normal--*-120-*-*-*-*-*-*";
slouken@6602
    53
slouken@6725
    54
static const SDL_MessageBoxColor g_default_colors[ SDL_MESSAGEBOX_COLOR_MAX ] = {
icculus@6817
    55
    { 56,  54,  53  }, /* SDL_MESSAGEBOX_COLOR_BACKGROUND, */
icculus@6817
    56
    { 209, 207, 205 }, /* SDL_MESSAGEBOX_COLOR_TEXT, */
icculus@6817
    57
    { 140, 135, 129 }, /* SDL_MESSAGEBOX_COLOR_BUTTON_BORDER, */
icculus@6817
    58
    { 105, 102, 99  }, /* SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND, */
icculus@6817
    59
    { 205, 202, 53  }, /* SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED, */
slouken@6602
    60
};
slouken@6602
    61
slouken@6602
    62
#define SDL_MAKE_RGB( _r, _g, _b )  ( ( ( Uint32 )( _r ) << 16 ) | \
slouken@6602
    63
                                      ( ( Uint32 )( _g ) << 8 ) |  \
slouken@6602
    64
                                      ( ( Uint32 )( _b ) ) )
slouken@6602
    65
slouken@6725
    66
typedef struct SDL_MessageBoxButtonDataX11 {
slouken@6602
    67
    int x, y;                           /* Text position */
slouken@6602
    68
    int length;                         /* Text length */
slouken@6602
    69
    int text_width;                     /* Text width */
slouken@6602
    70
slouken@6602
    71
    SDL_Rect rect;                      /* Rectangle for entire button */
slouken@6602
    72
slouken@6602
    73
    const SDL_MessageBoxButtonData *buttondata;   /* Button data from caller */
slouken@6602
    74
} SDL_MessageBoxButtonDataX11;
slouken@6602
    75
slouken@6725
    76
typedef struct TextLineData {
slouken@6602
    77
    int width;                          /* Width of this text line */
slouken@6602
    78
    int length;                         /* String length of this text line */
slouken@6602
    79
    const char *text;                   /* Text for this line */
slouken@6602
    80
} TextLineData;
slouken@6602
    81
slouken@7522
    82
typedef struct SDL_MessageBoxDataX11
slouken@7522
    83
{
slouken@7522
    84
    Display *display;
slouken@7522
    85
    int screen;
slouken@6602
    86
    Window window;
icculus@9657
    87
#if SDL_VIDEO_DRIVER_X11_XDBE
icculus@9657
    88
    XdbeBackBuffer buf;
icculus@9657
    89
    SDL_bool xdbe;                      /* Whether Xdbe is present or not */
icculus@9657
    90
#endif
slouken@6603
    91
    long event_mask;
slouken@6602
    92
    Atom wm_protocols;
slouken@6602
    93
    Atom wm_delete_message;
slouken@6602
    94
slouken@6602
    95
    int dialog_width;                   /* Dialog box width. */
slouken@6602
    96
    int dialog_height;                  /* Dialog box height. */
slouken@6602
    97
slouken@7522
    98
    XFontSet font_set;                  /* for UTF-8 systems */
slouken@7522
    99
    XFontStruct *font_struct;           /* Latin1 (ASCII) fallback. */
slouken@6602
   100
    int xtext, ytext;                   /* Text position to start drawing at. */
slouken@6602
   101
    int numlines;                       /* Count of Text lines. */
slouken@6602
   102
    int text_height;                    /* Height for text lines. */
icculus@12330
   103
    TextLineData *linedata;
slouken@6602
   104
slouken@6602
   105
    int *pbuttonid;                     /* Pointer to user return buttonid value. */
slouken@6602
   106
slouken@6602
   107
    int button_press_index;             /* Index into buttondata/buttonpos for button which is pressed (or -1). */
slouken@6602
   108
    int mouse_over_index;               /* Index into buttondata/buttonpos for button mouse is over (or -1). */
slouken@6602
   109
slouken@6602
   110
    int numbuttons;                     /* Count of buttons. */
slouken@6602
   111
    const SDL_MessageBoxButtonData *buttondata;
slouken@6602
   112
    SDL_MessageBoxButtonDataX11 buttonpos[ MAX_BUTTONS ];
slouken@6602
   113
slouken@6603
   114
    Uint32 color[ SDL_MESSAGEBOX_COLOR_MAX ];
slouken@6602
   115
slouken@6602
   116
    const SDL_MessageBoxData *messageboxdata;
slouken@6602
   117
} SDL_MessageBoxDataX11;
slouken@6602
   118
slouken@6602
   119
/* Maximum helper for ints. */
slouken@7860
   120
static SDL_INLINE int
slouken@6602
   121
IntMax( int a, int b )
slouken@6602
   122
{
slouken@6602
   123
    return ( a > b  ) ? a : b;
slouken@6602
   124
}
slouken@6602
   125
slouken@6602
   126
/* Return width and height for a string. */
slouken@6602
   127
static void
icculus@6723
   128
GetTextWidthHeight( SDL_MessageBoxDataX11 *data, const char *str, int nbytes, int *pwidth, int *pheight )
slouken@6602
   129
{
icculus@6723
   130
    if (SDL_X11_HAVE_UTF8) {
icculus@6723
   131
        XRectangle overall_ink, overall_logical;
icculus@7827
   132
        X11_Xutf8TextExtents(data->font_set, str, nbytes, &overall_ink, &overall_logical);
icculus@6723
   133
        *pwidth = overall_logical.width;
icculus@6723
   134
        *pheight = overall_logical.height;
icculus@6723
   135
    } else {
icculus@6723
   136
        XCharStruct text_structure;
icculus@6723
   137
        int font_direction, font_ascent, font_descent;
icculus@7827
   138
        X11_XTextExtents( data->font_struct, str, nbytes,
icculus@6723
   139
                      &font_direction, &font_ascent, &font_descent,
icculus@6723
   140
                      &text_structure );
icculus@6723
   141
        *pwidth = text_structure.width;
icculus@6723
   142
        *pheight = text_structure.ascent + text_structure.descent;
icculus@6723
   143
    }
slouken@6602
   144
}
slouken@6602
   145
slouken@6602
   146
/* Return index of button if position x,y is contained therein. */
slouken@6602
   147
static int
slouken@6602
   148
GetHitButtonIndex( SDL_MessageBoxDataX11 *data, int x, int y )
slouken@6602
   149
{
slouken@6602
   150
    int i;
slouken@6602
   151
    int numbuttons = data->numbuttons;
slouken@6602
   152
    SDL_MessageBoxButtonDataX11 *buttonpos = data->buttonpos;
slouken@6602
   153
slouken@6725
   154
    for ( i = 0; i < numbuttons; i++ ) {
slouken@6602
   155
        SDL_Rect *rect = &buttonpos[ i ].rect;
slouken@6602
   156
slouken@6602
   157
        if ( ( x >= rect->x ) &&
slouken@6725
   158
             ( x <= ( rect->x + rect->w ) ) &&
slouken@6725
   159
             ( y >= rect->y ) &&
slouken@6725
   160
             ( y <= ( rect->y + rect->h ) ) ) {
slouken@6602
   161
            return i;
slouken@6602
   162
        }
slouken@6602
   163
    }
slouken@6602
   164
slouken@6602
   165
    return -1;
slouken@6602
   166
}
slouken@6602
   167
slouken@6602
   168
/* Initialize SDL_MessageBoxData structure and Display, etc. */
slouken@6602
   169
static int
slouken@6602
   170
X11_MessageBoxInit( SDL_MessageBoxDataX11 *data, const SDL_MessageBoxData * messageboxdata, int * pbuttonid )
slouken@6602
   171
{
slouken@6603
   172
    int i;
slouken@6602
   173
    int numbuttons = messageboxdata->numbuttons;
slouken@6602
   174
    const SDL_MessageBoxButtonData *buttondata = messageboxdata->buttons;
slouken@6603
   175
    const SDL_MessageBoxColor *colorhints;
slouken@6602
   176
slouken@6602
   177
    if ( numbuttons > MAX_BUTTONS ) {
icculus@7037
   178
        return SDL_SetError("Too many buttons (%d max allowed)", MAX_BUTTONS);
slouken@6602
   179
    }
slouken@6602
   180
slouken@6602
   181
    data->dialog_width = MIN_DIALOG_WIDTH;
slouken@6602
   182
    data->dialog_height = MIN_DIALOG_HEIGHT;
slouken@6602
   183
    data->messageboxdata = messageboxdata;
slouken@6602
   184
    data->buttondata = buttondata;
slouken@6602
   185
    data->numbuttons = numbuttons;
slouken@6602
   186
    data->pbuttonid = pbuttonid;
slouken@6602
   187
icculus@7827
   188
    data->display = X11_XOpenDisplay( NULL );
slouken@6602
   189
    if ( !data->display ) {
icculus@7037
   190
        return SDL_SetError("Couldn't open X11 display");
slouken@6602
   191
    }
slouken@6602
   192
icculus@6723
   193
    if (SDL_X11_HAVE_UTF8) {
icculus@6723
   194
        char **missing = NULL;
icculus@6723
   195
        int num_missing = 0;
icculus@7827
   196
        data->font_set = X11_XCreateFontSet(data->display, g_MessageBoxFont,
icculus@6723
   197
                                        &missing, &num_missing, NULL);
icculus@6723
   198
        if ( missing != NULL ) {
icculus@7827
   199
            X11_XFreeStringList(missing);
icculus@6723
   200
        }
icculus@6723
   201
        if ( data->font_set == NULL ) {
icculus@7037
   202
            return SDL_SetError("Couldn't load font %s", g_MessageBoxFont);
icculus@6723
   203
        }
icculus@6723
   204
    } else {
icculus@7827
   205
        data->font_struct = X11_XLoadQueryFont( data->display, g_MessageBoxFontLatin1 );
icculus@6723
   206
        if ( data->font_struct == NULL ) {
icculus@7037
   207
            return SDL_SetError("Couldn't load font %s", g_MessageBoxFontLatin1);
icculus@6723
   208
        }
slouken@6602
   209
    }
slouken@6602
   210
slouken@6603
   211
    if ( messageboxdata->colorScheme ) {
slouken@6603
   212
        colorhints = messageboxdata->colorScheme->colors;
slouken@6603
   213
    } else {
slouken@6603
   214
        colorhints = g_default_colors;
slouken@6603
   215
    }
slouken@6602
   216
slouken@6603
   217
    /* Convert our SDL_MessageBoxColor r,g,b values to packed RGB format. */
slouken@6603
   218
    for ( i = 0; i < SDL_MESSAGEBOX_COLOR_MAX; i++ ) {
slouken@6603
   219
        data->color[ i ] = SDL_MAKE_RGB( colorhints[ i ].r, colorhints[ i ].g, colorhints[ i ].b );
slouken@6603
   220
    }
slouken@6602
   221
slouken@6602
   222
    return 0;
slouken@6602
   223
}
slouken@6602
   224
icculus@12330
   225
static int
icculus@12330
   226
CountLinesOfText(const char *text)
icculus@12330
   227
{
icculus@12330
   228
    int retval = 0;
icculus@12330
   229
    while (text && *text) {
icculus@12330
   230
        const char *lf = SDL_strchr(text, '\n');
icculus@12330
   231
        retval++;  /* even without an endline, this counts as a line. */
icculus@12330
   232
        text = lf ? lf + 1 : NULL;
icculus@12330
   233
    }
icculus@12330
   234
    return retval;
icculus@12330
   235
}
icculus@12330
   236
slouken@6602
   237
/* Calculate and initialize text and button locations. */
slouken@6602
   238
static int
slouken@6602
   239
X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *data )
slouken@6602
   240
{
slouken@6602
   241
    int i;
slouken@6602
   242
    int ybuttons;
slouken@6602
   243
    int text_width_max = 0;
slouken@6602
   244
    int button_text_height = 0;
slouken@6602
   245
    int button_width = MIN_BUTTON_WIDTH;
slouken@6602
   246
    const SDL_MessageBoxData *messageboxdata = data->messageboxdata;
slouken@6602
   247
slouken@6602
   248
    /* Go over text and break linefeeds into separate lines. */
slouken@6725
   249
    if ( messageboxdata->message && messageboxdata->message[ 0 ] ) {
slouken@6602
   250
        const char *text = messageboxdata->message;
icculus@12330
   251
        const int linecount = CountLinesOfText(text);
icculus@12330
   252
        TextLineData *plinedata = (TextLineData *) SDL_malloc(sizeof (TextLineData) * linecount);
slouken@6602
   253
icculus@12330
   254
        if (!plinedata) {
icculus@12330
   255
            return SDL_OutOfMemory();
icculus@12330
   256
        }
icculus@12330
   257
icculus@12330
   258
        data->linedata = plinedata;
icculus@12330
   259
        data->numlines = linecount;
icculus@12330
   260
icculus@12330
   261
        for ( i = 0; i < linecount; i++, plinedata++ ) {
icculus@12330
   262
            const char *lf = SDL_strchr( text, '\n' );
icculus@12330
   263
            const int length = lf ? ( lf - text ) : SDL_strlen( text );
slouken@6602
   264
            int height;
slouken@6602
   265
slouken@6602
   266
            plinedata->text = text;
slouken@6602
   267
icculus@12330
   268
            GetTextWidthHeight( data, text, length, &plinedata->width, &height );
slouken@6602
   269
slouken@6602
   270
            /* Text and widths are the largest we've ever seen. */
slouken@6602
   271
            data->text_height = IntMax( data->text_height, height );
slouken@6602
   272
            text_width_max = IntMax( text_width_max, plinedata->width );
slouken@6602
   273
icculus@12330
   274
            plinedata->length = length;
icculus@6758
   275
            if (lf && (lf > text) && (lf[-1] == '\r')) {
icculus@6758
   276
                plinedata->length--;
icculus@6758
   277
            }
icculus@6758
   278
icculus@12330
   279
            text += length + 1;
slouken@6602
   280
slouken@6602
   281
            /* Break if there are no more linefeeds. */
slouken@6602
   282
            if ( !lf )
slouken@6602
   283
                break;
slouken@6602
   284
        }
slouken@6602
   285
slouken@6602
   286
        /* Bump up the text height slightly. */
slouken@6602
   287
        data->text_height += 2;
slouken@6602
   288
    }
slouken@6602
   289
slouken@6602
   290
    /* Loop through all buttons and calculate the button widths and height. */
slouken@6725
   291
    for ( i = 0; i < data->numbuttons; i++ ) {
slouken@6602
   292
        int height;
slouken@6602
   293
slouken@6602
   294
        data->buttonpos[ i ].buttondata = &data->buttondata[ i ];
slouken@6602
   295
        data->buttonpos[ i ].length = SDL_strlen( data->buttondata[ i ].text );
slouken@6602
   296
icculus@6723
   297
        GetTextWidthHeight( data, data->buttondata[ i ].text, SDL_strlen( data->buttondata[ i ].text ),
slouken@6602
   298
                            &data->buttonpos[ i ].text_width, &height );
slouken@6602
   299
slouken@6602
   300
        button_width = IntMax( button_width, data->buttonpos[ i ].text_width );
slouken@6602
   301
        button_text_height = IntMax( button_text_height, height );
slouken@6602
   302
    }
slouken@6602
   303
slouken@6725
   304
    if ( data->numlines ) {
slouken@6602
   305
        /* x,y for this line of text. */
slouken@6602
   306
        data->xtext = data->text_height;
slouken@6602
   307
        data->ytext = data->text_height + data->text_height;
slouken@6602
   308
slouken@6602
   309
        /* Bump button y down to bottom of text. */
slouken@6602
   310
        ybuttons = 3 * data->ytext / 2 + ( data->numlines - 1 ) * data->text_height;
slouken@6602
   311
slouken@6602
   312
        /* Bump the dialog box width and height up if needed. */
slouken@6602
   313
        data->dialog_width = IntMax( data->dialog_width, 2 * data->xtext + text_width_max );
slouken@6602
   314
        data->dialog_height = IntMax( data->dialog_height, ybuttons );
slouken@6725
   315
    } else {
slouken@6602
   316
        /* Button y starts at height of button text. */
slouken@6602
   317
        ybuttons = button_text_height;
slouken@6602
   318
    }
slouken@6602
   319
slouken@6725
   320
    if ( data->numbuttons ) {
slouken@6602
   321
        int x, y;
slouken@6602
   322
        int width_of_buttons;
slouken@6602
   323
        int button_spacing = button_text_height;
slouken@6602
   324
        int button_height = 2 * button_text_height;
slouken@6602
   325
slouken@6602
   326
        /* Bump button width up a bit. */
slouken@6602
   327
        button_width += button_text_height;
slouken@6602
   328
slouken@6602
   329
        /* Get width of all buttons lined up. */
slouken@6602
   330
        width_of_buttons = data->numbuttons * button_width + ( data->numbuttons - 1 ) * button_spacing;
slouken@6602
   331
slouken@6602
   332
        /* Bump up dialog width and height if buttons are wider than text. */
slouken@6602
   333
        data->dialog_width = IntMax( data->dialog_width, width_of_buttons + 2 * button_spacing );
slouken@6602
   334
        data->dialog_height = IntMax( data->dialog_height, ybuttons + 2 * button_height );
slouken@6602
   335
slouken@6602
   336
        /* Location for first button. */
slouken@6602
   337
        x = ( data->dialog_width - width_of_buttons ) / 2;
slouken@6602
   338
        y = ybuttons + ( data->dialog_height - ybuttons - button_height ) / 2;
slouken@6602
   339
slouken@6725
   340
        for ( i = 0; i < data->numbuttons; i++ ) {
slouken@6602
   341
            /* Button coordinates. */
slouken@6602
   342
            data->buttonpos[ i ].rect.x = x;
slouken@6602
   343
            data->buttonpos[ i ].rect.y = y;
slouken@6602
   344
            data->buttonpos[ i ].rect.w = button_width;
slouken@6602
   345
            data->buttonpos[ i ].rect.h = button_height;
slouken@6602
   346
slouken@6602
   347
            /* Button text coordinates. */
slouken@6602
   348
            data->buttonpos[ i ].x = x + ( button_width - data->buttonpos[ i ].text_width ) / 2;
slouken@6602
   349
            data->buttonpos[ i ].y = y + ( button_height - button_text_height - 1 ) / 2 + button_text_height;
slouken@6602
   350
slouken@6602
   351
            /* Scoot over for next button. */
slouken@6615
   352
            x += button_width + button_spacing;
slouken@6602
   353
        }
slouken@6602
   354
    }
slouken@6602
   355
slouken@6602
   356
    return 0;
slouken@6602
   357
}
slouken@6602
   358
slouken@6602
   359
/* Free SDL_MessageBoxData data. */
slouken@6602
   360
static void
slouken@6602
   361
X11_MessageBoxShutdown( SDL_MessageBoxDataX11 *data )
slouken@6602
   362
{
slouken@6725
   363
    if ( data->font_set != NULL ) {
icculus@7827
   364
        X11_XFreeFontSet( data->display, data->font_set );
icculus@6723
   365
        data->font_set = NULL;
icculus@6723
   366
    }
icculus@6723
   367
slouken@6725
   368
    if ( data->font_struct != NULL ) {
icculus@7827
   369
        X11_XFreeFont( data->display, data->font_struct );
icculus@6723
   370
        data->font_struct = NULL;
slouken@6602
   371
    }
slouken@6602
   372
icculus@9657
   373
#if SDL_VIDEO_DRIVER_X11_XDBE
icculus@9657
   374
    if ( SDL_X11_HAVE_XDBE && data->xdbe ) {
icculus@9657
   375
        X11_XdbeDeallocateBackBufferName(data->display, data->buf);
icculus@9657
   376
    }
icculus@9657
   377
#endif
icculus@9657
   378
slouken@6725
   379
    if ( data->display ) {
slouken@6725
   380
        if ( data->window != None ) {
icculus@7827
   381
            X11_XWithdrawWindow( data->display, data->window, data->screen );
icculus@7827
   382
            X11_XDestroyWindow( data->display, data->window );
slouken@6602
   383
            data->window = None;
slouken@6602
   384
        }
slouken@6602
   385
icculus@7827
   386
        X11_XCloseDisplay( data->display );
slouken@6602
   387
        data->display = NULL;
slouken@6602
   388
    }
icculus@12330
   389
icculus@12330
   390
    SDL_free(data->linedata);
slouken@6602
   391
}
slouken@6602
   392
slouken@6602
   393
/* Create and set up our X11 dialog box indow. */
slouken@6602
   394
static int
slouken@6602
   395
X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data )
slouken@6602
   396
{
slouken@6602
   397
    int x, y;
slouken@6602
   398
    XSizeHints *sizehints;
slouken@6602
   399
    XSetWindowAttributes wnd_attr;
icculus@11259
   400
    Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_NAME;
slouken@6602
   401
    Display *display = data->display;
slouken@6602
   402
    SDL_WindowData *windowdata = NULL;
slouken@6602
   403
    const SDL_MessageBoxData *messageboxdata = data->messageboxdata;
icculus@11259
   404
    char *title_locale = NULL;
slouken@6602
   405
slouken@6602
   406
    if ( messageboxdata->window ) {
slouken@7522
   407
        SDL_DisplayData *displaydata =
slouken@7522
   408
            (SDL_DisplayData *) SDL_GetDisplayForWindow(messageboxdata->window)->driverdata;
slouken@6602
   409
        windowdata = (SDL_WindowData *)messageboxdata->window->driverdata;
slouken@7522
   410
        data->screen = displaydata->screen;
slouken@7522
   411
    } else {
slouken@7522
   412
        data->screen = DefaultScreen( display );
slouken@6602
   413
    }
slouken@6602
   414
slouken@6602
   415
    data->event_mask = ExposureMask |
slouken@6725
   416
                       ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
slouken@6725
   417
                       StructureNotifyMask | FocusChangeMask | PointerMotionMask;
slouken@6603
   418
    wnd_attr.event_mask = data->event_mask;
slouken@6602
   419
icculus@7827
   420
    data->window = X11_XCreateWindow(
slouken@7522
   421
                       display, RootWindow(display, data->screen),
slouken@6725
   422
                       0, 0,
slouken@6725
   423
                       data->dialog_width, data->dialog_height,
slouken@6725
   424
                       0, CopyFromParent, InputOutput, CopyFromParent,
slouken@6725
   425
                       CWEventMask, &wnd_attr );
slouken@6602
   426
    if ( data->window == None ) {
icculus@7037
   427
        return SDL_SetError("Couldn't create X window");
slouken@6602
   428
    }
slouken@6602
   429
slouken@6602
   430
    if ( windowdata ) {
slouken@6602
   431
        /* http://tronche.com/gui/x/icccm/sec-4.html#WM_TRANSIENT_FOR */
icculus@7827
   432
        X11_XSetTransientForHint( display, data->window, windowdata->xwindow );
slouken@6602
   433
    }
slouken@6602
   434
icculus@7827
   435
    X11_XStoreName( display, data->window, messageboxdata->title );
jwyatt@9698
   436
    _NET_WM_NAME = X11_XInternAtom(display, "_NET_WM_NAME", False);
icculus@11259
   437
icculus@11259
   438
    title_locale = SDL_iconv_utf8_locale(messageboxdata->title);
icculus@11259
   439
    if (title_locale) {
icculus@11259
   440
        XTextProperty titleprop;
icculus@11259
   441
        Status status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop);
icculus@11259
   442
        SDL_free(title_locale);
icculus@11259
   443
        if (status) {
icculus@11260
   444
            X11_XSetTextProperty(display, data->window, &titleprop, XA_WM_NAME);
icculus@11259
   445
            X11_XFree(titleprop.value);
icculus@11259
   446
        }
icculus@11259
   447
    }
icculus@11259
   448
icculus@11259
   449
#ifdef X_HAVE_UTF8_STRING
icculus@11259
   450
    if (SDL_X11_HAVE_UTF8) {
icculus@11259
   451
        XTextProperty titleprop;
icculus@11260
   452
        Status status = X11_Xutf8TextListToTextProperty(display, (char **) &messageboxdata->title, 1,
icculus@11259
   453
                                            XUTF8StringStyle, &titleprop);
icculus@11259
   454
        if (status == Success) {
icculus@11259
   455
            X11_XSetTextProperty(display, data->window, &titleprop,
icculus@11259
   456
                                 _NET_WM_NAME);
icculus@11259
   457
            X11_XFree(titleprop.value);
icculus@11259
   458
        }
icculus@11259
   459
    }
icculus@11259
   460
#endif
slouken@6602
   461
icculus@9339
   462
    /* Let the window manager know this is a dialog box */
icculus@9339
   463
    _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
icculus@9339
   464
    _NET_WM_WINDOW_TYPE_DIALOG = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
icculus@9339
   465
    X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
icculus@9339
   466
                    PropModeReplace,
icculus@9339
   467
                    (unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1);
icculus@9339
   468
slouken@6602
   469
    /* Allow the window to be deleted by the window manager */
icculus@7827
   470
    data->wm_protocols = X11_XInternAtom( display, "WM_PROTOCOLS", False );
icculus@7827
   471
    data->wm_delete_message = X11_XInternAtom( display, "WM_DELETE_WINDOW", False );
icculus@7827
   472
    X11_XSetWMProtocols( display, data->window, &data->wm_delete_message, 1 );
slouken@6602
   473
slouken@6602
   474
    if ( windowdata ) {
slouken@6602
   475
        XWindowAttributes attrib;
slouken@6602
   476
        Window dummy;
slouken@6602
   477
icculus@7827
   478
        X11_XGetWindowAttributes(display, windowdata->xwindow, &attrib);
slouken@6602
   479
        x = attrib.x + ( attrib.width - data->dialog_width ) / 2;
slouken@6602
   480
        y = attrib.y + ( attrib.height - data->dialog_height ) / 3 ;
icculus@7827
   481
        X11_XTranslateCoordinates(display, windowdata->xwindow, RootWindow(display, data->screen), x, y, &x, &y, &dummy);
slouken@6602
   482
    } else {
icculus@9801
   483
        const SDL_VideoDevice *dev = SDL_GetVideoDevice();
icculus@9801
   484
        if ((dev) && (dev->displays) && (dev->num_displays > 0)) {
icculus@9801
   485
            const SDL_VideoDisplay *dpy = &dev->displays[0];
icculus@9801
   486
            const SDL_DisplayData *dpydata = (SDL_DisplayData *) dpy->driverdata;
icculus@9801
   487
            x = dpydata->x + (( dpy->current_mode.w - data->dialog_width ) / 2);
icculus@9801
   488
            y = dpydata->y + (( dpy->current_mode.h - data->dialog_height ) / 3);
icculus@9801
   489
        } else {   /* oh well. This will misposition on a multi-head setup. Init first next time. */
icculus@9801
   490
            x = ( DisplayWidth( display, data->screen ) - data->dialog_width ) / 2;
icculus@9801
   491
            y = ( DisplayHeight( display, data->screen ) - data->dialog_height ) / 3 ;
icculus@9801
   492
        }
slouken@6602
   493
    }
icculus@7827
   494
    X11_XMoveWindow( display, data->window, x, y );
slouken@6602
   495
icculus@7827
   496
    sizehints = X11_XAllocSizeHints();
slouken@6602
   497
    if ( sizehints ) {
slouken@6602
   498
        sizehints->flags = USPosition | USSize | PMaxSize | PMinSize;
slouken@6602
   499
        sizehints->x = x;
slouken@6602
   500
        sizehints->y = y;
slouken@6602
   501
        sizehints->width = data->dialog_width;
slouken@6602
   502
        sizehints->height = data->dialog_height;
slouken@6602
   503
slouken@6602
   504
        sizehints->min_width = sizehints->max_width = data->dialog_width;
slouken@6602
   505
        sizehints->min_height = sizehints->max_height = data->dialog_height;
slouken@6602
   506
icculus@7827
   507
        X11_XSetWMNormalHints( display, data->window, sizehints );
slouken@6602
   508
icculus@7827
   509
        X11_XFree( sizehints );
slouken@6602
   510
    }
slouken@6602
   511
icculus@7827
   512
    X11_XMapRaised( display, data->window );
icculus@9657
   513
icculus@9657
   514
#if SDL_VIDEO_DRIVER_X11_XDBE
icculus@9657
   515
    /* Initialise a back buffer for double buffering */
icculus@9657
   516
    if (SDL_X11_HAVE_XDBE) {
icculus@9657
   517
        int xdbe_major, xdbe_minor;
icculus@9657
   518
        if (X11_XdbeQueryExtension(display, &xdbe_major, &xdbe_minor) != 0) {
icculus@9657
   519
            data->xdbe = SDL_TRUE;
icculus@9657
   520
            data->buf = X11_XdbeAllocateBackBufferName(display, data->window, XdbeUndefined);
icculus@9657
   521
        } else {
icculus@9657
   522
            data->xdbe = SDL_FALSE;
icculus@9657
   523
        }
icculus@9657
   524
    }
icculus@9657
   525
#endif
icculus@9657
   526
slouken@6602
   527
    return 0;
slouken@6602
   528
}
slouken@6602
   529
slouken@6602
   530
/* Draw our message box. */
slouken@6602
   531
static void
slouken@6602
   532
X11_MessageBoxDraw( SDL_MessageBoxDataX11 *data, GC ctx )
slouken@6602
   533
{
slouken@6602
   534
    int i;
icculus@9657
   535
    Drawable window = data->window;
slouken@6602
   536
    Display *display = data->display;
slouken@6602
   537
icculus@9657
   538
#if SDL_VIDEO_DRIVER_X11_XDBE
icculus@9657
   539
    if (SDL_X11_HAVE_XDBE && data->xdbe) {
icculus@9657
   540
        window = data->buf;
icculus@9657
   541
        X11_XdbeBeginIdiom(data->display);
icculus@9657
   542
    }
icculus@9657
   543
#endif
icculus@9657
   544
icculus@7827
   545
    X11_XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ] );
icculus@7827
   546
    X11_XFillRectangle( display, window, ctx, 0, 0, data->dialog_width, data->dialog_height );
slouken@6602
   547
icculus@7827
   548
    X11_XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_TEXT ] );
slouken@6725
   549
    for ( i = 0; i < data->numlines; i++ ) {
slouken@6602
   550
        TextLineData *plinedata = &data->linedata[ i ];
slouken@6602
   551
icculus@6723
   552
        if (SDL_X11_HAVE_UTF8) {
icculus@7827
   553
            X11_Xutf8DrawString( display, window, data->font_set, ctx,
icculus@6723
   554
                             data->xtext, data->ytext + i * data->text_height,
icculus@6723
   555
                             plinedata->text, plinedata->length );
icculus@6723
   556
        } else {
icculus@7827
   557
            X11_XDrawString( display, window, ctx,
icculus@6723
   558
                         data->xtext, data->ytext + i * data->text_height,
icculus@6723
   559
                         plinedata->text, plinedata->length );
icculus@6723
   560
        }
slouken@6602
   561
    }
slouken@6602
   562
slouken@6725
   563
    for ( i = 0; i < data->numbuttons; i++ ) {
slouken@6602
   564
        SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[ i ];
slouken@6602
   565
        const SDL_MessageBoxButtonData *buttondata = buttondatax11->buttondata;
slouken@6602
   566
        int border = ( buttondata->flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT ) ? 2 : 0;
slouken@6602
   567
        int offset = ( ( data->mouse_over_index == i ) && ( data->button_press_index == data->mouse_over_index ) ) ? 1 : 0;
slouken@6602
   568
icculus@7827
   569
        X11_XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND ] );
icculus@7827
   570
        X11_XFillRectangle( display, window, ctx,
slouken@6602
   571
                        buttondatax11->rect.x - border, buttondatax11->rect.y - border,
slouken@6602
   572
                        buttondatax11->rect.w + 2 * border, buttondatax11->rect.h + 2 * border );
slouken@6602
   573
icculus@7827
   574
        X11_XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BUTTON_BORDER ] );
icculus@7827
   575
        X11_XDrawRectangle( display, window, ctx,
slouken@6602
   576
                        buttondatax11->rect.x, buttondatax11->rect.y,
slouken@6602
   577
                        buttondatax11->rect.w, buttondatax11->rect.h );
slouken@6602
   578
icculus@7827
   579
        X11_XSetForeground( display, ctx, ( data->mouse_over_index == i ) ?
slouken@6602
   580
                        data->color[ SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED ] :
slouken@6603
   581
                        data->color[ SDL_MESSAGEBOX_COLOR_TEXT ] );
icculus@6723
   582
icculus@6723
   583
        if (SDL_X11_HAVE_UTF8) {
icculus@7827
   584
            X11_Xutf8DrawString( display, window, data->font_set, ctx,
icculus@6723
   585
                             buttondatax11->x + offset,
icculus@6723
   586
                             buttondatax11->y + offset,
icculus@6723
   587
                             buttondata->text, buttondatax11->length );
icculus@6723
   588
        } else {
icculus@7827
   589
            X11_XDrawString( display, window, ctx,
icculus@6723
   590
                         buttondatax11->x + offset, buttondatax11->y + offset,
icculus@6723
   591
                         buttondata->text, buttondatax11->length );
icculus@6723
   592
        }
slouken@6602
   593
    }
icculus@9657
   594
icculus@9657
   595
#if SDL_VIDEO_DRIVER_X11_XDBE
icculus@9657
   596
    if (SDL_X11_HAVE_XDBE && data->xdbe) {
icculus@9657
   597
        XdbeSwapInfo swap_info;
icculus@9657
   598
        swap_info.swap_window = data->window;
icculus@9657
   599
        swap_info.swap_action = XdbeUndefined;
icculus@9657
   600
        X11_XdbeSwapBuffers(data->display, &swap_info, 1);
icculus@9657
   601
        X11_XdbeEndIdiom(data->display);
icculus@9657
   602
    }
icculus@9657
   603
#endif
slouken@6602
   604
}
slouken@6602
   605
icculus@9695
   606
static Bool
icculus@9695
   607
X11_MessageBoxEventTest(Display *display, XEvent *event, XPointer arg)
icculus@9695
   608
{
icculus@9695
   609
    const SDL_MessageBoxDataX11 *data = (const SDL_MessageBoxDataX11 *) arg;
icculus@9695
   610
    return ((event->xany.display == data->display) && (event->xany.window == data->window)) ? True : False;
icculus@9695
   611
}
icculus@9695
   612
slouken@6602
   613
/* Loop and handle message box event messages until something kills it. */
slouken@6602
   614
static int
slouken@6602
   615
X11_MessageBoxLoop( SDL_MessageBoxDataX11 *data )
slouken@6602
   616
{
slouken@6602
   617
    GC ctx;
slouken@6602
   618
    XGCValues ctx_vals;
slouken@6602
   619
    SDL_bool close_dialog = SDL_FALSE;
slouken@6602
   620
    SDL_bool has_focus = SDL_TRUE;
slouken@6602
   621
    KeySym last_key_pressed = XK_VoidSymbol;
icculus@6723
   622
    unsigned long gcflags = GCForeground | GCBackground;
slouken@6602
   623
icculus@6723
   624
    SDL_zero(ctx_vals);
slouken@6602
   625
    ctx_vals.foreground = data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ];
slouken@6602
   626
    ctx_vals.background = data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ];
slouken@6602
   627
icculus@6723
   628
    if (!SDL_X11_HAVE_UTF8) {
icculus@6723
   629
        gcflags |= GCFont;
icculus@6723
   630
        ctx_vals.font = data->font_struct->fid;
icculus@6723
   631
    }
icculus@6723
   632
icculus@7827
   633
    ctx = X11_XCreateGC( data->display, data->window, gcflags, &ctx_vals );
slouken@6602
   634
    if ( ctx == None ) {
icculus@7037
   635
        return SDL_SetError("Couldn't create graphics context");
slouken@6602
   636
    }
slouken@6602
   637
slouken@6602
   638
    data->button_press_index = -1;  /* Reset what button is currently depressed. */
slouken@6602
   639
    data->mouse_over_index = -1;    /* Reset what button the mouse is over. */
slouken@6602
   640
slouken@6602
   641
    while( !close_dialog ) {
slouken@6602
   642
        XEvent e;
slouken@6602
   643
        SDL_bool draw = SDL_TRUE;
slouken@6602
   644
icculus@9695
   645
        /* can't use XWindowEvent() because it can't handle ClientMessage events. */
icculus@9695
   646
        /* can't use XNextEvent() because we only want events for this window. */
icculus@9695
   647
        X11_XIfEvent( data->display, &e, X11_MessageBoxEventTest, (XPointer) data );
slouken@6602
   648
icculus@7827
   649
        /* If X11_XFilterEvent returns True, then some input method has filtered the
slouken@6602
   650
           event, and the client should discard the event. */
icculus@7827
   651
        if ( ( e.type != Expose ) && X11_XFilterEvent( &e, None ) )
slouken@6602
   652
            continue;
slouken@6602
   653
slouken@6602
   654
        switch( e.type ) {
slouken@6602
   655
        case Expose:
slouken@6602
   656
            if ( e.xexpose.count > 0 ) {
slouken@6602
   657
                draw = SDL_FALSE;
slouken@6602
   658
            }
slouken@6602
   659
            break;
slouken@6602
   660
slouken@6602
   661
        case FocusIn:
slouken@6602
   662
            /* Got focus. */
slouken@6602
   663
            has_focus = SDL_TRUE;
slouken@6602
   664
            break;
slouken@6602
   665
slouken@6602
   666
        case FocusOut:
slouken@6602
   667
            /* lost focus. Reset button and mouse info. */
slouken@6602
   668
            has_focus = SDL_FALSE;
slouken@6602
   669
            data->button_press_index = -1;
slouken@6602
   670
            data->mouse_over_index = -1;
slouken@6602
   671
            break;
slouken@6602
   672
slouken@6602
   673
        case MotionNotify:
slouken@6602
   674
            if ( has_focus ) {
slouken@6602
   675
                /* Mouse moved... */
icculus@9657
   676
                const int previndex = data->mouse_over_index;
slouken@6602
   677
                data->mouse_over_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
jorgen@8132
   678
                if (data->mouse_over_index == previndex) {
jorgen@8132
   679
                    draw = SDL_FALSE;
jorgen@8132
   680
                }
slouken@6602
   681
            }
slouken@6602
   682
            break;
slouken@6602
   683
slouken@6602
   684
        case ClientMessage:
slouken@6602
   685
            if ( e.xclient.message_type == data->wm_protocols &&
slouken@6602
   686
                 e.xclient.format == 32 &&
slouken@6602
   687
                 e.xclient.data.l[ 0 ] == data->wm_delete_message ) {
slouken@6602
   688
                close_dialog = SDL_TRUE;
slouken@6602
   689
            }
slouken@6602
   690
            break;
slouken@6602
   691
slouken@6602
   692
        case KeyPress:
slouken@6602
   693
            /* Store key press - we make sure in key release that we got both. */
icculus@7827
   694
            last_key_pressed = X11_XLookupKeysym( &e.xkey, 0 );
slouken@6602
   695
            break;
slouken@6602
   696
slouken@6725
   697
        case KeyRelease: {
slouken@6602
   698
            Uint32 mask = 0;
icculus@7827
   699
            KeySym key = X11_XLookupKeysym( &e.xkey, 0 );
slouken@6602
   700
slouken@6602
   701
            /* If this is a key release for something we didn't get the key down for, then bail. */
slouken@6602
   702
            if ( key != last_key_pressed )
slouken@6602
   703
                break;
slouken@6602
   704
slouken@6602
   705
            if ( key == XK_Escape )
slouken@6602
   706
                mask = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
slouken@6602
   707
            else if ( ( key == XK_Return ) || ( key == XK_KP_Enter ) )
slouken@6602
   708
                mask = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
slouken@6602
   709
slouken@6602
   710
            if ( mask ) {
slouken@6602
   711
                int i;
slouken@6602
   712
slouken@6602
   713
                /* Look for first button with this mask set, and return it if found. */
slouken@6602
   714
                for ( i = 0; i < data->numbuttons; i++ ) {
slouken@6602
   715
                    SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[ i ];
slouken@6602
   716
slouken@6602
   717
                    if ( buttondatax11->buttondata->flags & mask ) {
slouken@6602
   718
                        *data->pbuttonid = buttondatax11->buttondata->buttonid;
slouken@6602
   719
                        close_dialog = SDL_TRUE;
slouken@6602
   720
                        break;
slouken@6602
   721
                    }
slouken@6602
   722
                }
slouken@6602
   723
            }
slouken@6602
   724
            break;
slouken@6602
   725
        }
slouken@6602
   726
slouken@6602
   727
        case ButtonPress:
slouken@6602
   728
            data->button_press_index = -1;
slouken@6602
   729
            if ( e.xbutton.button == Button1 ) {
slouken@6602
   730
                /* Find index of button they clicked on. */
slouken@6602
   731
                data->button_press_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
slouken@6602
   732
            }
slouken@6602
   733
            break;
slouken@6602
   734
slouken@6602
   735
        case ButtonRelease:
slouken@6602
   736
            /* If button is released over the same button that was clicked down on, then return it. */
slouken@6602
   737
            if ( ( e.xbutton.button == Button1 ) && ( data->button_press_index >= 0 ) ) {
slouken@6602
   738
                int button = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
slouken@6602
   739
slouken@6602
   740
                if ( data->button_press_index == button ) {
slouken@6602
   741
                    SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[ button ];
slouken@6602
   742
slouken@6602
   743
                    *data->pbuttonid = buttondatax11->buttondata->buttonid;
slouken@6602
   744
                    close_dialog = SDL_TRUE;
slouken@6602
   745
                }
slouken@6602
   746
            }
slouken@6602
   747
            data->button_press_index = -1;
slouken@6602
   748
            break;
slouken@6602
   749
        }
slouken@6602
   750
slouken@6602
   751
        if ( draw ) {
slouken@6602
   752
            /* Draw our dialog box. */
slouken@6602
   753
            X11_MessageBoxDraw( data, ctx );
slouken@6602
   754
        }
slouken@6602
   755
    }
slouken@6602
   756
icculus@7827
   757
    X11_XFreeGC( data->display, ctx );
slouken@6602
   758
    return 0;
slouken@6602
   759
}
slouken@6602
   760
icculus@6726
   761
static int
icculus@6726
   762
X11_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonid)
slouken@6602
   763
{
slouken@6602
   764
    int ret;
slouken@6602
   765
    SDL_MessageBoxDataX11 data;
mikesart@6835
   766
#if SDL_SET_LOCALE
icculus@6724
   767
    char *origlocale;
mikesart@6835
   768
#endif
slouken@6602
   769
icculus@6723
   770
    SDL_zero(data);
icculus@6723
   771
slouken@6602
   772
    if ( !SDL_X11_LoadSymbols() )
slouken@6602
   773
        return -1;
slouken@6602
   774
mikesart@6835
   775
#if SDL_SET_LOCALE
icculus@6724
   776
    origlocale = setlocale(LC_ALL, NULL);
icculus@6724
   777
    if (origlocale != NULL) {
icculus@6724
   778
        origlocale = SDL_strdup(origlocale);
icculus@6724
   779
        if (origlocale == NULL) {
icculus@7037
   780
            return SDL_OutOfMemory();
icculus@6724
   781
        }
icculus@6724
   782
        setlocale(LC_ALL, "");
icculus@6724
   783
    }
mikesart@6835
   784
#endif
icculus@6724
   785
slouken@6602
   786
    /* This code could get called from multiple threads maybe? */
icculus@7827
   787
    X11_XInitThreads();
slouken@6602
   788
slouken@6602
   789
    /* Initialize the return buttonid value to -1 (for error or dialogbox closed). */
slouken@6602
   790
    *buttonid = -1;
slouken@6602
   791
slouken@6602
   792
    /* Init and display the message box. */
slouken@6602
   793
    ret = X11_MessageBoxInit( &data, messageboxdata, buttonid );
slouken@6602
   794
    if ( ret != -1 ) {
slouken@6602
   795
        ret = X11_MessageBoxInitPositions( &data );
slouken@6602
   796
        if ( ret != -1 ) {
slouken@6602
   797
            ret = X11_MessageBoxCreateWindow( &data );
slouken@6602
   798
            if ( ret != -1 ) {
slouken@6602
   799
                ret = X11_MessageBoxLoop( &data );
slouken@6602
   800
            }
slouken@6602
   801
        }
slouken@6602
   802
    }
slouken@6602
   803
slouken@6602
   804
    X11_MessageBoxShutdown( &data );
icculus@6724
   805
mikesart@6835
   806
#if SDL_SET_LOCALE
icculus@6724
   807
    if (origlocale) {
icculus@6724
   808
        setlocale(LC_ALL, origlocale);
icculus@6724
   809
        SDL_free(origlocale);
icculus@6724
   810
    }
mikesart@6835
   811
#endif
icculus@6724
   812
slouken@6602
   813
    return ret;
slouken@6602
   814
}
slouken@6602
   815
icculus@6726
   816
/* Display an x11 message box. */
icculus@6726
   817
int
icculus@6726
   818
X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
icculus@6726
   819
{
icculus@6726
   820
#if SDL_FORK_MESSAGEBOX
icculus@6726
   821
    /* Use a child process to protect against setlocale(). Annoying. */
icculus@6726
   822
    pid_t pid;
icculus@6726
   823
    int fds[2];
icculus@6726
   824
    int status = 0;
icculus@6726
   825
icculus@6726
   826
    if (pipe(fds) == -1) {
icculus@6726
   827
        return X11_ShowMessageBoxImpl(messageboxdata, buttonid); /* oh well. */
icculus@6726
   828
    }
icculus@6726
   829
icculus@6726
   830
    pid = fork();
icculus@6726
   831
    if (pid == -1) {  /* failed */
icculus@6726
   832
        close(fds[0]);
icculus@6726
   833
        close(fds[1]);
icculus@6726
   834
        return X11_ShowMessageBoxImpl(messageboxdata, buttonid); /* oh well. */
icculus@6726
   835
    } else if (pid == 0) {  /* we're the child */
icculus@6726
   836
        int exitcode = 0;
icculus@6726
   837
        close(fds[0]);
icculus@6726
   838
        status = X11_ShowMessageBoxImpl(messageboxdata, buttonid);
icculus@6726
   839
        if (write(fds[1], &status, sizeof (int)) != sizeof (int))
icculus@6726
   840
            exitcode = 1;
icculus@6726
   841
        else if (write(fds[1], buttonid, sizeof (int)) != sizeof (int))
icculus@6726
   842
            exitcode = 1;
icculus@6726
   843
        close(fds[1]);
icculus@6726
   844
        _exit(exitcode);  /* don't run atexit() stuff, static destructors, etc. */
icculus@6726
   845
    } else {  /* we're the parent */
icculus@6726
   846
        pid_t rc;
icculus@6726
   847
        close(fds[1]);
icculus@6726
   848
        do {
icculus@6726
   849
            rc = waitpid(pid, &status, 0);
icculus@6726
   850
        } while ((rc == -1) && (errno == EINTR));
icculus@6726
   851
icculus@6726
   852
        SDL_assert(rc == pid);  /* not sure what to do if this fails. */
icculus@6726
   853
icculus@6726
   854
        if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) {
icculus@7037
   855
            return SDL_SetError("msgbox child process failed");
icculus@6726
   856
        }
icculus@6726
   857
icculus@6726
   858
        if (read(fds[0], &status, sizeof (int)) != sizeof (int))
icculus@6726
   859
            status = -1;
icculus@6726
   860
        else if (read(fds[0], buttonid, sizeof (int)) != sizeof (int))
icculus@6726
   861
            status = -1;
icculus@6726
   862
        close(fds[0]);
icculus@6726
   863
icculus@6726
   864
        return status;
icculus@6726
   865
    }
icculus@6726
   866
#else
icculus@6726
   867
    return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
icculus@6726
   868
#endif
icculus@6726
   869
}
slouken@6602
   870
#endif /* SDL_VIDEO_DRIVER_X11 */
slouken@6602
   871
slouken@6602
   872
/* vi: set ts=4 sw=4 expandtab: */