123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913 |
- /*
- Simple DirectMedia Layer
- Copyright (C) 1997-2021 Sam Lantinga <[email protected]>
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
- */
- #include "../../SDL_internal.h"
- #if SDL_VIDEO_DRIVER_WINDOWS
- #ifdef HAVE_LIMITS_H
- #include <limits.h>
- #endif
- #ifndef SIZE_MAX
- #define SIZE_MAX ((size_t)-1)
- #endif
- #include "../../core/windows/SDL_windows.h"
- #include "SDL_windowsvideo.h"
- #include "SDL_windowstaskdialog.h"
- #ifndef SS_EDITCONTROL
- #define SS_EDITCONTROL 0x2000
- #endif
- #ifndef IDOK
- #define IDOK 1
- #endif
- #ifndef IDCANCEL
- #define IDCANCEL 2
- #endif
- /* Custom dialog return codes */
- #define IDCLOSED 20
- #define IDINVALPTRINIT 50
- #define IDINVALPTRCOMMAND 51
- #define IDINVALPTRSETFOCUS 52
- #define IDINVALPTRDLGITEM 53
- /* First button ID */
- #define IDBUTTONINDEX0 100
- #define DLGITEMTYPEBUTTON 0x0080
- #define DLGITEMTYPESTATIC 0x0082
- /* Windows only sends the lower 16 bits of the control ID when a button
- * gets clicked. There are also some predefined and custom IDs that lower
- * the available number further. 2^16 - 101 buttons should be enough for
- * everyone, no need to make the code more complex.
- */
- #define MAX_BUTTONS (0xffff - 100)
- /* Display a Windows message box */
- #pragma pack(push, 1)
- typedef struct
- {
- WORD dlgVer;
- WORD signature;
- DWORD helpID;
- DWORD exStyle;
- DWORD style;
- WORD cDlgItems;
- short x;
- short y;
- short cx;
- short cy;
- } DLGTEMPLATEEX;
- typedef struct
- {
- DWORD helpID;
- DWORD exStyle;
- DWORD style;
- short x;
- short y;
- short cx;
- short cy;
- DWORD id;
- } DLGITEMTEMPLATEEX;
- #pragma pack(pop)
- typedef struct
- {
- DLGTEMPLATEEX* lpDialog;
- Uint8 *data;
- size_t size;
- size_t used;
- WORD numbuttons;
- } WIN_DialogData;
- static SDL_bool GetButtonIndex(const SDL_MessageBoxData *messageboxdata, Uint32 flags, size_t *i)
- {
- for (*i = 0; *i < (size_t)messageboxdata->numbuttons; ++*i) {
- if (messageboxdata->buttons[*i].flags & flags) {
- return SDL_TRUE;
- }
- }
- return SDL_FALSE;
- }
- static INT_PTR MessageBoxDialogProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
- {
- const SDL_MessageBoxData *messageboxdata;
- size_t buttonindex;
- switch ( iMessage ) {
- case WM_INITDIALOG:
- if (lParam == 0) {
- EndDialog(hDlg, IDINVALPTRINIT);
- return TRUE;
- }
- messageboxdata = (const SDL_MessageBoxData *)lParam;
- SetWindowLongPtr(hDlg, GWLP_USERDATA, lParam);
- if (GetButtonIndex(messageboxdata, SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, &buttonindex)) {
- /* Focus on the first default return-key button */
- HWND buttonctl = GetDlgItem(hDlg, (int)(IDBUTTONINDEX0 + buttonindex));
- if (buttonctl == NULL) {
- EndDialog(hDlg, IDINVALPTRDLGITEM);
- }
- PostMessage(hDlg, WM_NEXTDLGCTL, (WPARAM)buttonctl, TRUE);
- } else {
- /* Give the focus to the dialog window instead */
- SetFocus(hDlg);
- }
- return FALSE;
- case WM_SETFOCUS:
- messageboxdata = (const SDL_MessageBoxData *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
- if (messageboxdata == NULL) {
- EndDialog(hDlg, IDINVALPTRSETFOCUS);
- return TRUE;
- }
- /* Let the default button be focused if there is one. Otherwise, prevent any initial focus. */
- if (GetButtonIndex(messageboxdata, SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, &buttonindex)) {
- return FALSE;
- }
- return TRUE;
- case WM_COMMAND:
- messageboxdata = (const SDL_MessageBoxData *)GetWindowLongPtr(hDlg, GWLP_USERDATA);
- if (messageboxdata == NULL) {
- EndDialog(hDlg, IDINVALPTRCOMMAND);
- return TRUE;
- }
- /* Return the ID of the button that was pushed */
- if (wParam == IDOK) {
- if (GetButtonIndex(messageboxdata, SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT, &buttonindex)) {
- EndDialog(hDlg, IDBUTTONINDEX0 + buttonindex);
- }
- } else if (wParam == IDCANCEL) {
- if (GetButtonIndex(messageboxdata, SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT, &buttonindex)) {
- EndDialog(hDlg, IDBUTTONINDEX0 + buttonindex);
- } else {
- /* Closing of window was requested by user or system. It would be rude not to comply. */
- EndDialog(hDlg, IDCLOSED);
- }
- } else if (wParam >= IDBUTTONINDEX0 && (int)wParam - IDBUTTONINDEX0 < messageboxdata->numbuttons) {
- EndDialog(hDlg, wParam);
- }
- return TRUE;
- default:
- break;
- }
- return FALSE;
- }
- static SDL_bool ExpandDialogSpace(WIN_DialogData *dialog, size_t space)
- {
- /* Growing memory in 64 KiB steps. */
- const size_t sizestep = 0x10000;
- size_t size = dialog->size;
- if (size == 0) {
- /* Start with 4 KiB or a multiple of 64 KiB to fit the data. */
- size = 0x1000;
- if (SIZE_MAX - sizestep < space) {
- size = space;
- } else if (space > size) {
- size = (space + sizestep) & ~(sizestep - 1);
- }
- } else if (SIZE_MAX - dialog->used < space) {
- SDL_OutOfMemory();
- return SDL_FALSE;
- } else if (SIZE_MAX - (dialog->used + space) < sizestep) {
- /* Close to the maximum. */
- size = dialog->used + space;
- } else if (size < dialog->used + space) {
- /* Round up to the next 64 KiB block. */
- size = dialog->used + space;
- size += sizestep - size % sizestep;
- }
- if (size > dialog->size) {
- void *data = SDL_realloc(dialog->data, size);
- if (!data) {
- SDL_OutOfMemory();
- return SDL_FALSE;
- }
- dialog->data = data;
- dialog->size = size;
- dialog->lpDialog = (DLGTEMPLATEEX*)dialog->data;
- }
- return SDL_TRUE;
- }
- static SDL_bool AlignDialogData(WIN_DialogData *dialog, size_t size)
- {
- size_t padding = (dialog->used % size);
- if (!ExpandDialogSpace(dialog, padding)) {
- return SDL_FALSE;
- }
- dialog->used += padding;
- return SDL_TRUE;
- }
- static SDL_bool AddDialogData(WIN_DialogData *dialog, const void *data, size_t size)
- {
- if (!ExpandDialogSpace(dialog, size)) {
- return SDL_FALSE;
- }
- SDL_memcpy(dialog->data+dialog->used, data, size);
- dialog->used += size;
- return SDL_TRUE;
- }
- static SDL_bool AddDialogString(WIN_DialogData *dialog, const char *string)
- {
- WCHAR *wstring;
- WCHAR *p;
- size_t count;
- SDL_bool status;
- if (!string) {
- string = "";
- }
- wstring = WIN_UTF8ToString(string);
- if (!wstring) {
- return SDL_FALSE;
- }
- /* Find out how many characters we have, including null terminator */
- count = 0;
- for (p = wstring; *p; ++p) {
- ++count;
- }
- ++count;
- status = AddDialogData(dialog, wstring, count*sizeof(WCHAR));
- SDL_free(wstring);
- return status;
- }
- static int s_BaseUnitsX;
- static int s_BaseUnitsY;
- static void Vec2ToDLU(short *x, short *y)
- {
- SDL_assert(s_BaseUnitsX != 0); /* we init in WIN_ShowMessageBox(), which is the only public function... */
- *x = MulDiv(*x, 4, s_BaseUnitsX);
- *y = MulDiv(*y, 8, s_BaseUnitsY);
- }
- 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)
- {
- DLGITEMTEMPLATEEX item;
- WORD marker = 0xFFFF;
- WORD extraData = 0;
- SDL_zero(item);
- item.style = style;
- item.exStyle = exStyle;
- item.x = x;
- item.y = y;
- item.cx = w;
- item.cy = h;
- item.id = id;
- Vec2ToDLU(&item.x, &item.y);
- Vec2ToDLU(&item.cx, &item.cy);
- if (!AlignDialogData(dialog, sizeof(DWORD))) {
- return SDL_FALSE;
- }
- if (!AddDialogData(dialog, &item, sizeof(item))) {
- return SDL_FALSE;
- }
- if (!AddDialogData(dialog, &marker, sizeof(marker))) {
- return SDL_FALSE;
- }
- if (!AddDialogData(dialog, &type, sizeof(type))) {
- return SDL_FALSE;
- }
- if (type == DLGITEMTYPEBUTTON || (type == DLGITEMTYPESTATIC && caption != NULL)) {
- if (!AddDialogString(dialog, caption)) {
- return SDL_FALSE;
- }
- } else {
- if (!AddDialogData(dialog, &marker, sizeof(marker))) {
- return SDL_FALSE;
- }
- if (!AddDialogData(dialog, &ordinal, sizeof(ordinal))) {
- return SDL_FALSE;
- }
- }
- if (!AddDialogData(dialog, &extraData, sizeof(extraData))) {
- return SDL_FALSE;
- }
- if (type == DLGITEMTYPEBUTTON) {
- dialog->numbuttons++;
- }
- ++dialog->lpDialog->cDlgItems;
- return SDL_TRUE;
- }
- static SDL_bool AddDialogStaticText(WIN_DialogData *dialog, int x, int y, int w, int h, const char *text)
- {
- DWORD style = WS_VISIBLE | WS_CHILD | SS_LEFT | SS_NOPREFIX | SS_EDITCONTROL | WS_GROUP;
- return AddDialogControl(dialog, DLGITEMTYPESTATIC, style, 0, x, y, w, h, -1, text, 0);
- }
- static SDL_bool AddDialogStaticIcon(WIN_DialogData *dialog, int x, int y, int w, int h, Uint16 ordinal)
- {
- DWORD style = WS_VISIBLE | WS_CHILD | SS_ICON | WS_GROUP;
- return AddDialogControl(dialog, DLGITEMTYPESTATIC, style, 0, x, y, w, h, -2, NULL, ordinal);
- }
- static SDL_bool AddDialogButton(WIN_DialogData *dialog, int x, int y, int w, int h, const char *text, int id, SDL_bool isDefault)
- {
- DWORD style = WS_VISIBLE | WS_CHILD | WS_TABSTOP;
- if (isDefault) {
- style |= BS_DEFPUSHBUTTON;
- } else {
- style |= BS_PUSHBUTTON;
- }
- /* The first button marks the start of the group. */
- if (dialog->numbuttons == 0) {
- style |= WS_GROUP;
- }
- return AddDialogControl(dialog, DLGITEMTYPEBUTTON, style, 0, x, y, w, h, id, text, 0);
- }
- static void FreeDialogData(WIN_DialogData *dialog)
- {
- SDL_free(dialog->data);
- SDL_free(dialog);
- }
- static WIN_DialogData *CreateDialogData(int w, int h, const char *caption)
- {
- WIN_DialogData *dialog;
- DLGTEMPLATEEX dialogTemplate;
- WORD WordToPass;
- SDL_zero(dialogTemplate);
- dialogTemplate.dlgVer = 1;
- dialogTemplate.signature = 0xffff;
- dialogTemplate.style = (WS_CAPTION | DS_CENTER | DS_SHELLFONT);
- dialogTemplate.x = 0;
- dialogTemplate.y = 0;
- dialogTemplate.cx = w;
- dialogTemplate.cy = h;
- Vec2ToDLU(&dialogTemplate.cx, &dialogTemplate.cy);
- dialog = (WIN_DialogData *)SDL_calloc(1, sizeof(*dialog));
- if (!dialog) {
- return NULL;
- }
- if (!AddDialogData(dialog, &dialogTemplate, sizeof(dialogTemplate))) {
- FreeDialogData(dialog);
- return NULL;
- }
- /* No menu */
- WordToPass = 0;
- if (!AddDialogData(dialog, &WordToPass, 2)) {
- FreeDialogData(dialog);
- return NULL;
- }
- /* No custom class */
- if (!AddDialogData(dialog, &WordToPass, 2)) {
- FreeDialogData(dialog);
- return NULL;
- }
- /* title */
- if (!AddDialogString(dialog, caption)) {
- FreeDialogData(dialog);
- return NULL;
- }
- /* Font stuff */
- {
- /*
- * We want to use the system messagebox font.
- */
- BYTE ToPass;
- NONCLIENTMETRICSA NCM;
- NCM.cbSize = sizeof(NCM);
- SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, 0, &NCM, 0);
- /* Font size - convert to logical font size for dialog parameter. */
- {
- HDC ScreenDC = GetDC(NULL);
- int LogicalPixelsY = GetDeviceCaps(ScreenDC, LOGPIXELSY);
- if (!LogicalPixelsY) /* This can happen if the application runs out of GDI handles */
- LogicalPixelsY = 72;
- WordToPass = (WORD)(-72 * NCM.lfMessageFont.lfHeight / LogicalPixelsY);
- ReleaseDC(NULL, ScreenDC);
- }
- if (!AddDialogData(dialog, &WordToPass, 2)) {
- FreeDialogData(dialog);
- return NULL;
- }
- /* Font weight */
- WordToPass = (WORD)NCM.lfMessageFont.lfWeight;
- if (!AddDialogData(dialog, &WordToPass, 2)) {
- FreeDialogData(dialog);
- return NULL;
- }
- /* italic? */
- ToPass = NCM.lfMessageFont.lfItalic;
- if (!AddDialogData(dialog, &ToPass, 1)) {
- FreeDialogData(dialog);
- return NULL;
- }
- /* charset? */
- ToPass = NCM.lfMessageFont.lfCharSet;
- if (!AddDialogData(dialog, &ToPass, 1)) {
- FreeDialogData(dialog);
- return NULL;
- }
- /* font typeface. */
- if (!AddDialogString(dialog, NCM.lfMessageFont.lfFaceName)) {
- FreeDialogData(dialog);
- return NULL;
- }
- }
- return dialog;
- }
- /* Escaping ampersands is necessary to disable mnemonics in dialog controls.
- * The caller provides a char** for dst and a size_t* for dstlen where the
- * address of the work buffer and its size will be stored. Their values must be
- * NULL and 0 on the first call. src is the string to be escaped. On error, the
- * function returns NULL and, on success, returns a pointer to the escaped
- * sequence as a read-only string that is valid until the next call or until the
- * work buffer is freed. Once all strings have been processed, it's the caller's
- * responsibilty to free the work buffer with SDL_free, even on errors.
- */
- static const char *EscapeAmpersands(char **dst, size_t *dstlen, const char *src)
- {
- char *newdst;
- size_t ampcount = 0;
- size_t srclen = 0;
- if (src == NULL) {
- return NULL;
- }
- while (src[srclen]) {
- if (src[srclen] == '&') {
- ampcount++;
- }
- srclen++;
- }
- srclen++;
- if (ampcount == 0) {
- /* Nothing to do. */
- return src;
- }
- if (SIZE_MAX - srclen < ampcount) {
- return NULL;
- }
- if (*dst == NULL || *dstlen < srclen + ampcount) {
- /* Allocating extra space in case the next strings are a bit longer. */
- size_t extraspace = SIZE_MAX - (srclen + ampcount);
- if (extraspace > 512) {
- extraspace = 512;
- }
- *dstlen = srclen + ampcount + extraspace;
- SDL_free(*dst);
- *dst = NULL;
- newdst = SDL_malloc(*dstlen);
- if (newdst == NULL) {
- return NULL;
- }
- *dst = newdst;
- } else {
- newdst = *dst;
- }
- /* The escape character is the ampersand itself. */
- while (srclen--) {
- if (*src == '&') {
- *newdst++ = '&';
- }
- *newdst++ = *src++;
- }
- return *dst;
- }
- /* This function is called if a Task Dialog is unsupported. */
- static int
- WIN_ShowOldMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
- {
- WIN_DialogData *dialog;
- int i, x, y, retval;
- HFONT DialogFont;
- SIZE Size;
- RECT TextSize;
- wchar_t* wmessage;
- TEXTMETRIC TM;
- HDC FontDC;
- INT_PTR result;
- char *ampescape = NULL;
- size_t ampescapesize = 0;
- Uint16 defbuttoncount = 0;
- Uint16 icon = 0;
- HWND ParentWindow = NULL;
- const int ButtonWidth = 88;
- const int ButtonHeight = 26;
- const int TextMargin = 16;
- const int ButtonMargin = 12;
- const int IconWidth = GetSystemMetrics(SM_CXICON);
- const int IconHeight = GetSystemMetrics(SM_CYICON);
- const int IconMargin = 20;
- if (messageboxdata->numbuttons > MAX_BUTTONS) {
- return SDL_SetError("Number of butons exceeds limit of %d", MAX_BUTTONS);
- }
- switch (messageboxdata->flags) {
- case SDL_MESSAGEBOX_ERROR:
- icon = (Uint16)(size_t)IDI_ERROR;
- break;
- case SDL_MESSAGEBOX_WARNING:
- icon = (Uint16)(size_t)IDI_WARNING;
- break;
- case SDL_MESSAGEBOX_INFORMATION:
- icon = (Uint16)(size_t)IDI_INFORMATION;
- break;
- }
- /* Jan 25th, 2013 - [email protected]
- *
- * I've tried to make this more reasonable, but I've run in to a lot
- * of nonsense.
- *
- * The original issue is the code was written in pixels and not
- * dialog units (DLUs). All DialogBox functions use DLUs, which
- * vary based on the selected font (yay).
- *
- * According to MSDN, the most reliable way to convert is via
- * MapDialogUnits, which requires an HWND, which we don't have
- * at time of template creation.
- *
- * We do however have:
- * The system font (DLU width 8 for me)
- * The font we select for the dialog (DLU width 6 for me)
- *
- * Based on experimentation, *neither* of these return the value
- * actually used. Stepping in to MapDialogUnits(), the conversion
- * is fairly clear, and uses 7 for me.
- *
- * As a result, some of this is hacky to ensure the sizing is
- * somewhat correct.
- *
- * Honestly, a long term solution is to use CreateWindow, not CreateDialog.
- *
- * In order to get text dimensions we need to have a DC with the desired font.
- * I'm assuming a dialog box in SDL is rare enough we can to the create.
- */
- FontDC = CreateCompatibleDC(0);
- {
- /* Create a duplicate of the font used in system message boxes. */
- LOGFONT lf;
- NONCLIENTMETRICS NCM;
- NCM.cbSize = sizeof(NCM);
- SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &NCM, 0);
- lf = NCM.lfMessageFont;
- DialogFont = CreateFontIndirect(&lf);
- }
- /* Select the font in to our DC */
- SelectObject(FontDC, DialogFont);
- {
- /* Get the metrics to try and figure our DLU conversion. */
- GetTextMetrics(FontDC, &TM);
- /* Calculation from the following documentation:
- * https://support.microsoft.com/en-gb/help/125681/how-to-calculate-dialog-base-units-with-non-system-based-font
- * This fixes bug 2137, dialog box calculation with a fixed-width system font
- */
- {
- SIZE extent;
- GetTextExtentPoint32A(FontDC, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 52, &extent);
- s_BaseUnitsX = (extent.cx / 26 + 1) / 2;
- }
- /*s_BaseUnitsX = TM.tmAveCharWidth + 1;*/
- s_BaseUnitsY = TM.tmHeight;
- }
- /* Measure the *pixel* size of the string. */
- wmessage = WIN_UTF8ToString(messageboxdata->message);
- SDL_zero(TextSize);
- DrawText(FontDC, wmessage, -1, &TextSize, DT_CALCRECT | DT_LEFT | DT_NOPREFIX | DT_EDITCONTROL);
- /* Add margins and some padding for hangs, etc. */
- TextSize.left += TextMargin;
- TextSize.right += TextMargin + 2;
- TextSize.top += TextMargin;
- TextSize.bottom += TextMargin + 2;
- /* Done with the DC, and the string */
- DeleteDC(FontDC);
- SDL_free(wmessage);
- /* Increase the size of the dialog by some border spacing around the text. */
- Size.cx = TextSize.right - TextSize.left;
- Size.cy = TextSize.bottom - TextSize.top;
- Size.cx += TextMargin * 2;
- Size.cy += TextMargin * 2;
- /* Make dialog wider and shift text over for the icon. */
- if (icon) {
- Size.cx += IconMargin + IconWidth;
- TextSize.left += IconMargin + IconWidth;
- TextSize.right += IconMargin + IconWidth;
- }
- /* Ensure the size is wide enough for all of the buttons. */
- if (Size.cx < messageboxdata->numbuttons * (ButtonWidth + ButtonMargin) + ButtonMargin)
- Size.cx = messageboxdata->numbuttons * (ButtonWidth + ButtonMargin) + ButtonMargin;
- /* Reset the height to the icon size if it is actually bigger than the text. */
- if (icon && Size.cy < IconMargin * 2 + IconHeight) {
- Size.cy = IconMargin * 2 + IconHeight;
- }
- /* Add vertical space for the buttons and border. */
- Size.cy += ButtonHeight + TextMargin;
- dialog = CreateDialogData(Size.cx, Size.cy, messageboxdata->title);
- if (!dialog) {
- return -1;
- }
- if (icon && ! AddDialogStaticIcon(dialog, IconMargin, IconMargin, IconWidth, IconHeight, icon)) {
- FreeDialogData(dialog);
- return -1;
- }
- if (!AddDialogStaticText(dialog, TextSize.left, TextSize.top, TextSize.right - TextSize.left, TextSize.bottom - TextSize.top, messageboxdata->message)) {
- FreeDialogData(dialog);
- return -1;
- }
- /* Align the buttons to the right/bottom. */
- x = Size.cx - (ButtonWidth + ButtonMargin) * messageboxdata->numbuttons;
- y = Size.cy - ButtonHeight - ButtonMargin;
- for (i = 0; i < messageboxdata->numbuttons; i++) {
- SDL_bool isdefault = SDL_FALSE;
- const char *buttontext;
- const SDL_MessageBoxButtonData *sdlButton;
- /* We always have to create the dialog buttons from left to right
- * so that the tab order is correct. Select the info to use
- * depending on which order was requested. */
- if (messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_LEFT_TO_RIGHT) {
- sdlButton = &messageboxdata->buttons[i];
- } else {
- sdlButton = &messageboxdata->buttons[messageboxdata->numbuttons - 1 - i];
- }
- if (sdlButton->flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) {
- defbuttoncount++;
- if (defbuttoncount == 1) {
- isdefault = SDL_TRUE;
- }
- }
- buttontext = EscapeAmpersands(&escape, &escapesize, sdlButton->text);
- /* Make sure to provide the correct ID to keep buttons indexed in the
- * same order as how they are in messageboxdata. */
- if (buttontext == NULL || !AddDialogButton(dialog, x, y, ButtonWidth, ButtonHeight, buttontext, IDBUTTONINDEX0 + (int)(sdlButton - messageboxdata->buttons), isdefault)) {
- FreeDialogData(dialog);
- SDL_free(ampescape);
- return -1;
- }
- x += ButtonWidth + ButtonMargin;
- }
- SDL_free(ampescape);
- /* If we have a parent window, get the Instance and HWND for them
- * so that our little dialog gets exclusive focus at all times. */
- if (messageboxdata->window) {
- ParentWindow = ((SDL_WindowData*)messageboxdata->window->driverdata)->hwnd;
- }
- result = DialogBoxIndirectParam(NULL, (DLGTEMPLATE*)dialog->lpDialog, ParentWindow, (DLGPROC)MessageBoxDialogProc, (LPARAM)messageboxdata);
- if (result >= IDBUTTONINDEX0 && result - IDBUTTONINDEX0 < messageboxdata->numbuttons) {
- *buttonid = messageboxdata->buttons[result - IDBUTTONINDEX0].buttonid;
- retval = 0;
- } else if (result == IDCLOSED) {
- /* Dialog window closed by user or system. */
- /* This could use a special return code. */
- retval = 0;
- *buttonid = -1;
- } else {
- if (result == 0) {
- SDL_SetError("Invalid parent window handle");
- } else if (result == -1) {
- SDL_SetError("The message box encountered an error.");
- } else if (result == IDINVALPTRINIT || result == IDINVALPTRSETFOCUS || result == IDINVALPTRCOMMAND) {
- SDL_SetError("Invalid message box pointer in dialog procedure");
- } else if (result == IDINVALPTRDLGITEM) {
- SDL_SetError("Couldn't find dialog control of the default enter-key button");
- } else {
- SDL_SetError("An unknown error occured");
- }
- retval = -1;
- }
- FreeDialogData(dialog);
- return retval;
- }
- /* TaskDialogIndirect procedure
- * This is because SDL targets Windows XP (0x501), so this is not defined in the platform SDK.
- */
- typedef HRESULT(FAR WINAPI *TASKDIALOGINDIRECTPROC)(const TASKDIALOGCONFIG *pTaskConfig, int *pnButton, int *pnRadioButton, BOOL *pfVerificationFlagChecked);
- int
- WIN_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
- {
- HWND ParentWindow = NULL;
- wchar_t *wmessage;
- wchar_t *wtitle;
- TASKDIALOGCONFIG TaskConfig;
- TASKDIALOG_BUTTON *pButtons;
- TASKDIALOG_BUTTON *pButton;
- HMODULE hComctl32;
- TASKDIALOGINDIRECTPROC pfnTaskDialogIndirect;
- HRESULT hr;
- char *ampescape = NULL;
- size_t ampescapesize = 0;
- int nButton;
- int nCancelButton;
- int i;
- if (SIZE_MAX / sizeof(TASKDIALOG_BUTTON) < messageboxdata->numbuttons) {
- return SDL_OutOfMemory();
- }
- /* If we cannot load comctl32.dll use the old messagebox! */
- hComctl32 = LoadLibrary(TEXT("comctl32.dll"));
- if (hComctl32 == NULL) {
- return WIN_ShowOldMessageBox(messageboxdata, buttonid);
- }
- /* If TaskDialogIndirect doesn't exist use the old messagebox!
- This will fail prior to Windows Vista.
- The manifest file in the application may require targeting version 6 of comctl32.dll, even
- when we use LoadLibrary here!
- If you don't want to bother with manifests, put this #pragma in your app's source code somewhere:
- pragma comment(linker,"\"/manifestdependency:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
- */
- pfnTaskDialogIndirect = (TASKDIALOGINDIRECTPROC) GetProcAddress(hComctl32, "TaskDialogIndirect");
- if (pfnTaskDialogIndirect == NULL) {
- FreeLibrary(hComctl32);
- return WIN_ShowOldMessageBox(messageboxdata, buttonid);
- }
- /* If we have a parent window, get the Instance and HWND for them
- so that our little dialog gets exclusive focus at all times. */
- if (messageboxdata->window) {
- ParentWindow = ((SDL_WindowData *) messageboxdata->window->driverdata)->hwnd;
- }
- wmessage = WIN_UTF8ToString(messageboxdata->message);
- wtitle = WIN_UTF8ToString(messageboxdata->title);
- SDL_zero(TaskConfig);
- TaskConfig.cbSize = sizeof (TASKDIALOGCONFIG);
- TaskConfig.hwndParent = ParentWindow;
- TaskConfig.dwFlags = TDF_SIZE_TO_CONTENT;
- TaskConfig.pszWindowTitle = wtitle;
- if (messageboxdata->flags & SDL_MESSAGEBOX_ERROR) {
- TaskConfig.pszMainIcon = TD_ERROR_ICON;
- } else if (messageboxdata->flags & SDL_MESSAGEBOX_WARNING) {
- TaskConfig.pszMainIcon = TD_WARNING_ICON;
- } else if (messageboxdata->flags & SDL_MESSAGEBOX_INFORMATION) {
- TaskConfig.pszMainIcon = TD_INFORMATION_ICON;
- } else {
- TaskConfig.pszMainIcon = NULL;
- }
- TaskConfig.pszContent = wmessage;
- TaskConfig.cButtons = messageboxdata->numbuttons;
- pButtons = SDL_malloc(sizeof (TASKDIALOG_BUTTON) * messageboxdata->numbuttons);
- TaskConfig.nDefaultButton = 0;
- nCancelButton = 0;
- for (i = 0; i < messageboxdata->numbuttons; i++)
- {
- const char *buttontext;
- if (messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_LEFT_TO_RIGHT) {
- pButton = &pButtons[i];
- } else {
- pButton = &pButtons[messageboxdata->numbuttons - 1 - i];
- }
- if (messageboxdata->buttons[i].flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) {
- nCancelButton = messageboxdata->buttons[i].buttonid;
- pButton->nButtonID = IDCANCEL;
- } else {
- pButton->nButtonID = IDBUTTONINDEX0 + i;
- }
- buttontext = EscapeAmpersands(&escape, &escapesize, messageboxdata->buttons[i].text);
- if (buttontext == NULL) {
- int j;
- FreeLibrary(hComctl32);
- SDL_free(ampescape);
- SDL_free(wmessage);
- SDL_free(wtitle);
- for (j = 0; j < i; j++) {
- SDL_free((wchar_t *) pButtons[j].pszButtonText);
- }
- SDL_free(pButtons);
- return -1;
- }
- pButton->pszButtonText = WIN_UTF8ToString(buttontext);
- if (messageboxdata->buttons[i].flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) {
- TaskConfig.nDefaultButton = pButton->nButtonID;
- }
- }
- TaskConfig.pButtons = pButtons;
- /* Show the Task Dialog */
- hr = pfnTaskDialogIndirect(&TaskConfig, &nButton, NULL, NULL);
- /* Free everything */
- FreeLibrary(hComctl32);
- SDL_free(ampescape);
- SDL_free(wmessage);
- SDL_free(wtitle);
- for (i = 0; i < messageboxdata->numbuttons; i++) {
- SDL_free((wchar_t *) pButtons[i].pszButtonText);
- }
- SDL_free(pButtons);
- /* Check the Task Dialog was successful and give the result */
- if (SUCCEEDED(hr)) {
- if (nButton == IDCANCEL) {
- *buttonid = nCancelButton;
- } else if (nButton >= IDBUTTONINDEX0 && nButton < IDBUTTONINDEX0 + messageboxdata->numbuttons) {
- *buttonid = messageboxdata->buttons[nButton - IDBUTTONINDEX0].buttonid;
- } else {
- *buttonid = -1;
- }
- return 0;
- }
- /* We failed showing the Task Dialog, use the old message box! */
- return WIN_ShowOldMessageBox(messageboxdata, buttonid);
- }
- #endif /* SDL_VIDEO_DRIVER_WINDOWS */
- /* vi: set ts=4 sw=4 expandtab: */
|