src/video/windows/SDL_windowsmessagebox.c
author Alex Szpakowski <slime73@gmail.com>
Sat, 10 Nov 2018 16:15:48 -0400
changeset 12404 eb60e952b13f
parent 12042 23bc0cb86dc6
child 12503 806492103856
permissions -rw-r--r--
Add SDL_TouchDeviceType enum and SDL_GetTouchDeviceType(SDL_TouchID id).

Touch device types include SDL_TOUCH_DEVICE_DIRECT (a touch screen with window-relative coordinates for touches), SDL_TOUCH_DEVICE_INDIRECT_ABSOLUTE (a trackpad-style device with absolute device coordinates), and SDL_TOUCH_DEVICE_INDIRECT_RELATIVE (a trackpad-style device with screen cursor-relative coordinates).

Phone screens are an example of a direct device type. Mac trackpads are the indirect-absolute touch device type. The Apple TV remote is an indirect-relative touch device type.
slouken@6620
     1
/*
slouken@6620
     2
  Simple DirectMedia Layer
slouken@11811
     3
  Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
slouken@6620
     4
slouken@6620
     5
  This software is provided 'as-is', without any express or implied
slouken@6620
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@6620
     7
  arising from the use of this software.
slouken@6620
     8
slouken@6620
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@6620
    10
  including commercial applications, and to alter it and redistribute it
slouken@6620
    11
  freely, subject to the following restrictions:
slouken@6620
    12
slouken@6620
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@6620
    14
     claim that you wrote the original software. If you use this software
slouken@6620
    15
     in a product, an acknowledgment in the product documentation would be
slouken@6620
    16
     appreciated but is not required.
slouken@6620
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@6620
    18
     misrepresented as being the original software.
slouken@6620
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@6620
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@6620
    22
slouken@6620
    23
#if SDL_VIDEO_DRIVER_WINDOWS
slouken@6620
    24
slouken@11937
    25
#ifdef HAVE_LIMITS_H
slouken@11937
    26
#include <limits.h>
slouken@11937
    27
#else
slouken@11937
    28
#ifndef SIZE_MAX
slouken@11937
    29
#define SIZE_MAX ((size_t)-1)
slouken@11937
    30
#endif
slouken@11937
    31
#endif
slouken@11937
    32
slouken@7828
    33
#include "../../core/windows/SDL_windows.h"
slouken@7828
    34
slouken@7828
    35
#include "SDL_assert.h"
slouken@6620
    36
#include "SDL_windowsvideo.h"
icculus@11917
    37
#include "SDL_windowstaskdialog.h"
slouken@6620
    38
slouken@7030
    39
#ifndef SS_EDITCONTROL
slouken@7030
    40
#define SS_EDITCONTROL  0x2000
slouken@7030
    41
#endif
slouken@7030
    42
slouken@11937
    43
#ifndef IDOK
slouken@11937
    44
#define IDOK 1
slouken@11937
    45
#endif
slouken@11937
    46
slouken@11937
    47
#ifndef IDCANCEL
slouken@11937
    48
#define IDCANCEL 2
slouken@11937
    49
#endif
slouken@11937
    50
slouken@11937
    51
/* Custom dialog return codes */
slouken@11937
    52
#define IDCLOSED 20
slouken@11937
    53
#define IDINVALPTRINIT 50
slouken@11937
    54
#define IDINVALPTRCOMMAND 51
slouken@11937
    55
#define IDINVALPTRSETFOCUS 52
slouken@11937
    56
#define IDINVALPTRDLGITEM 53
slouken@11937
    57
/* First button ID */
slouken@11937
    58
#define IDBUTTONINDEX0 100
slouken@11937
    59
slouken@11937
    60
#define DLGITEMTYPEBUTTON 0x0080
slouken@11937
    61
#define DLGITEMTYPESTATIC 0x0082
slouken@11937
    62
slouken@11937
    63
/* Windows only sends the lower 16 bits of the control ID when a button
slouken@11937
    64
 * gets clicked. There are also some predefined and custom IDs that lower
slouken@11937
    65
 * the available number further. 2^16 - 101 buttons should be enough for
slouken@11937
    66
 * everyone, no need to make the code more complex.
slouken@11937
    67
 */
slouken@11937
    68
#define MAX_BUTTONS (0xffff - 100)
slouken@11937
    69
slouken@11937
    70
slouken@6620
    71
/* Display a Windows message box */
slouken@6620
    72
slouken@7028
    73
#pragma pack(push, 1)
slouken@7028
    74
slouken@6620
    75
typedef struct
slouken@6620
    76
{
slouken@7191
    77
    WORD dlgVer;
slouken@7191
    78
    WORD signature;
slouken@7191
    79
    DWORD helpID;
slouken@7191
    80
    DWORD exStyle;
slouken@7191
    81
    DWORD style;
slouken@7191
    82
    WORD cDlgItems;
slouken@7191
    83
    short x;
slouken@7191
    84
    short y;
slouken@7191
    85
    short cx;
slouken@7191
    86
    short cy;
slouken@7028
    87
} DLGTEMPLATEEX;
slouken@7028
    88
slouken@7028
    89
typedef struct
slouken@7028
    90
{
slouken@7191
    91
    DWORD helpID;
slouken@7191
    92
    DWORD exStyle;
slouken@7191
    93
    DWORD style;
slouken@7191
    94
    short x;
slouken@7191
    95
    short y;
slouken@7191
    96
    short cx;
slouken@7191
    97
    short cy;
slouken@7191
    98
    DWORD id;
slouken@7028
    99
} DLGITEMTEMPLATEEX;
slouken@7028
   100
slouken@7028
   101
#pragma pack(pop)
slouken@7028
   102
slouken@7028
   103
typedef struct
slouken@7028
   104
{
slouken@7028
   105
    DLGTEMPLATEEX* lpDialog;
slouken@6620
   106
    Uint8 *data;
slouken@6620
   107
    size_t size;
slouken@6620
   108
    size_t used;
slouken@11937
   109
    WORD numbuttons;
slouken@6620
   110
} WIN_DialogData;
slouken@6620
   111
slouken@11937
   112
static SDL_bool GetButtonIndex(const SDL_MessageBoxData *messageboxdata, Uint32 flags, size_t *i)
slouken@11937
   113
{
slouken@11937
   114
    for (*i = 0; *i < (size_t)messageboxdata->numbuttons; ++*i) {
slouken@11937
   115
        if (messageboxdata->buttons[*i].flags & flags) {
slouken@11937
   116
            return SDL_TRUE;
slouken@11937
   117
        }
slouken@11937
   118
    }
slouken@11937
   119
    return SDL_FALSE;
slouken@11937
   120
}
slouken@6620
   121
slouken@6620
   122
static INT_PTR MessageBoxDialogProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
slouken@6620
   123
{
slouken@11937
   124
    const SDL_MessageBoxData *messageboxdata;
slouken@11937
   125
    size_t buttonindex;
slouken@11937
   126
slouken@6620
   127
    switch ( iMessage ) {
slouken@11937
   128
    case WM_INITDIALOG:
slouken@11937
   129
        if (lParam == 0) {
slouken@11937
   130
            EndDialog(hDlg, IDINVALPTRINIT);
slouken@11937
   131
            return TRUE;
slouken@11937
   132
        }
slouken@11937
   133
        messageboxdata = (const SDL_MessageBoxData *)lParam;
slouken@11937
   134
        SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);
slouken@11937
   135
slouken@11937
   136
        if (GetButtonIndex(messageboxdata, SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, &buttonindex)) {
slouken@11937
   137
            /* Focus on the first default return-key button */
slouken@11937
   138
            HWND buttonctl = GetDlgItem(hDlg, (int)(IDBUTTONINDEX0 + buttonindex));
slouken@11937
   139
            if (buttonctl == NULL) {
slouken@11937
   140
                EndDialog(hDlg, IDINVALPTRDLGITEM);
slouken@11937
   141
            }
slouken@11937
   142
            PostMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)buttonctl, TRUE);
slouken@11937
   143
        } else {
slouken@11937
   144
            /* Give the focus to the dialog window instead */
slouken@11937
   145
            SetFocus(hDlg);
slouken@11937
   146
        }
slouken@11937
   147
        return FALSE;
slouken@11937
   148
    case WM_SETFOCUS:
slouken@11937
   149
        messageboxdata = (const SDL_MessageBoxData *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
slouken@11937
   150
        if (messageboxdata == NULL) {
slouken@11937
   151
            EndDialog(hDlg, IDINVALPTRSETFOCUS);
slouken@11937
   152
            return TRUE;
slouken@11937
   153
        }
slouken@11937
   154
slouken@11937
   155
        /* Let the default button be focused if there is one. Otherwise, prevent any initial focus. */
slouken@11937
   156
        if (GetButtonIndex(messageboxdata, SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, &buttonindex)) {
slouken@11937
   157
            return FALSE;
slouken@11937
   158
        }
slouken@11937
   159
        return TRUE;
slouken@6620
   160
    case WM_COMMAND:
slouken@11937
   161
        messageboxdata = (const SDL_MessageBoxData *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
slouken@11937
   162
        if (messageboxdata == NULL) {
slouken@11937
   163
            EndDialog(hDlg, IDINVALPTRCOMMAND);
slouken@11937
   164
            return TRUE;
slouken@11937
   165
        }
slouken@11937
   166
slouken@6620
   167
        /* Return the ID of the button that was pushed */
slouken@11937
   168
        if (wParam == IDOK) {
slouken@11937
   169
            if (GetButtonIndex(messageboxdata, SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, &buttonindex)) {
slouken@11937
   170
                EndDialog(hDlg, IDBUTTONINDEX0 + buttonindex);
slouken@11937
   171
            }
slouken@11937
   172
        } else if (wParam == IDCANCEL) {
slouken@11937
   173
            if (GetButtonIndex(messageboxdata, SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, &buttonindex)) {
slouken@11937
   174
                EndDialog(hDlg, IDBUTTONINDEX0 + buttonindex);
slouken@11937
   175
            } else {
slouken@11937
   176
                /* Closing of window was requested by user or system. It would be rude not to comply. */
slouken@11937
   177
                EndDialog(hDlg, IDCLOSED);
slouken@11937
   178
            }
slouken@11937
   179
        } else if (wParam >= IDBUTTONINDEX0 && (int)wParam - IDBUTTONINDEX0 < messageboxdata->numbuttons) {
slouken@11937
   180
            EndDialog(hDlg, wParam);
slouken@11937
   181
        }
slouken@6620
   182
        return TRUE;
slouken@6620
   183
slouken@6620
   184
    default:
slouken@6620
   185
        break;
slouken@6620
   186
    }
slouken@6620
   187
    return FALSE;
slouken@6620
   188
}
slouken@6620
   189
slouken@6620
   190
static SDL_bool ExpandDialogSpace(WIN_DialogData *dialog, size_t space)
slouken@6620
   191
{
slouken@11937
   192
    /* Growing memory in 64 KiB steps. */
slouken@11937
   193
    const size_t sizestep = 0x10000;
slouken@6620
   194
    size_t size = dialog->size;
slouken@6620
   195
slouken@6620
   196
    if (size == 0) {
slouken@11937
   197
        /* Start with 4 KiB or a multiple of 64 KiB to fit the data. */
slouken@11937
   198
        size = 0x1000;
slouken@11937
   199
        if (SIZE_MAX - sizestep < space) {
slouken@11937
   200
            size = space;
slouken@11937
   201
        } else if (space > size) {
slouken@11937
   202
            size = (space + sizestep) & ~(sizestep - 1);
slouken@6620
   203
        }
slouken@11937
   204
    } else if (SIZE_MAX - dialog->used < space) {
slouken@11937
   205
        SDL_OutOfMemory();
slouken@11937
   206
        return SDL_FALSE;
slouken@11937
   207
    } else if (SIZE_MAX - (dialog->used + space) < sizestep) {
slouken@11937
   208
        /* Close to the maximum. */
slouken@11937
   209
        size = dialog->used + space;
slouken@11937
   210
    } else if (size < dialog->used + space) {
slouken@11937
   211
        /* Round up to the next 64 KiB block. */
slouken@11937
   212
        size = dialog->used + space;
slouken@11937
   213
        size += sizestep - size % sizestep;
slouken@6620
   214
    }
slouken@11937
   215
slouken@6620
   216
    if (size > dialog->size) {
slouken@6620
   217
        void *data = SDL_realloc(dialog->data, size);
slouken@6620
   218
        if (!data) {
slouken@6620
   219
            SDL_OutOfMemory();
slouken@6620
   220
            return SDL_FALSE;
slouken@6620
   221
        }
slouken@6620
   222
        dialog->data = data;
slouken@6620
   223
        dialog->size = size;
slouken@7028
   224
        dialog->lpDialog = (DLGTEMPLATEEX*)dialog->data;
slouken@6620
   225
    }
slouken@6620
   226
    return SDL_TRUE;
slouken@6620
   227
}
slouken@7191
   228
slouken@6620
   229
static SDL_bool AlignDialogData(WIN_DialogData *dialog, size_t size)
slouken@6620
   230
{
slouken@6620
   231
    size_t padding = (dialog->used % size);
slouken@6620
   232
slouken@6620
   233
    if (!ExpandDialogSpace(dialog, padding)) {
slouken@6620
   234
        return SDL_FALSE;
slouken@6620
   235
    }
slouken@6620
   236
slouken@6620
   237
    dialog->used += padding;
slouken@6620
   238
slouken@6620
   239
    return SDL_TRUE;
slouken@6620
   240
}
slouken@6620
   241
slouken@6620
   242
static SDL_bool AddDialogData(WIN_DialogData *dialog, const void *data, size_t size)
slouken@6620
   243
{
slouken@6620
   244
    if (!ExpandDialogSpace(dialog, size)) {
slouken@6620
   245
        return SDL_FALSE;
slouken@6620
   246
    }
slouken@6620
   247
slouken@6620
   248
    SDL_memcpy(dialog->data+dialog->used, data, size);
slouken@6620
   249
    dialog->used += size;
slouken@6620
   250
slouken@6620
   251
    return SDL_TRUE;
slouken@6620
   252
}
slouken@6620
   253
slouken@6620
   254
static SDL_bool AddDialogString(WIN_DialogData *dialog, const char *string)
slouken@6620
   255
{
slouken@6620
   256
    WCHAR *wstring;
slouken@6620
   257
    WCHAR *p;
slouken@6620
   258
    size_t count;
slouken@6620
   259
    SDL_bool status;
slouken@6620
   260
slouken@6620
   261
    if (!string) {
slouken@6620
   262
        string = "";
slouken@6620
   263
    }
slouken@6620
   264
slouken@6620
   265
    wstring = WIN_UTF8ToString(string);
slouken@6620
   266
    if (!wstring) {
slouken@6620
   267
        return SDL_FALSE;
slouken@6620
   268
    }
slouken@6620
   269
slouken@6620
   270
    /* Find out how many characters we have, including null terminator */
slouken@6620
   271
    count = 0;
slouken@6620
   272
    for (p = wstring; *p; ++p) {
slouken@6620
   273
        ++count;
slouken@6620
   274
    }
slouken@6620
   275
    ++count;
slouken@6620
   276
slouken@6620
   277
    status = AddDialogData(dialog, wstring, count*sizeof(WCHAR));
slouken@6620
   278
    SDL_free(wstring);
slouken@6620
   279
    return status;
slouken@6620
   280
}
slouken@6620
   281
slouken@7028
   282
static int s_BaseUnitsX;
slouken@7028
   283
static int s_BaseUnitsY;
icculus@7052
   284
static void Vec2ToDLU(short *x, short *y)
slouken@7028
   285
{
slouken@7191
   286
    SDL_assert(s_BaseUnitsX != 0); /* we init in WIN_ShowMessageBox(), which is the only public function... */
slouken@7028
   287
slouken@7028
   288
    *x = MulDiv(*x, 4, s_BaseUnitsX);
slouken@7028
   289
    *y = MulDiv(*y, 8, s_BaseUnitsY);
slouken@7028
   290
}
slouken@7028
   291
slouken@7028
   292
slouken@11937
   293
static SDL_bool AddDialogControl(WIN_DialogData *dialog, WORD type, DWORD style, DWORD exStyle, int x, int y, int w, int h, int id, const char *caption, WORD ordinal)
slouken@6620
   294
{
slouken@7028
   295
    DLGITEMTEMPLATEEX item;
slouken@6620
   296
    WORD marker = 0xFFFF;
slouken@6620
   297
    WORD extraData = 0;
slouken@6620
   298
slouken@6620
   299
    SDL_zero(item);
slouken@6620
   300
    item.style = style;
slouken@7028
   301
    item.exStyle = exStyle;
slouken@6620
   302
    item.x = x;
slouken@6620
   303
    item.y = y;
slouken@6620
   304
    item.cx = w;
slouken@6620
   305
    item.cy = h;
slouken@6620
   306
    item.id = id;
slouken@6620
   307
slouken@7028
   308
    Vec2ToDLU(&item.x, &item.y);
slouken@7028
   309
    Vec2ToDLU(&item.cx, &item.cy);
slouken@7028
   310
slouken@6620
   311
    if (!AlignDialogData(dialog, sizeof(DWORD))) {
slouken@6620
   312
        return SDL_FALSE;
slouken@6620
   313
    }
slouken@6620
   314
    if (!AddDialogData(dialog, &item, sizeof(item))) {
slouken@6620
   315
        return SDL_FALSE;
slouken@6620
   316
    }
slouken@6620
   317
    if (!AddDialogData(dialog, &marker, sizeof(marker))) {
slouken@6620
   318
        return SDL_FALSE;
slouken@6620
   319
    }
slouken@6620
   320
    if (!AddDialogData(dialog, &type, sizeof(type))) {
slouken@6620
   321
        return SDL_FALSE;
slouken@6620
   322
    }
slouken@11937
   323
    if (type == DLGITEMTYPEBUTTON || (type == DLGITEMTYPESTATIC && caption != NULL)) {
slouken@11937
   324
        if (!AddDialogString(dialog, caption)) {
slouken@11937
   325
            return SDL_FALSE;
slouken@11937
   326
        }
slouken@11937
   327
    } else {
slouken@11937
   328
        if (!AddDialogData(dialog, &marker, sizeof(marker))) {
slouken@11937
   329
            return SDL_FALSE;
slouken@11937
   330
        }
slouken@11937
   331
        if (!AddDialogData(dialog, &ordinal, sizeof(ordinal))) {
slouken@11937
   332
            return SDL_FALSE;
slouken@11937
   333
        }
slouken@6620
   334
    }
slouken@6620
   335
    if (!AddDialogData(dialog, &extraData, sizeof(extraData))) {
slouken@6620
   336
        return SDL_FALSE;
slouken@6620
   337
    }
slouken@11937
   338
    if (type == DLGITEMTYPEBUTTON) {
slouken@11937
   339
        dialog->numbuttons++;
slouken@11937
   340
    }
slouken@7028
   341
    ++dialog->lpDialog->cDlgItems;
slouken@6620
   342
slouken@6620
   343
    return SDL_TRUE;
slouken@6620
   344
}
slouken@6620
   345
slouken@11937
   346
static SDL_bool AddDialogStaticText(WIN_DialogData *dialog, int x, int y, int w, int h, const char *text)
slouken@6620
   347
{
slouken@11937
   348
    DWORD style = WS_VISIBLE | WS_CHILD | SS_LEFT | SS_NOPREFIX | SS_EDITCONTROL | WS_GROUP;
slouken@11937
   349
    return AddDialogControl(dialog, DLGITEMTYPESTATIC, style, 0, x, y, w, h, -1, text, 0);
slouken@11937
   350
}
slouken@11937
   351
slouken@11937
   352
static SDL_bool AddDialogStaticIcon(WIN_DialogData *dialog, int x, int y, int w, int h, Uint16 ordinal)
slouken@11937
   353
{
slouken@11937
   354
    DWORD style = WS_VISIBLE | WS_CHILD | SS_ICON | WS_GROUP;
slouken@11937
   355
    return AddDialogControl(dialog, DLGITEMTYPESTATIC, style, 0, x, y, w, h, -2, NULL, ordinal);
slouken@6620
   356
}
slouken@6620
   357
slouken@6620
   358
static SDL_bool AddDialogButton(WIN_DialogData *dialog, int x, int y, int w, int h, const char *text, int id, SDL_bool isDefault)
slouken@6620
   359
{
slouken@11937
   360
    DWORD style = WS_VISIBLE | WS_CHILD | WS_TABSTOP;
slouken@6620
   361
    if (isDefault) {
slouken@6620
   362
        style |= BS_DEFPUSHBUTTON;
slouken@6620
   363
    } else {
slouken@6620
   364
        style |= BS_PUSHBUTTON;
slouken@6620
   365
    }
slouken@11937
   366
    /* The first button marks the start of the group. */
slouken@11937
   367
    if (dialog->numbuttons == 0) {
slouken@11937
   368
        style |= WS_GROUP;
slouken@11937
   369
    }
slouken@11937
   370
    return AddDialogControl(dialog, DLGITEMTYPEBUTTON, style, 0, x, y, w, h, IDBUTTONINDEX0 + dialog->numbuttons, text, 0);
slouken@6620
   371
}
slouken@6620
   372
slouken@6620
   373
static void FreeDialogData(WIN_DialogData *dialog)
slouken@6620
   374
{
slouken@7719
   375
    SDL_free(dialog->data);
slouken@6620
   376
    SDL_free(dialog);
slouken@6620
   377
}
slouken@6620
   378
slouken@6620
   379
static WIN_DialogData *CreateDialogData(int w, int h, const char *caption)
slouken@6620
   380
{
slouken@6620
   381
    WIN_DialogData *dialog;
slouken@7028
   382
    DLGTEMPLATEEX dialogTemplate;
slouken@7028
   383
    WORD WordToPass;
slouken@6620
   384
slouken@6620
   385
    SDL_zero(dialogTemplate);
slouken@7028
   386
    dialogTemplate.dlgVer = 1;
slouken@7028
   387
    dialogTemplate.signature = 0xffff;
slouken@7028
   388
    dialogTemplate.style = (WS_CAPTION | DS_CENTER | DS_SHELLFONT);
slouken@6620
   389
    dialogTemplate.x = 0;
slouken@6620
   390
    dialogTemplate.y = 0;
slouken@6620
   391
    dialogTemplate.cx = w;
slouken@6620
   392
    dialogTemplate.cy = h;
slouken@7028
   393
    Vec2ToDLU(&dialogTemplate.cx, &dialogTemplate.cy);
slouken@6620
   394
slouken@6620
   395
    dialog = (WIN_DialogData *)SDL_calloc(1, sizeof(*dialog));
slouken@6620
   396
    if (!dialog) {
slouken@6620
   397
        return NULL;
slouken@6620
   398
    }
slouken@6620
   399
slouken@6620
   400
    if (!AddDialogData(dialog, &dialogTemplate, sizeof(dialogTemplate))) {
slouken@6620
   401
        FreeDialogData(dialog);
slouken@6620
   402
        return NULL;
slouken@6620
   403
    }
slouken@6620
   404
slouken@7191
   405
    /* No menu */
slouken@7028
   406
    WordToPass = 0;
slouken@7028
   407
    if (!AddDialogData(dialog, &WordToPass, 2)) {
slouken@6620
   408
        FreeDialogData(dialog);
slouken@6620
   409
        return NULL;
slouken@6620
   410
    }
slouken@6620
   411
slouken@7191
   412
    /* No custom class */
slouken@7028
   413
    if (!AddDialogData(dialog, &WordToPass, 2)) {
slouken@7028
   414
        FreeDialogData(dialog);
slouken@7028
   415
        return NULL;
slouken@7028
   416
    }
slouken@7028
   417
slouken@7191
   418
    /* title */
slouken@6620
   419
    if (!AddDialogString(dialog, caption)) {
slouken@6620
   420
        FreeDialogData(dialog);
slouken@6620
   421
        return NULL;
slouken@6620
   422
    }
slouken@6620
   423
slouken@7191
   424
    /* Font stuff */
slouken@7028
   425
    {
slouken@7191
   426
        /*
slouken@7191
   427
         * We want to use the system messagebox font.
slouken@7191
   428
         */
slouken@7028
   429
        BYTE ToPass;
slouken@7191
   430
slouken@7028
   431
        NONCLIENTMETRICSA NCM;
slouken@7028
   432
        NCM.cbSize = sizeof(NCM);
slouken@7028
   433
        SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, 0, &NCM, 0);
slouken@7191
   434
slouken@7191
   435
        /* Font size - convert to logical font size for dialog parameter. */
slouken@7028
   436
        {
slouken@9863
   437
            HDC ScreenDC = GetDC(NULL);
slouken@9863
   438
            int LogicalPixelsY = GetDeviceCaps(ScreenDC, LOGPIXELSY);
slouken@9863
   439
            if (!LogicalPixelsY) /* This can happen if the application runs out of GDI handles */
slouken@9863
   440
                LogicalPixelsY = 72;
slouken@9863
   441
            WordToPass = (WORD)(-72 * NCM.lfMessageFont.lfHeight / LogicalPixelsY);
slouken@9863
   442
            ReleaseDC(NULL, ScreenDC);
slouken@7028
   443
        }
slouken@7028
   444
slouken@7028
   445
        if (!AddDialogData(dialog, &WordToPass, 2)) {
slouken@7028
   446
            FreeDialogData(dialog);
slouken@7028
   447
            return NULL;
slouken@7028
   448
        }
slouken@7028
   449
slouken@7191
   450
        /* Font weight */
slouken@7028
   451
        WordToPass = (WORD)NCM.lfMessageFont.lfWeight;
slouken@7028
   452
        if (!AddDialogData(dialog, &WordToPass, 2)) {
slouken@7028
   453
            FreeDialogData(dialog);
slouken@7028
   454
            return NULL;
slouken@7028
   455
        }
slouken@7028
   456
slouken@7191
   457
        /* italic? */
slouken@7028
   458
        ToPass = NCM.lfMessageFont.lfItalic;
slouken@7028
   459
        if (!AddDialogData(dialog, &ToPass, 1)) {
slouken@7028
   460
            FreeDialogData(dialog);
slouken@7028
   461
            return NULL;
slouken@7028
   462
        }
slouken@7028
   463
slouken@7191
   464
        /* charset? */
slouken@7028
   465
        ToPass = NCM.lfMessageFont.lfCharSet;
slouken@7028
   466
        if (!AddDialogData(dialog, &ToPass, 1)) {
slouken@7028
   467
            FreeDialogData(dialog);
slouken@7028
   468
            return NULL;
slouken@7028
   469
        }
slouken@7028
   470
slouken@7191
   471
        /* font typeface. */
slouken@7028
   472
        if (!AddDialogString(dialog, NCM.lfMessageFont.lfFaceName)) {
slouken@7028
   473
            FreeDialogData(dialog);
slouken@7028
   474
            return NULL;
slouken@7028
   475
        }
slouken@7028
   476
    }
slouken@7028
   477
slouken@6620
   478
    return dialog;
slouken@6620
   479
}
slouken@6620
   480
slouken@11937
   481
/* Escaping ampersands is necessary to disable mnemonics in dialog controls.
slouken@11937
   482
 * The caller provides a char** for dst and a size_t* for dstlen where the
slouken@11937
   483
 * address of the work buffer and its size will be stored. Their values must be
slouken@11937
   484
 * NULL and 0 on the first call. src is the string to be escaped. On error, the
slouken@11937
   485
 * function returns NULL and, on success, returns a pointer to the escaped
slouken@11937
   486
 * sequence as a read-only string that is valid until the next call or until the
slouken@11937
   487
 * work buffer is freed. Once all strings have been processed, it's the caller's
slouken@11937
   488
 * responsibilty to free the work buffer with SDL_free, even on errors.
slouken@11937
   489
 */
slouken@11937
   490
static const char *EscapeAmpersands(char **dst, size_t *dstlen, const char *src)
slouken@11937
   491
{
slouken@11937
   492
    char *newdst;
slouken@11937
   493
    size_t ampcount = 0;
slouken@11937
   494
    size_t srclen = 0;
slouken@11937
   495
slouken@11937
   496
    if (src == NULL) {
slouken@11937
   497
        return NULL;
slouken@11937
   498
    }
slouken@11937
   499
slouken@11937
   500
    while (src[srclen]) {
slouken@11937
   501
        if (src[srclen] == '&') {
slouken@11937
   502
            ampcount++;
slouken@11937
   503
        }
slouken@11937
   504
        srclen++;
slouken@11937
   505
    }
slouken@11937
   506
    srclen++;
slouken@11937
   507
slouken@11937
   508
    if (ampcount == 0) {
slouken@11937
   509
        /* Nothing to do. */
slouken@11937
   510
        return src;
slouken@11937
   511
    }
slouken@11937
   512
    if (SIZE_MAX - srclen < ampcount) {
slouken@11937
   513
        return NULL;
slouken@11937
   514
    }
slouken@11937
   515
    if (*dst == NULL || *dstlen < srclen + ampcount) {
slouken@11937
   516
        /* Allocating extra space in case the next strings are a bit longer. */
slouken@11937
   517
        size_t extraspace = SIZE_MAX - (srclen + ampcount);
slouken@11937
   518
        if (extraspace > 512) {
slouken@11937
   519
            extraspace = 512;
slouken@11937
   520
        }
slouken@11937
   521
        *dstlen = srclen + ampcount + extraspace;
slouken@11937
   522
        SDL_free(*dst);
slouken@11937
   523
        *dst = NULL;
slouken@11937
   524
        newdst = SDL_malloc(*dstlen);
slouken@11937
   525
        if (newdst == NULL) {
slouken@11937
   526
            return NULL;
slouken@11937
   527
        }
slouken@11937
   528
        *dst = newdst;
slouken@11937
   529
    } else {
slouken@11937
   530
        newdst = *dst;
slouken@11937
   531
    }
slouken@11937
   532
slouken@11937
   533
    /* The escape character is the ampersand itself. */
slouken@11937
   534
    while (srclen--) {
slouken@11937
   535
        if (*src == '&') {
slouken@11937
   536
            *newdst++ = '&';
slouken@11937
   537
        }
slouken@11937
   538
        *newdst++ = *src++;
slouken@11937
   539
    }
slouken@11937
   540
slouken@11937
   541
    return *dst;
slouken@11937
   542
}
slouken@11937
   543
icculus@11917
   544
/* This function is called if a Task Dialog is unsupported. */
icculus@11917
   545
static int
icculus@11917
   546
WIN_ShowOldMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
slouken@6620
   547
{
slouken@6620
   548
    WIN_DialogData *dialog;
slouken@11937
   549
    int i, x, y, retval;
slouken@6620
   550
    const SDL_MessageBoxButtonData *buttons = messageboxdata->buttons;
slouken@7028
   551
    HFONT DialogFont;
slouken@7028
   552
    SIZE Size;
slouken@7028
   553
    RECT TextSize;
slouken@7028
   554
    wchar_t* wmessage;
slouken@7028
   555
    TEXTMETRIC TM;
slouken@11937
   556
    HDC FontDC;
slouken@11937
   557
    INT_PTR result;
slouken@11937
   558
    char *ampescape = NULL;
slouken@11937
   559
    size_t ampescapesize = 0;
slouken@11937
   560
    Uint16 defbuttoncount = 0;
slouken@11937
   561
    Uint16 icon = 0;
slouken@7028
   562
icculus@11036
   563
    HWND ParentWindow = NULL;
slouken@7028
   564
slouken@7028
   565
    const int ButtonWidth = 88;
slouken@7028
   566
    const int ButtonHeight = 26;
slouken@7028
   567
    const int TextMargin = 16;
slouken@7028
   568
    const int ButtonMargin = 12;
slouken@11937
   569
    const int IconWidth = GetSystemMetrics(SM_CXICON);
slouken@11937
   570
    const int IconHeight = GetSystemMetrics(SM_CYICON);
slouken@11937
   571
    const int IconMargin = 20;
slouken@6620
   572
slouken@11937
   573
    if (messageboxdata->numbuttons > MAX_BUTTONS) {
slouken@11937
   574
        return SDL_SetError("Number of butons exceeds limit of %d", MAX_BUTTONS);
slouken@11937
   575
    }
slouken@11937
   576
slouken@11937
   577
    switch (messageboxdata->flags) {
slouken@11937
   578
    case SDL_MESSAGEBOX_ERROR:
icculus@12042
   579
        icon = (Uint16)(size_t)IDI_ERROR;
slouken@11937
   580
        break;
slouken@11937
   581
    case SDL_MESSAGEBOX_WARNING:
icculus@12042
   582
        icon = (Uint16)(size_t)IDI_WARNING;
slouken@11937
   583
        break;
slouken@11937
   584
    case SDL_MESSAGEBOX_INFORMATION:
icculus@12042
   585
        icon = (Uint16)(size_t)IDI_INFORMATION;
slouken@11937
   586
        break;
slouken@11937
   587
    }
slouken@7028
   588
slouken@7191
   589
    /* Jan 25th, 2013 - dant@fleetsa.com
slouken@7191
   590
     *
slouken@7191
   591
     *
slouken@7191
   592
     * I've tried to make this more reasonable, but I've run in to a lot
slouken@7191
   593
     * of nonsense.
slouken@7191
   594
     *
slouken@7191
   595
     * The original issue is the code was written in pixels and not
slouken@7191
   596
     * dialog units (DLUs). All DialogBox functions use DLUs, which
slouken@7191
   597
     * vary based on the selected font (yay).
slouken@7191
   598
     *
slouken@7191
   599
     * According to MSDN, the most reliable way to convert is via
slouken@7191
   600
     * MapDialogUnits, which requires an HWND, which we don't have
slouken@7191
   601
     * at time of template creation.
slouken@7191
   602
     *
slouken@7191
   603
     * We do however have:
slouken@7191
   604
     *  The system font (DLU width 8 for me)
slouken@7191
   605
     *  The font we select for the dialog (DLU width 6 for me)
slouken@7191
   606
     *
slouken@7191
   607
     * Based on experimentation, *neither* of these return the value
slouken@7191
   608
     * actually used. Stepping in to MapDialogUnits(), the conversion
slouken@7191
   609
     * is fairly clear, and uses 7 for me.
slouken@7191
   610
     *
slouken@7191
   611
     * As a result, some of this is hacky to ensure the sizing is
slouken@7191
   612
     * somewhat correct.
slouken@7191
   613
     *
slouken@7191
   614
     * Honestly, a long term solution is to use CreateWindow, not CreateDialog.
slouken@7191
   615
     *
slouken@7191
   616
slouken@7191
   617
     *
slouken@7191
   618
     * In order to get text dimensions we need to have a DC with the desired font.
slouken@7191
   619
     * I'm assuming a dialog box in SDL is rare enough we can to the create.
slouken@7191
   620
     */
slouken@11937
   621
    FontDC = CreateCompatibleDC(0);
slouken@7191
   622
slouken@7028
   623
    {
slouken@7191
   624
        /* Create a duplicate of the font used in system message boxes. */
slouken@7028
   625
        LOGFONT lf;
slouken@7028
   626
        NONCLIENTMETRICS NCM;
slouken@7028
   627
        NCM.cbSize = sizeof(NCM);
slouken@7028
   628
        SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &NCM, 0);
slouken@7028
   629
        lf = NCM.lfMessageFont;
slouken@7028
   630
        DialogFont = CreateFontIndirect(&lf);
slouken@7028
   631
    }
slouken@7028
   632
slouken@7191
   633
    /* Select the font in to our DC */
slouken@7028
   634
    SelectObject(FontDC, DialogFont);
slouken@7028
   635
slouken@7028
   636
    {
slouken@7191
   637
        /* Get the metrics to try and figure our DLU conversion. */
slouken@7028
   638
        GetTextMetrics(FontDC, &TM);
slouken@11303
   639
slouken@11303
   640
        /* Calculation from the following documentation:
slouken@11303
   641
         * https://support.microsoft.com/en-gb/help/125681/how-to-calculate-dialog-base-units-with-non-system-based-font
slouken@11303
   642
         * This fixes bug 2137, dialog box calculation with a fixed-width system font
slouken@11303
   643
         */
slouken@11303
   644
        {
slouken@11303
   645
            SIZE extent;
slouken@11303
   646
            GetTextExtentPoint32A(FontDC, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &extent);
slouken@11303
   647
            s_BaseUnitsX = (extent.cx / 26 + 1) / 2;
slouken@11303
   648
        }
slouken@11303
   649
        /*s_BaseUnitsX = TM.tmAveCharWidth + 1;*/
slouken@7028
   650
        s_BaseUnitsY = TM.tmHeight;
slouken@7028
   651
    }
slouken@7191
   652
slouken@7191
   653
    /* Measure the *pixel* size of the string. */
slouken@7028
   654
    wmessage = WIN_UTF8ToString(messageboxdata->message);
slouken@7028
   655
    SDL_zero(TextSize);
slouken@11937
   656
    DrawText(FontDC, wmessage, -1, &TextSize, DT_CALCRECT | DT_LEFT | DT_NOPREFIX | DT_EDITCONTROL);
slouken@7028
   657
slouken@11937
   658
    /* Add margins and some padding for hangs, etc. */
slouken@11937
   659
    TextSize.left += TextMargin;
slouken@11937
   660
    TextSize.right += TextMargin + 2;
slouken@11937
   661
    TextSize.top += TextMargin;
slouken@11937
   662
    TextSize.bottom += TextMargin + 2;
slouken@7028
   663
slouken@7191
   664
    /* Done with the DC, and the string */
slouken@7028
   665
    DeleteDC(FontDC);
slouken@7028
   666
    SDL_free(wmessage);
slouken@7028
   667
slouken@7191
   668
    /* Increase the size of the dialog by some border spacing around the text. */
slouken@7028
   669
    Size.cx = TextSize.right - TextSize.left;
slouken@7028
   670
    Size.cy = TextSize.bottom - TextSize.top;
slouken@7028
   671
    Size.cx += TextMargin * 2;
slouken@7028
   672
    Size.cy += TextMargin * 2;
slouken@7028
   673
slouken@11937
   674
    /* Make dialog wider and shift text over for the icon. */
slouken@11937
   675
    if (icon) {
slouken@11937
   676
        Size.cx += IconMargin + IconWidth;
slouken@11937
   677
        TextSize.left += IconMargin + IconWidth;
slouken@11937
   678
        TextSize.right += IconMargin + IconWidth;
slouken@11937
   679
    }
slouken@11937
   680
slouken@7191
   681
    /* Ensure the size is wide enough for all of the buttons. */
slouken@7028
   682
    if (Size.cx < messageboxdata->numbuttons * (ButtonWidth + ButtonMargin) + ButtonMargin)
slouken@7028
   683
        Size.cx = messageboxdata->numbuttons * (ButtonWidth + ButtonMargin) + ButtonMargin;
slouken@7028
   684
slouken@11937
   685
    /* Reset the height to the icon size if it is actually bigger than the text. */
slouken@11937
   686
    if (icon && Size.cy < IconMargin * 2 + IconHeight) {
slouken@11937
   687
        Size.cy = IconMargin * 2 + IconHeight;
slouken@11937
   688
    }
slouken@11937
   689
slouken@7191
   690
    /* Add vertical space for the buttons and border. */
slouken@7028
   691
    Size.cy += ButtonHeight + TextMargin;
slouken@7028
   692
slouken@7028
   693
    dialog = CreateDialogData(Size.cx, Size.cy, messageboxdata->title);
slouken@6620
   694
    if (!dialog) {
slouken@6620
   695
        return -1;
slouken@6620
   696
    }
slouken@6620
   697
slouken@11937
   698
    if (icon && ! AddDialogStaticIcon(dialog, IconMargin, IconMargin, IconWidth, IconHeight, icon)) {
slouken@11937
   699
        FreeDialogData(dialog);
slouken@11937
   700
        return -1;
slouken@11937
   701
    }
slouken@11937
   702
slouken@11937
   703
    if (!AddDialogStaticText(dialog, TextSize.left, TextSize.top, TextSize.right - TextSize.left, TextSize.bottom - TextSize.top, messageboxdata->message)) {
slouken@6620
   704
        FreeDialogData(dialog);
slouken@6620
   705
        return -1;
slouken@6620
   706
    }
slouken@6620
   707
slouken@7191
   708
    /* Align the buttons to the right/bottom. */
slouken@10478
   709
    x = Size.cx - (ButtonWidth + ButtonMargin) * messageboxdata->numbuttons;
slouken@7028
   710
    y = Size.cy - ButtonHeight - ButtonMargin;
slouken@10478
   711
    for (i = messageboxdata->numbuttons - 1; i >= 0; --i) {
slouken@11937
   712
        SDL_bool isdefault = SDL_FALSE;
slouken@11937
   713
        const char *buttontext;
slouken@6620
   714
slouken@6620
   715
        if (buttons[i].flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) {
slouken@11937
   716
            defbuttoncount++;
slouken@11937
   717
            if (defbuttoncount == 1) {
slouken@11937
   718
                isdefault = SDL_TRUE;
slouken@11937
   719
            }
slouken@6620
   720
        }
slouken@11937
   721
slouken@11937
   722
        buttontext = EscapeAmpersands(&ampescape, &ampescapesize, buttons[i].text);
slouken@11937
   723
        if (buttontext == NULL || !AddDialogButton(dialog, x, y, ButtonWidth, ButtonHeight, buttontext, buttons[i].buttonid, isdefault)) {
slouken@6620
   724
            FreeDialogData(dialog);
slouken@11937
   725
            SDL_free(ampescape);
slouken@6620
   726
            return -1;
slouken@6620
   727
        }
slouken@10478
   728
        x += ButtonWidth + ButtonMargin;
slouken@6620
   729
    }
slouken@11937
   730
    SDL_free(ampescape);
slouken@6620
   731
icculus@11036
   732
    /* If we have a parent window, get the Instance and HWND for them
icculus@11036
   733
     * so that our little dialog gets exclusive focus at all times. */
icculus@11037
   734
    if (messageboxdata->window) {
icculus@11036
   735
        ParentWindow = ((SDL_WindowData*)messageboxdata->window->driverdata)->hwnd;
icculus@11037
   736
    }
icculus@11036
   737
slouken@11937
   738
    result = DialogBoxIndirectParam(NULL, (DLGTEMPLATE*)dialog->lpDialog, ParentWindow, (DLGPROC)MessageBoxDialogProc, (LPARAM)messageboxdata);
slouken@11937
   739
    if (result >= IDBUTTONINDEX0 && result - IDBUTTONINDEX0 < messageboxdata->numbuttons) {
slouken@11937
   740
        *buttonid = messageboxdata->buttons[(messageboxdata->numbuttons - 1) - (result - IDBUTTONINDEX0)].buttonid;
slouken@11937
   741
        retval = 0;
slouken@11937
   742
    } else if (result == IDCLOSED) {
slouken@11937
   743
        /* Dialog window closed by user or system. */
slouken@11937
   744
        /* This could use a special return code. */
slouken@11937
   745
        retval = 0;
slouken@11937
   746
        *buttonid = -1;
slouken@11937
   747
    } else {
slouken@11937
   748
        if (result == 0) {
slouken@11937
   749
            SDL_SetError("Invalid parent window handle");
slouken@11937
   750
        } else if (result == -1) {
slouken@11937
   751
            SDL_SetError("The message box encountered an error.");
slouken@11937
   752
        } else if (result == IDINVALPTRINIT || result == IDINVALPTRSETFOCUS || result == IDINVALPTRCOMMAND) {
slouken@11937
   753
            SDL_SetError("Invalid message box pointer in dialog procedure");
slouken@11937
   754
        } else if (result == IDINVALPTRDLGITEM) {
slouken@11937
   755
            SDL_SetError("Couldn't find dialog control of the default enter-key button");
slouken@11937
   756
        } else {
slouken@11937
   757
            SDL_SetError("An unknown error occured");
slouken@11937
   758
        }
slouken@11937
   759
        retval = -1;
slouken@11937
   760
    }
slouken@6620
   761
slouken@6620
   762
    FreeDialogData(dialog);
slouken@11937
   763
    return retval;
slouken@6620
   764
}
slouken@6620
   765
icculus@11917
   766
/* TaskDialogIndirect procedure
icculus@11917
   767
 * This is because SDL targets Windows XP (0x501), so this is not defined in the platform SDK.
icculus@11917
   768
 */
icculus@11917
   769
typedef HRESULT(FAR WINAPI *TASKDIALOGINDIRECTPROC)(const TASKDIALOGCONFIG *pTaskConfig, int *pnButton, int *pnRadioButton, BOOL *pfVerificationFlagChecked);
icculus@11917
   770
icculus@11917
   771
int
icculus@11917
   772
WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
icculus@11917
   773
{
icculus@11917
   774
    HWND ParentWindow = NULL;
icculus@11917
   775
    wchar_t *wmessage;
icculus@11917
   776
    wchar_t *wtitle;
icculus@11917
   777
    TASKDIALOGCONFIG TaskConfig;
icculus@11917
   778
    TASKDIALOG_BUTTON *pButtons;
icculus@11917
   779
    TASKDIALOG_BUTTON *pButton;
icculus@11917
   780
    HMODULE hComctl32;
icculus@11917
   781
    TASKDIALOGINDIRECTPROC pfnTaskDialogIndirect;
icculus@11917
   782
    HRESULT hr;
slouken@11937
   783
    char *ampescape = NULL;
slouken@11937
   784
    size_t ampescapesize = 0;
icculus@11917
   785
    int nButton;
icculus@11917
   786
    int nCancelButton;
icculus@11917
   787
    int i;
icculus@11917
   788
slouken@11937
   789
    if (SIZE_MAX / sizeof(TASKDIALOG_BUTTON) < messageboxdata->numbuttons) {
slouken@11937
   790
        return SDL_OutOfMemory();
slouken@11937
   791
    }
slouken@11937
   792
icculus@11917
   793
    /* If we cannot load comctl32.dll use the old messagebox! */
icculus@11917
   794
    hComctl32 = LoadLibrary(TEXT("Comctl32.dll"));
icculus@11917
   795
    if (hComctl32 == NULL) {
slouken@11937
   796
        return WIN_ShowOldMessageBox(messageboxdata, buttonid);
icculus@11917
   797
    }
slouken@11937
   798
icculus@11917
   799
    /* If TaskDialogIndirect doesn't exist use the old messagebox!
icculus@11917
   800
       This will fail prior to Windows Vista.
icculus@11917
   801
       The manifest file in the application may require targeting version 6 of comctl32.dll, even
icculus@11917
   802
       when we use LoadLibrary here!
icculus@11917
   803
       If you don't want to bother with manifests, put this #pragma in your app's source code somewhere:
icculus@11917
   804
       pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0'  processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
icculus@11917
   805
     */
icculus@11917
   806
    pfnTaskDialogIndirect = (TASKDIALOGINDIRECTPROC) GetProcAddress(hComctl32, "TaskDialogIndirect");
icculus@11917
   807
    if (pfnTaskDialogIndirect == NULL) {
icculus@11917
   808
        FreeLibrary(hComctl32);
icculus@11917
   809
        return WIN_ShowOldMessageBox(messageboxdata, buttonid);
icculus@11917
   810
    }
icculus@11917
   811
icculus@11917
   812
    /* If we have a parent window, get the Instance and HWND for them
icculus@11917
   813
       so that our little dialog gets exclusive focus at all times. */
icculus@11917
   814
    if (messageboxdata->window) {
icculus@11917
   815
        ParentWindow = ((SDL_WindowData *) messageboxdata->window->driverdata)->hwnd;
icculus@11917
   816
    }
icculus@11917
   817
icculus@11917
   818
    wmessage = WIN_UTF8ToString(messageboxdata->message);
icculus@11917
   819
    wtitle = WIN_UTF8ToString(messageboxdata->title);
icculus@11917
   820
icculus@11917
   821
    SDL_zero(TaskConfig);
icculus@11917
   822
    TaskConfig.cbSize = sizeof (TASKDIALOGCONFIG);
icculus@11917
   823
    TaskConfig.hwndParent = ParentWindow;
icculus@11917
   824
    TaskConfig.dwFlags = TDF_SIZE_TO_CONTENT;
icculus@11917
   825
    TaskConfig.pszWindowTitle = wtitle;
icculus@11917
   826
    if (messageboxdata->flags & SDL_MESSAGEBOX_ERROR) {
icculus@11917
   827
        TaskConfig.pszMainIcon = TD_ERROR_ICON;
icculus@11917
   828
    } else if (messageboxdata->flags & SDL_MESSAGEBOX_WARNING) {
icculus@11917
   829
        TaskConfig.pszMainIcon = TD_WARNING_ICON;
icculus@11917
   830
    } else if (messageboxdata->flags & SDL_MESSAGEBOX_INFORMATION) {
icculus@11917
   831
        TaskConfig.pszMainIcon = TD_INFORMATION_ICON;
icculus@11917
   832
    } else {
icculus@11917
   833
        TaskConfig.pszMainIcon = NULL;
icculus@11917
   834
    }
icculus@11917
   835
icculus@11917
   836
    TaskConfig.pszContent = wmessage;
icculus@11917
   837
    TaskConfig.cButtons = messageboxdata->numbuttons;
icculus@11917
   838
    pButtons = SDL_malloc(sizeof (TASKDIALOG_BUTTON) * messageboxdata->numbuttons);
icculus@11917
   839
    TaskConfig.nDefaultButton = 0;
slouken@11920
   840
    nCancelButton = 0;
icculus@11917
   841
    for (i = 0; i < messageboxdata->numbuttons; i++)
icculus@11917
   842
    {
slouken@11937
   843
        const char *buttontext;
icculus@11917
   844
        pButton = &pButtons[messageboxdata->numbuttons-1-i];
icculus@11917
   845
        if (messageboxdata->buttons[i].flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) {
icculus@11917
   846
            nCancelButton = messageboxdata->buttons[i].buttonid;
icculus@11917
   847
            pButton->nButtonID = 2;
icculus@11917
   848
        } else {
icculus@11917
   849
            pButton->nButtonID = messageboxdata->buttons[i].buttonid + 1;
icculus@11917
   850
            if (pButton->nButtonID >= 2) {
icculus@11917
   851
                pButton->nButtonID++;
icculus@11917
   852
            }
icculus@11917
   853
        }
slouken@11937
   854
        buttontext = EscapeAmpersands(&ampescape, &ampescapesize, messageboxdata->buttons[i].text);
slouken@11937
   855
        if (buttontext == NULL) {
slouken@11937
   856
            int j;
slouken@11937
   857
            FreeLibrary(hComctl32);
slouken@11937
   858
            SDL_free(ampescape);
slouken@11937
   859
            SDL_free(wmessage);
slouken@11937
   860
            SDL_free(wtitle);
slouken@11937
   861
            for (j = 0; j < i; j++) {
slouken@11937
   862
                SDL_free((wchar_t *) pButtons[j].pszButtonText);
slouken@11937
   863
            }
slouken@11937
   864
            SDL_free(pButtons);
slouken@11937
   865
            return -1;
slouken@11937
   866
        }
slouken@11937
   867
        pButton->pszButtonText = WIN_UTF8ToString(buttontext);
icculus@11917
   868
        if (messageboxdata->buttons[i].flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) {
icculus@11917
   869
            TaskConfig.nDefaultButton = pButton->nButtonID;
icculus@11917
   870
        }
icculus@11917
   871
    }
icculus@11917
   872
    TaskConfig.pButtons = pButtons;
icculus@11917
   873
icculus@11917
   874
    /* Show the Task Dialog */
icculus@11917
   875
    hr = pfnTaskDialogIndirect(&TaskConfig, &nButton, NULL, NULL);
icculus@11917
   876
icculus@11917
   877
    /* Free everything */
icculus@11917
   878
    FreeLibrary(hComctl32);
slouken@11937
   879
    SDL_free(ampescape);
icculus@11917
   880
    SDL_free(wmessage);
icculus@11917
   881
    SDL_free(wtitle);
icculus@11917
   882
    for (i = 0; i < messageboxdata->numbuttons; i++) {
icculus@11917
   883
        SDL_free((wchar_t *) pButtons[i].pszButtonText);
icculus@11917
   884
    }
icculus@11917
   885
    SDL_free(pButtons);
icculus@11917
   886
icculus@11917
   887
    /* Check the Task Dialog was successful and give the result */
icculus@11917
   888
    if (SUCCEEDED(hr)) {
icculus@11917
   889
        if (nButton == 2) {
icculus@11917
   890
            *buttonid = nCancelButton;
icculus@11917
   891
        } else if (nButton > 2) {
icculus@11917
   892
            *buttonid = nButton-1-1;
icculus@11917
   893
        } else {
icculus@11917
   894
            *buttonid = nButton-1;
icculus@11917
   895
        }
icculus@11917
   896
        return 0;
icculus@11917
   897
    }
icculus@11917
   898
icculus@11917
   899
    /* We failed showing the Task Dialog, use the old message box! */
icculus@11917
   900
    return WIN_ShowOldMessageBox(messageboxdata, buttonid);
icculus@11917
   901
}
icculus@11917
   902
slouken@6620
   903
#endif /* SDL_VIDEO_DRIVER_WINDOWS */
slouken@6620
   904
slouken@6620
   905
/* vi: set ts=4 sw=4 expandtab: */