src/video/x11/SDL_x11messagebox.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 14 Jul 2015 23:46:35 -0400
changeset 9801 752406828724
parent 9733 dd3c3024723c
child 9998 f67cf37e9cd4
permissions -rw-r--r--
X11: center parentless message boxes on the primary display if possible.

This relies on a successful SDL_Init(SDL_INIT_VIDEO) to work, since it's
silly to reproduce all the Xinerama/XRandR code in the message box parts. If
X11 is available but SDL hasn't been initialized, the message box will center
in the primary screen, which will be positioned weirdly on multi-head setups,
but this should fix the most significant common case.
slouken@6602
     1
/*
slouken@6602
     2
  Simple DirectMedia Layer
slouken@9619
     3
  Copyright (C) 1997-2015 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@6602
    30
slouken@9733
    31
#include <X11/keysym.h>
icculus@6723
    32
#include <locale.h>
icculus@6723
    33
icculus@6726
    34
icculus@9423
    35
#define SDL_FORK_MESSAGEBOX 1
icculus@9423
    36
#define SDL_SET_LOCALE      1
icculus@6726
    37
icculus@6726
    38
#if SDL_FORK_MESSAGEBOX
icculus@6726
    39
#include <sys/types.h>
icculus@6726
    40
#include <sys/wait.h>
icculus@6726
    41
#include <unistd.h>
icculus@6726
    42
#include <errno.h>
icculus@6726
    43
#endif
icculus@6726
    44
slouken@6602
    45
#define MAX_BUTTONS             8       /* Maximum number of buttons supported */
slouken@6602
    46
#define MAX_TEXT_LINES          32      /* Maximum number of text lines 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";
urkle@8103
    52
static const char g_MessageBoxFont[] = "-*-*-*-*-*-*-*-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. */
slouken@6602
   103
    TextLineData linedata[ MAX_TEXT_LINES ];
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
slouken@6602
   225
/* Calculate and initialize text and button locations. */
slouken@6602
   226
static int
slouken@6602
   227
X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *data )
slouken@6602
   228
{
slouken@6602
   229
    int i;
slouken@6602
   230
    int ybuttons;
slouken@6602
   231
    int text_width_max = 0;
slouken@6602
   232
    int button_text_height = 0;
slouken@6602
   233
    int button_width = MIN_BUTTON_WIDTH;
slouken@6602
   234
    const SDL_MessageBoxData *messageboxdata = data->messageboxdata;
slouken@6602
   235
slouken@6602
   236
    /* Go over text and break linefeeds into separate lines. */
slouken@6725
   237
    if ( messageboxdata->message && messageboxdata->message[ 0 ] ) {
slouken@6602
   238
        const char *text = messageboxdata->message;
slouken@6602
   239
        TextLineData *plinedata = data->linedata;
slouken@6602
   240
slouken@6725
   241
        for ( i = 0; i < MAX_TEXT_LINES; i++, plinedata++ ) {
slouken@6602
   242
            int height;
slouken@6602
   243
            char *lf = SDL_strchr( ( char * )text, '\n' );
slouken@6602
   244
slouken@6602
   245
            data->numlines++;
slouken@6602
   246
slouken@6602
   247
            /* Only grab length up to lf if it exists and isn't the last line. */
slouken@6602
   248
            plinedata->length = ( lf && ( i < MAX_TEXT_LINES - 1 ) ) ? ( lf - text ) : SDL_strlen( text );
slouken@6602
   249
            plinedata->text = text;
slouken@6602
   250
icculus@6723
   251
            GetTextWidthHeight( data, text, plinedata->length, &plinedata->width, &height );
slouken@6602
   252
slouken@6602
   253
            /* Text and widths are the largest we've ever seen. */
slouken@6602
   254
            data->text_height = IntMax( data->text_height, height );
slouken@6602
   255
            text_width_max = IntMax( text_width_max, plinedata->width );
slouken@6602
   256
icculus@6758
   257
            if (lf && (lf > text) && (lf[-1] == '\r')) {
icculus@6758
   258
                plinedata->length--;
icculus@6758
   259
            }
icculus@6758
   260
slouken@6602
   261
            text += plinedata->length + 1;
slouken@6602
   262
slouken@6602
   263
            /* Break if there are no more linefeeds. */
slouken@6602
   264
            if ( !lf )
slouken@6602
   265
                break;
slouken@6602
   266
        }
slouken@6602
   267
slouken@6602
   268
        /* Bump up the text height slightly. */
slouken@6602
   269
        data->text_height += 2;
slouken@6602
   270
    }
slouken@6602
   271
slouken@6602
   272
    /* Loop through all buttons and calculate the button widths and height. */
slouken@6725
   273
    for ( i = 0; i < data->numbuttons; i++ ) {
slouken@6602
   274
        int height;
slouken@6602
   275
slouken@6602
   276
        data->buttonpos[ i ].buttondata = &data->buttondata[ i ];
slouken@6602
   277
        data->buttonpos[ i ].length = SDL_strlen( data->buttondata[ i ].text );
slouken@6602
   278
icculus@6723
   279
        GetTextWidthHeight( data, data->buttondata[ i ].text, SDL_strlen( data->buttondata[ i ].text ),
slouken@6602
   280
                            &data->buttonpos[ i ].text_width, &height );
slouken@6602
   281
slouken@6602
   282
        button_width = IntMax( button_width, data->buttonpos[ i ].text_width );
slouken@6602
   283
        button_text_height = IntMax( button_text_height, height );
slouken@6602
   284
    }
slouken@6602
   285
slouken@6725
   286
    if ( data->numlines ) {
slouken@6602
   287
        /* x,y for this line of text. */
slouken@6602
   288
        data->xtext = data->text_height;
slouken@6602
   289
        data->ytext = data->text_height + data->text_height;
slouken@6602
   290
slouken@6602
   291
        /* Bump button y down to bottom of text. */
slouken@6602
   292
        ybuttons = 3 * data->ytext / 2 + ( data->numlines - 1 ) * data->text_height;
slouken@6602
   293
slouken@6602
   294
        /* Bump the dialog box width and height up if needed. */
slouken@6602
   295
        data->dialog_width = IntMax( data->dialog_width, 2 * data->xtext + text_width_max );
slouken@6602
   296
        data->dialog_height = IntMax( data->dialog_height, ybuttons );
slouken@6725
   297
    } else {
slouken@6602
   298
        /* Button y starts at height of button text. */
slouken@6602
   299
        ybuttons = button_text_height;
slouken@6602
   300
    }
slouken@6602
   301
slouken@6725
   302
    if ( data->numbuttons ) {
slouken@6602
   303
        int x, y;
slouken@6602
   304
        int width_of_buttons;
slouken@6602
   305
        int button_spacing = button_text_height;
slouken@6602
   306
        int button_height = 2 * button_text_height;
slouken@6602
   307
slouken@6602
   308
        /* Bump button width up a bit. */
slouken@6602
   309
        button_width += button_text_height;
slouken@6602
   310
slouken@6602
   311
        /* Get width of all buttons lined up. */
slouken@6602
   312
        width_of_buttons = data->numbuttons * button_width + ( data->numbuttons - 1 ) * button_spacing;
slouken@6602
   313
slouken@6602
   314
        /* Bump up dialog width and height if buttons are wider than text. */
slouken@6602
   315
        data->dialog_width = IntMax( data->dialog_width, width_of_buttons + 2 * button_spacing );
slouken@6602
   316
        data->dialog_height = IntMax( data->dialog_height, ybuttons + 2 * button_height );
slouken@6602
   317
slouken@6602
   318
        /* Location for first button. */
slouken@6602
   319
        x = ( data->dialog_width - width_of_buttons ) / 2;
slouken@6602
   320
        y = ybuttons + ( data->dialog_height - ybuttons - button_height ) / 2;
slouken@6602
   321
slouken@6725
   322
        for ( i = 0; i < data->numbuttons; i++ ) {
slouken@6602
   323
            /* Button coordinates. */
slouken@6602
   324
            data->buttonpos[ i ].rect.x = x;
slouken@6602
   325
            data->buttonpos[ i ].rect.y = y;
slouken@6602
   326
            data->buttonpos[ i ].rect.w = button_width;
slouken@6602
   327
            data->buttonpos[ i ].rect.h = button_height;
slouken@6602
   328
slouken@6602
   329
            /* Button text coordinates. */
slouken@6602
   330
            data->buttonpos[ i ].x = x + ( button_width - data->buttonpos[ i ].text_width ) / 2;
slouken@6602
   331
            data->buttonpos[ i ].y = y + ( button_height - button_text_height - 1 ) / 2 + button_text_height;
slouken@6602
   332
slouken@6602
   333
            /* Scoot over for next button. */
slouken@6615
   334
            x += button_width + button_spacing;
slouken@6602
   335
        }
slouken@6602
   336
    }
slouken@6602
   337
slouken@6602
   338
    return 0;
slouken@6602
   339
}
slouken@6602
   340
slouken@6602
   341
/* Free SDL_MessageBoxData data. */
slouken@6602
   342
static void
slouken@6602
   343
X11_MessageBoxShutdown( SDL_MessageBoxDataX11 *data )
slouken@6602
   344
{
slouken@6725
   345
    if ( data->font_set != NULL ) {
icculus@7827
   346
        X11_XFreeFontSet( data->display, data->font_set );
icculus@6723
   347
        data->font_set = NULL;
icculus@6723
   348
    }
icculus@6723
   349
slouken@6725
   350
    if ( data->font_struct != NULL ) {
icculus@7827
   351
        X11_XFreeFont( data->display, data->font_struct );
icculus@6723
   352
        data->font_struct = NULL;
slouken@6602
   353
    }
slouken@6602
   354
icculus@9657
   355
#if SDL_VIDEO_DRIVER_X11_XDBE
icculus@9657
   356
    if ( SDL_X11_HAVE_XDBE && data->xdbe ) {
icculus@9657
   357
        X11_XdbeDeallocateBackBufferName(data->display, data->buf);
icculus@9657
   358
    }
icculus@9657
   359
#endif
icculus@9657
   360
slouken@6725
   361
    if ( data->display ) {
slouken@6725
   362
        if ( data->window != None ) {
icculus@7827
   363
            X11_XWithdrawWindow( data->display, data->window, data->screen );
icculus@7827
   364
            X11_XDestroyWindow( data->display, data->window );
slouken@6602
   365
            data->window = None;
slouken@6602
   366
        }
slouken@6602
   367
icculus@7827
   368
        X11_XCloseDisplay( data->display );
slouken@6602
   369
        data->display = NULL;
slouken@6602
   370
    }
slouken@6602
   371
}
slouken@6602
   372
slouken@6602
   373
/* Create and set up our X11 dialog box indow. */
slouken@6602
   374
static int
slouken@6602
   375
X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data )
slouken@6602
   376
{
slouken@6602
   377
    int x, y;
slouken@6602
   378
    XSizeHints *sizehints;
slouken@6602
   379
    XSetWindowAttributes wnd_attr;
jwyatt@9698
   380
    Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_NAME, UTF8_STRING;
slouken@6602
   381
    Display *display = data->display;
slouken@6602
   382
    SDL_WindowData *windowdata = NULL;
slouken@6602
   383
    const SDL_MessageBoxData *messageboxdata = data->messageboxdata;
slouken@6602
   384
slouken@6602
   385
    if ( messageboxdata->window ) {
slouken@7522
   386
        SDL_DisplayData *displaydata =
slouken@7522
   387
            (SDL_DisplayData *) SDL_GetDisplayForWindow(messageboxdata->window)->driverdata;
slouken@6602
   388
        windowdata = (SDL_WindowData *)messageboxdata->window->driverdata;
slouken@7522
   389
        data->screen = displaydata->screen;
slouken@7522
   390
    } else {
slouken@7522
   391
        data->screen = DefaultScreen( display );
slouken@6602
   392
    }
slouken@6602
   393
slouken@6602
   394
    data->event_mask = ExposureMask |
slouken@6725
   395
                       ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
slouken@6725
   396
                       StructureNotifyMask | FocusChangeMask | PointerMotionMask;
slouken@6603
   397
    wnd_attr.event_mask = data->event_mask;
slouken@6602
   398
icculus@7827
   399
    data->window = X11_XCreateWindow(
slouken@7522
   400
                       display, RootWindow(display, data->screen),
slouken@6725
   401
                       0, 0,
slouken@6725
   402
                       data->dialog_width, data->dialog_height,
slouken@6725
   403
                       0, CopyFromParent, InputOutput, CopyFromParent,
slouken@6725
   404
                       CWEventMask, &wnd_attr );
slouken@6602
   405
    if ( data->window == None ) {
icculus@7037
   406
        return SDL_SetError("Couldn't create X window");
slouken@6602
   407
    }
slouken@6602
   408
slouken@6602
   409
    if ( windowdata ) {
slouken@6602
   410
        /* http://tronche.com/gui/x/icccm/sec-4.html#WM_TRANSIENT_FOR */
icculus@7827
   411
        X11_XSetTransientForHint( display, data->window, windowdata->xwindow );
slouken@6602
   412
    }
slouken@6602
   413
icculus@7827
   414
    X11_XStoreName( display, data->window, messageboxdata->title );
jwyatt@9698
   415
    _NET_WM_NAME = X11_XInternAtom(display, "_NET_WM_NAME", False);
jwyatt@9698
   416
    UTF8_STRING = X11_XInternAtom(display, "UTF8_STRING", False);
jwyatt@9698
   417
    X11_XChangeProperty(display, data->window, _NET_WM_NAME, UTF8_STRING, 8,
jwyatt@9698
   418
                    PropModeReplace, (unsigned char *) messageboxdata->title,
jwyatt@9698
   419
                    strlen(messageboxdata->title) + 1 );
slouken@6602
   420
icculus@9339
   421
    /* Let the window manager know this is a dialog box */
icculus@9339
   422
    _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
icculus@9339
   423
    _NET_WM_WINDOW_TYPE_DIALOG = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
icculus@9339
   424
    X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
icculus@9339
   425
                    PropModeReplace,
icculus@9339
   426
                    (unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1);
icculus@9339
   427
slouken@6602
   428
    /* Allow the window to be deleted by the window manager */
icculus@7827
   429
    data->wm_protocols = X11_XInternAtom( display, "WM_PROTOCOLS", False );
icculus@7827
   430
    data->wm_delete_message = X11_XInternAtom( display, "WM_DELETE_WINDOW", False );
icculus@7827
   431
    X11_XSetWMProtocols( display, data->window, &data->wm_delete_message, 1 );
slouken@6602
   432
slouken@6602
   433
    if ( windowdata ) {
slouken@6602
   434
        XWindowAttributes attrib;
slouken@6602
   435
        Window dummy;
slouken@6602
   436
icculus@7827
   437
        X11_XGetWindowAttributes(display, windowdata->xwindow, &attrib);
slouken@6602
   438
        x = attrib.x + ( attrib.width - data->dialog_width ) / 2;
slouken@6602
   439
        y = attrib.y + ( attrib.height - data->dialog_height ) / 3 ;
icculus@7827
   440
        X11_XTranslateCoordinates(display, windowdata->xwindow, RootWindow(display, data->screen), x, y, &x, &y, &dummy);
slouken@6602
   441
    } else {
icculus@9801
   442
        const SDL_VideoDevice *dev = SDL_GetVideoDevice();
icculus@9801
   443
        if ((dev) && (dev->displays) && (dev->num_displays > 0)) {
icculus@9801
   444
            const SDL_VideoDisplay *dpy = &dev->displays[0];
icculus@9801
   445
            const SDL_DisplayData *dpydata = (SDL_DisplayData *) dpy->driverdata;
icculus@9801
   446
            x = dpydata->x + (( dpy->current_mode.w - data->dialog_width ) / 2);
icculus@9801
   447
            y = dpydata->y + (( dpy->current_mode.h - data->dialog_height ) / 3);
icculus@9801
   448
        } else {   /* oh well. This will misposition on a multi-head setup. Init first next time. */
icculus@9801
   449
            x = ( DisplayWidth( display, data->screen ) - data->dialog_width ) / 2;
icculus@9801
   450
            y = ( DisplayHeight( display, data->screen ) - data->dialog_height ) / 3 ;
icculus@9801
   451
        }
slouken@6602
   452
    }
icculus@7827
   453
    X11_XMoveWindow( display, data->window, x, y );
slouken@6602
   454
icculus@7827
   455
    sizehints = X11_XAllocSizeHints();
slouken@6602
   456
    if ( sizehints ) {
slouken@6602
   457
        sizehints->flags = USPosition | USSize | PMaxSize | PMinSize;
slouken@6602
   458
        sizehints->x = x;
slouken@6602
   459
        sizehints->y = y;
slouken@6602
   460
        sizehints->width = data->dialog_width;
slouken@6602
   461
        sizehints->height = data->dialog_height;
slouken@6602
   462
slouken@6602
   463
        sizehints->min_width = sizehints->max_width = data->dialog_width;
slouken@6602
   464
        sizehints->min_height = sizehints->max_height = data->dialog_height;
slouken@6602
   465
icculus@7827
   466
        X11_XSetWMNormalHints( display, data->window, sizehints );
slouken@6602
   467
icculus@7827
   468
        X11_XFree( sizehints );
slouken@6602
   469
    }
slouken@6602
   470
icculus@7827
   471
    X11_XMapRaised( display, data->window );
icculus@9657
   472
icculus@9657
   473
#if SDL_VIDEO_DRIVER_X11_XDBE
icculus@9657
   474
    /* Initialise a back buffer for double buffering */
icculus@9657
   475
    if (SDL_X11_HAVE_XDBE) {
icculus@9657
   476
        int xdbe_major, xdbe_minor;
icculus@9657
   477
        if (X11_XdbeQueryExtension(display, &xdbe_major, &xdbe_minor) != 0) {
icculus@9657
   478
            data->xdbe = SDL_TRUE;
icculus@9657
   479
            data->buf = X11_XdbeAllocateBackBufferName(display, data->window, XdbeUndefined);
icculus@9657
   480
        } else {
icculus@9657
   481
            data->xdbe = SDL_FALSE;
icculus@9657
   482
        }
icculus@9657
   483
    }
icculus@9657
   484
#endif
icculus@9657
   485
slouken@6602
   486
    return 0;
slouken@6602
   487
}
slouken@6602
   488
slouken@6602
   489
/* Draw our message box. */
slouken@6602
   490
static void
slouken@6602
   491
X11_MessageBoxDraw( SDL_MessageBoxDataX11 *data, GC ctx )
slouken@6602
   492
{
slouken@6602
   493
    int i;
icculus@9657
   494
    Drawable window = data->window;
slouken@6602
   495
    Display *display = data->display;
slouken@6602
   496
icculus@9657
   497
#if SDL_VIDEO_DRIVER_X11_XDBE
icculus@9657
   498
    if (SDL_X11_HAVE_XDBE && data->xdbe) {
icculus@9657
   499
        window = data->buf;
icculus@9657
   500
        X11_XdbeBeginIdiom(data->display);
icculus@9657
   501
    }
icculus@9657
   502
#endif
icculus@9657
   503
icculus@7827
   504
    X11_XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ] );
icculus@7827
   505
    X11_XFillRectangle( display, window, ctx, 0, 0, data->dialog_width, data->dialog_height );
slouken@6602
   506
icculus@7827
   507
    X11_XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_TEXT ] );
slouken@6725
   508
    for ( i = 0; i < data->numlines; i++ ) {
slouken@6602
   509
        TextLineData *plinedata = &data->linedata[ i ];
slouken@6602
   510
icculus@6723
   511
        if (SDL_X11_HAVE_UTF8) {
icculus@7827
   512
            X11_Xutf8DrawString( display, window, data->font_set, ctx,
icculus@6723
   513
                             data->xtext, data->ytext + i * data->text_height,
icculus@6723
   514
                             plinedata->text, plinedata->length );
icculus@6723
   515
        } else {
icculus@7827
   516
            X11_XDrawString( display, window, ctx,
icculus@6723
   517
                         data->xtext, data->ytext + i * data->text_height,
icculus@6723
   518
                         plinedata->text, plinedata->length );
icculus@6723
   519
        }
slouken@6602
   520
    }
slouken@6602
   521
slouken@6725
   522
    for ( i = 0; i < data->numbuttons; i++ ) {
slouken@6602
   523
        SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[ i ];
slouken@6602
   524
        const SDL_MessageBoxButtonData *buttondata = buttondatax11->buttondata;
slouken@6602
   525
        int border = ( buttondata->flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT ) ? 2 : 0;
slouken@6602
   526
        int offset = ( ( data->mouse_over_index == i ) && ( data->button_press_index == data->mouse_over_index ) ) ? 1 : 0;
slouken@6602
   527
icculus@7827
   528
        X11_XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND ] );
icculus@7827
   529
        X11_XFillRectangle( display, window, ctx,
slouken@6602
   530
                        buttondatax11->rect.x - border, buttondatax11->rect.y - border,
slouken@6602
   531
                        buttondatax11->rect.w + 2 * border, buttondatax11->rect.h + 2 * border );
slouken@6602
   532
icculus@7827
   533
        X11_XSetForeground( display, ctx, data->color[ SDL_MESSAGEBOX_COLOR_BUTTON_BORDER ] );
icculus@7827
   534
        X11_XDrawRectangle( display, window, ctx,
slouken@6602
   535
                        buttondatax11->rect.x, buttondatax11->rect.y,
slouken@6602
   536
                        buttondatax11->rect.w, buttondatax11->rect.h );
slouken@6602
   537
icculus@7827
   538
        X11_XSetForeground( display, ctx, ( data->mouse_over_index == i ) ?
slouken@6602
   539
                        data->color[ SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED ] :
slouken@6603
   540
                        data->color[ SDL_MESSAGEBOX_COLOR_TEXT ] );
icculus@6723
   541
icculus@6723
   542
        if (SDL_X11_HAVE_UTF8) {
icculus@7827
   543
            X11_Xutf8DrawString( display, window, data->font_set, ctx,
icculus@6723
   544
                             buttondatax11->x + offset,
icculus@6723
   545
                             buttondatax11->y + offset,
icculus@6723
   546
                             buttondata->text, buttondatax11->length );
icculus@6723
   547
        } else {
icculus@7827
   548
            X11_XDrawString( display, window, ctx,
icculus@6723
   549
                         buttondatax11->x + offset, buttondatax11->y + offset,
icculus@6723
   550
                         buttondata->text, buttondatax11->length );
icculus@6723
   551
        }
slouken@6602
   552
    }
icculus@9657
   553
icculus@9657
   554
#if SDL_VIDEO_DRIVER_X11_XDBE
icculus@9657
   555
    if (SDL_X11_HAVE_XDBE && data->xdbe) {
icculus@9657
   556
        XdbeSwapInfo swap_info;
icculus@9657
   557
        swap_info.swap_window = data->window;
icculus@9657
   558
        swap_info.swap_action = XdbeUndefined;
icculus@9657
   559
        X11_XdbeSwapBuffers(data->display, &swap_info, 1);
icculus@9657
   560
        X11_XdbeEndIdiom(data->display);
icculus@9657
   561
    }
icculus@9657
   562
#endif
slouken@6602
   563
}
slouken@6602
   564
icculus@9695
   565
static Bool
icculus@9695
   566
X11_MessageBoxEventTest(Display *display, XEvent *event, XPointer arg)
icculus@9695
   567
{
icculus@9695
   568
    const SDL_MessageBoxDataX11 *data = (const SDL_MessageBoxDataX11 *) arg;
icculus@9695
   569
    return ((event->xany.display == data->display) && (event->xany.window == data->window)) ? True : False;
icculus@9695
   570
}
icculus@9695
   571
slouken@6602
   572
/* Loop and handle message box event messages until something kills it. */
slouken@6602
   573
static int
slouken@6602
   574
X11_MessageBoxLoop( SDL_MessageBoxDataX11 *data )
slouken@6602
   575
{
slouken@6602
   576
    GC ctx;
slouken@6602
   577
    XGCValues ctx_vals;
slouken@6602
   578
    SDL_bool close_dialog = SDL_FALSE;
slouken@6602
   579
    SDL_bool has_focus = SDL_TRUE;
slouken@6602
   580
    KeySym last_key_pressed = XK_VoidSymbol;
icculus@6723
   581
    unsigned long gcflags = GCForeground | GCBackground;
slouken@6602
   582
icculus@6723
   583
    SDL_zero(ctx_vals);
slouken@6602
   584
    ctx_vals.foreground = data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ];
slouken@6602
   585
    ctx_vals.background = data->color[ SDL_MESSAGEBOX_COLOR_BACKGROUND ];
slouken@6602
   586
icculus@6723
   587
    if (!SDL_X11_HAVE_UTF8) {
icculus@6723
   588
        gcflags |= GCFont;
icculus@6723
   589
        ctx_vals.font = data->font_struct->fid;
icculus@6723
   590
    }
icculus@6723
   591
icculus@7827
   592
    ctx = X11_XCreateGC( data->display, data->window, gcflags, &ctx_vals );
slouken@6602
   593
    if ( ctx == None ) {
icculus@7037
   594
        return SDL_SetError("Couldn't create graphics context");
slouken@6602
   595
    }
slouken@6602
   596
slouken@6602
   597
    data->button_press_index = -1;  /* Reset what button is currently depressed. */
slouken@6602
   598
    data->mouse_over_index = -1;    /* Reset what button the mouse is over. */
slouken@6602
   599
slouken@6602
   600
    while( !close_dialog ) {
slouken@6602
   601
        XEvent e;
slouken@6602
   602
        SDL_bool draw = SDL_TRUE;
slouken@6602
   603
icculus@9695
   604
        /* can't use XWindowEvent() because it can't handle ClientMessage events. */
icculus@9695
   605
        /* can't use XNextEvent() because we only want events for this window. */
icculus@9695
   606
        X11_XIfEvent( data->display, &e, X11_MessageBoxEventTest, (XPointer) data );
slouken@6602
   607
icculus@7827
   608
        /* If X11_XFilterEvent returns True, then some input method has filtered the
slouken@6602
   609
           event, and the client should discard the event. */
icculus@7827
   610
        if ( ( e.type != Expose ) && X11_XFilterEvent( &e, None ) )
slouken@6602
   611
            continue;
slouken@6602
   612
slouken@6602
   613
        switch( e.type ) {
slouken@6602
   614
        case Expose:
slouken@6602
   615
            if ( e.xexpose.count > 0 ) {
slouken@6602
   616
                draw = SDL_FALSE;
slouken@6602
   617
            }
slouken@6602
   618
            break;
slouken@6602
   619
slouken@6602
   620
        case FocusIn:
slouken@6602
   621
            /* Got focus. */
slouken@6602
   622
            has_focus = SDL_TRUE;
slouken@6602
   623
            break;
slouken@6602
   624
slouken@6602
   625
        case FocusOut:
slouken@6602
   626
            /* lost focus. Reset button and mouse info. */
slouken@6602
   627
            has_focus = SDL_FALSE;
slouken@6602
   628
            data->button_press_index = -1;
slouken@6602
   629
            data->mouse_over_index = -1;
slouken@6602
   630
            break;
slouken@6602
   631
slouken@6602
   632
        case MotionNotify:
slouken@6602
   633
            if ( has_focus ) {
slouken@6602
   634
                /* Mouse moved... */
icculus@9657
   635
                const int previndex = data->mouse_over_index;
slouken@6602
   636
                data->mouse_over_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
jorgen@8132
   637
                if (data->mouse_over_index == previndex) {
jorgen@8132
   638
                    draw = SDL_FALSE;
jorgen@8132
   639
                }
slouken@6602
   640
            }
slouken@6602
   641
            break;
slouken@6602
   642
slouken@6602
   643
        case ClientMessage:
slouken@6602
   644
            if ( e.xclient.message_type == data->wm_protocols &&
slouken@6602
   645
                 e.xclient.format == 32 &&
slouken@6602
   646
                 e.xclient.data.l[ 0 ] == data->wm_delete_message ) {
slouken@6602
   647
                close_dialog = SDL_TRUE;
slouken@6602
   648
            }
slouken@6602
   649
            break;
slouken@6602
   650
slouken@6602
   651
        case KeyPress:
slouken@6602
   652
            /* Store key press - we make sure in key release that we got both. */
icculus@7827
   653
            last_key_pressed = X11_XLookupKeysym( &e.xkey, 0 );
slouken@6602
   654
            break;
slouken@6602
   655
slouken@6725
   656
        case KeyRelease: {
slouken@6602
   657
            Uint32 mask = 0;
icculus@7827
   658
            KeySym key = X11_XLookupKeysym( &e.xkey, 0 );
slouken@6602
   659
slouken@6602
   660
            /* If this is a key release for something we didn't get the key down for, then bail. */
slouken@6602
   661
            if ( key != last_key_pressed )
slouken@6602
   662
                break;
slouken@6602
   663
slouken@6602
   664
            if ( key == XK_Escape )
slouken@6602
   665
                mask = SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT;
slouken@6602
   666
            else if ( ( key == XK_Return ) || ( key == XK_KP_Enter ) )
slouken@6602
   667
                mask = SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT;
slouken@6602
   668
slouken@6602
   669
            if ( mask ) {
slouken@6602
   670
                int i;
slouken@6602
   671
slouken@6602
   672
                /* Look for first button with this mask set, and return it if found. */
slouken@6602
   673
                for ( i = 0; i < data->numbuttons; i++ ) {
slouken@6602
   674
                    SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[ i ];
slouken@6602
   675
slouken@6602
   676
                    if ( buttondatax11->buttondata->flags & mask ) {
slouken@6602
   677
                        *data->pbuttonid = buttondatax11->buttondata->buttonid;
slouken@6602
   678
                        close_dialog = SDL_TRUE;
slouken@6602
   679
                        break;
slouken@6602
   680
                    }
slouken@6602
   681
                }
slouken@6602
   682
            }
slouken@6602
   683
            break;
slouken@6602
   684
        }
slouken@6602
   685
slouken@6602
   686
        case ButtonPress:
slouken@6602
   687
            data->button_press_index = -1;
slouken@6602
   688
            if ( e.xbutton.button == Button1 ) {
slouken@6602
   689
                /* Find index of button they clicked on. */
slouken@6602
   690
                data->button_press_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
slouken@6602
   691
            }
slouken@6602
   692
            break;
slouken@6602
   693
slouken@6602
   694
        case ButtonRelease:
slouken@6602
   695
            /* If button is released over the same button that was clicked down on, then return it. */
slouken@6602
   696
            if ( ( e.xbutton.button == Button1 ) && ( data->button_press_index >= 0 ) ) {
slouken@6602
   697
                int button = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
slouken@6602
   698
slouken@6602
   699
                if ( data->button_press_index == button ) {
slouken@6602
   700
                    SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[ button ];
slouken@6602
   701
slouken@6602
   702
                    *data->pbuttonid = buttondatax11->buttondata->buttonid;
slouken@6602
   703
                    close_dialog = SDL_TRUE;
slouken@6602
   704
                }
slouken@6602
   705
            }
slouken@6602
   706
            data->button_press_index = -1;
slouken@6602
   707
            break;
slouken@6602
   708
        }
slouken@6602
   709
slouken@6602
   710
        if ( draw ) {
slouken@6602
   711
            /* Draw our dialog box. */
slouken@6602
   712
            X11_MessageBoxDraw( data, ctx );
slouken@6602
   713
        }
slouken@6602
   714
    }
slouken@6602
   715
icculus@7827
   716
    X11_XFreeGC( data->display, ctx );
slouken@6602
   717
    return 0;
slouken@6602
   718
}
slouken@6602
   719
icculus@6726
   720
static int
icculus@6726
   721
X11_ShowMessageBoxImpl(const SDL_MessageBoxData *messageboxdata, int *buttonid)
slouken@6602
   722
{
slouken@6602
   723
    int ret;
slouken@6602
   724
    SDL_MessageBoxDataX11 data;
mikesart@6835
   725
#if SDL_SET_LOCALE
icculus@6724
   726
    char *origlocale;
mikesart@6835
   727
#endif
slouken@6602
   728
icculus@6723
   729
    SDL_zero(data);
icculus@6723
   730
slouken@6602
   731
    if ( !SDL_X11_LoadSymbols() )
slouken@6602
   732
        return -1;
slouken@6602
   733
mikesart@6835
   734
#if SDL_SET_LOCALE
icculus@6724
   735
    origlocale = setlocale(LC_ALL, NULL);
icculus@6724
   736
    if (origlocale != NULL) {
icculus@6724
   737
        origlocale = SDL_strdup(origlocale);
icculus@6724
   738
        if (origlocale == NULL) {
icculus@7037
   739
            return SDL_OutOfMemory();
icculus@6724
   740
        }
icculus@6724
   741
        setlocale(LC_ALL, "");
icculus@6724
   742
    }
mikesart@6835
   743
#endif
icculus@6724
   744
slouken@6602
   745
    /* This code could get called from multiple threads maybe? */
icculus@7827
   746
    X11_XInitThreads();
slouken@6602
   747
slouken@6602
   748
    /* Initialize the return buttonid value to -1 (for error or dialogbox closed). */
slouken@6602
   749
    *buttonid = -1;
slouken@6602
   750
slouken@6602
   751
    /* Init and display the message box. */
slouken@6602
   752
    ret = X11_MessageBoxInit( &data, messageboxdata, buttonid );
slouken@6602
   753
    if ( ret != -1 ) {
slouken@6602
   754
        ret = X11_MessageBoxInitPositions( &data );
slouken@6602
   755
        if ( ret != -1 ) {
slouken@6602
   756
            ret = X11_MessageBoxCreateWindow( &data );
slouken@6602
   757
            if ( ret != -1 ) {
slouken@6602
   758
                ret = X11_MessageBoxLoop( &data );
slouken@6602
   759
            }
slouken@6602
   760
        }
slouken@6602
   761
    }
slouken@6602
   762
slouken@6602
   763
    X11_MessageBoxShutdown( &data );
icculus@6724
   764
mikesart@6835
   765
#if SDL_SET_LOCALE
icculus@6724
   766
    if (origlocale) {
icculus@6724
   767
        setlocale(LC_ALL, origlocale);
icculus@6724
   768
        SDL_free(origlocale);
icculus@6724
   769
    }
mikesart@6835
   770
#endif
icculus@6724
   771
slouken@6602
   772
    return ret;
slouken@6602
   773
}
slouken@6602
   774
icculus@6726
   775
/* Display an x11 message box. */
icculus@6726
   776
int
icculus@6726
   777
X11_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
icculus@6726
   778
{
icculus@6726
   779
#if SDL_FORK_MESSAGEBOX
icculus@6726
   780
    /* Use a child process to protect against setlocale(). Annoying. */
icculus@6726
   781
    pid_t pid;
icculus@6726
   782
    int fds[2];
icculus@6726
   783
    int status = 0;
icculus@6726
   784
icculus@6726
   785
    if (pipe(fds) == -1) {
icculus@6726
   786
        return X11_ShowMessageBoxImpl(messageboxdata, buttonid); /* oh well. */
icculus@6726
   787
    }
icculus@6726
   788
icculus@6726
   789
    pid = fork();
icculus@6726
   790
    if (pid == -1) {  /* failed */
icculus@6726
   791
        close(fds[0]);
icculus@6726
   792
        close(fds[1]);
icculus@6726
   793
        return X11_ShowMessageBoxImpl(messageboxdata, buttonid); /* oh well. */
icculus@6726
   794
    } else if (pid == 0) {  /* we're the child */
icculus@6726
   795
        int exitcode = 0;
icculus@6726
   796
        close(fds[0]);
icculus@6726
   797
        status = X11_ShowMessageBoxImpl(messageboxdata, buttonid);
icculus@6726
   798
        if (write(fds[1], &status, sizeof (int)) != sizeof (int))
icculus@6726
   799
            exitcode = 1;
icculus@6726
   800
        else if (write(fds[1], buttonid, sizeof (int)) != sizeof (int))
icculus@6726
   801
            exitcode = 1;
icculus@6726
   802
        close(fds[1]);
icculus@6726
   803
        _exit(exitcode);  /* don't run atexit() stuff, static destructors, etc. */
icculus@6726
   804
    } else {  /* we're the parent */
icculus@6726
   805
        pid_t rc;
icculus@6726
   806
        close(fds[1]);
icculus@6726
   807
        do {
icculus@6726
   808
            rc = waitpid(pid, &status, 0);
icculus@6726
   809
        } while ((rc == -1) && (errno == EINTR));
icculus@6726
   810
icculus@6726
   811
        SDL_assert(rc == pid);  /* not sure what to do if this fails. */
icculus@6726
   812
icculus@6726
   813
        if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) {
icculus@7037
   814
            return SDL_SetError("msgbox child process failed");
icculus@6726
   815
        }
icculus@6726
   816
icculus@6726
   817
        if (read(fds[0], &status, sizeof (int)) != sizeof (int))
icculus@6726
   818
            status = -1;
icculus@6726
   819
        else if (read(fds[0], buttonid, sizeof (int)) != sizeof (int))
icculus@6726
   820
            status = -1;
icculus@6726
   821
        close(fds[0]);
icculus@6726
   822
icculus@6726
   823
        return status;
icculus@6726
   824
    }
icculus@6726
   825
#else
icculus@6726
   826
    return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
icculus@6726
   827
#endif
icculus@6726
   828
}
slouken@6602
   829
#endif /* SDL_VIDEO_DRIVER_X11 */
slouken@6602
   830
slouken@6602
   831
/* vi: set ts=4 sw=4 expandtab: */