2 Simple DirectMedia Layer
3 Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
21 #include "../../SDL_internal.h"
23 #if SDL_VIDEO_DRIVER_OS2
25 /* Display a OS/2 message box */
28 #include "../../core/os2/SDL_os2.h"
29 #include "SDL_os2video.h"
33 #define IDD_TEXT_MESSAGE 1001
34 #define IDD_BITMAP 1002
35 #define IDD_PB_FIRST 1003
37 typedef struct _MSGBOXDLGDATA {
42 static VOID _wmInitDlg(HWND hwnd, MSGBOXDLGDATA *pDlgData)
44 HPS hps = WinGetPS(hwnd);
45 POINTL aptText[TXTBOX_COUNT];
51 ULONG ulButtonsCY = 0;
52 ULONG ulButtonsCX = 0;
57 HWND hwnd; /* Button window handle. */
58 ULONG ulCX; /* Button width in dialog coordinates. */
61 HAB hab = WinQueryAnchorBlock(hwnd);
63 /* --- Align the buttons to the right/bottom. --- */
65 /* Collect window handles of all buttons in dialog. */
66 hEnum = WinBeginEnumWindows(hwnd);
68 while ((hWndNext = WinGetNextWindow(hEnum)) != NULLHANDLE) {
69 if (WinQueryClassName(hWndNext, sizeof(acBuf), acBuf) == 0)
72 if (strcmp(acBuf, "#3") == 0) { /* Class name of button. */
73 if (cButtons < sizeof(aButtons) / sizeof(struct _BUTTON)) {
74 aButtons[cButtons].hwnd = hWndNext;
79 WinEndEnumWindows(hEnum);
81 /* Query size of text for each button, get width of each button, total
82 * buttons width (ulButtonsCX) and max. height (ulButtonsCX) in _dialog
86 for(ulIdx = 0; ulIdx < cButtons; ulIdx++) {
87 /* Query size of text in window coordinates. */
88 cbBuf = WinQueryWindowText(aButtons[ulIdx].hwnd, sizeof(acBuf), acBuf);
89 GpiQueryTextBox(hps, cbBuf, acBuf, TXTBOX_COUNT, aptText);
90 aptText[TXTBOX_TOPRIGHT].x -= aptText[TXTBOX_BOTTOMLEFT].x;
91 aptText[TXTBOX_TOPRIGHT].y -= aptText[TXTBOX_BOTTOMLEFT].y;
92 /* Convert text size to dialog coordinates. */
93 WinMapDlgPoints(hwnd, &aptText[TXTBOX_TOPRIGHT], 1, FALSE);
94 /* Add vertical and horizontal space for button's frame (dialog coord.). */
95 if (aptText[TXTBOX_TOPRIGHT].x < 30) {/* Minimal button width. */
96 aptText[TXTBOX_TOPRIGHT].x = 30;
98 aptText[TXTBOX_TOPRIGHT].x += 4;
100 aptText[TXTBOX_TOPRIGHT].y += 3;
102 aButtons[ulIdx].ulCX = aptText[TXTBOX_TOPRIGHT].x; /* Store button width */
103 ulButtonsCX += aptText[TXTBOX_TOPRIGHT].x + 2; /* Add total btn. width */
104 /* Get max. height for buttons. */
105 if (ulButtonsCY < aptText[TXTBOX_TOPRIGHT].y)
106 ulButtonsCY = aptText[TXTBOX_TOPRIGHT].y + 1;
111 /* Expand horizontal size of the window to fit all buttons and move window
112 * to the center of parent window. */
114 /* Convert total width of buttons to window coordinates. */
115 aptText[0].x = ulButtonsCX + 4;
116 WinMapDlgPoints(hwnd, &aptText[0], 1, TRUE);
117 /* Check width of the window and expand as needed. */
118 WinQueryWindowRect(hwnd, &rectlItem);
119 if (rectlItem.xRight <= aptText[0].x)
120 rectlItem.xRight = aptText[0].x;
122 /* Move window rectangle to the center of owner window. */
123 WinQueryWindowRect(pDlgData->hwndUnder, &rectl);
124 /* Left-bottom point of centered dialog on owner window. */
125 rectl.xLeft = (rectl.xRight - rectlItem.xRight) / 2;
126 rectl.yBottom = (rectl.yTop - rectlItem.yTop) / 2;
127 /* Map left-bottom point to desktop. */
128 WinMapWindowPoints(pDlgData->hwndUnder, HWND_DESKTOP, (PPOINTL)&rectl, 1);
129 WinOffsetRect(hab, &rectlItem, rectl.xLeft, rectl.yBottom);
131 /* Set new rectangle for the window. */
132 WinSetWindowPos(hwnd, HWND_TOP, rectlItem.xLeft, rectlItem.yBottom,
133 rectlItem.xRight - rectlItem.xLeft,
134 rectlItem.yTop - rectlItem.yBottom,
135 SWP_SIZE | SWP_MOVE);
137 /* Set buttons positions. */
139 /* Get horizontal position for the first button. */
140 WinMapDlgPoints(hwnd, (PPOINTL)&rectlItem, 2, FALSE); /* Win size to dlg coord. */
141 ulX = rectlItem.xRight - rectlItem.xLeft - ulButtonsCX - 2; /* First button position. */
143 /* Set positions and sizes for all buttons. */
144 for (ulIdx = 0; ulIdx < cButtons; ulIdx++) {
145 /* Get poisition and size for the button in dialog coordinates. */
148 aptText[1].x = aButtons[ulIdx].ulCX;
149 aptText[1].y = ulButtonsCY;
150 /* Convert to window coordinates. */
151 WinMapDlgPoints(hwnd, aptText, 2, TRUE);
153 WinSetWindowPos(aButtons[ulIdx].hwnd, HWND_TOP,
154 aptText[0].x, aptText[0].y, aptText[1].x, aptText[1].y,
155 SWP_MOVE | SWP_SIZE);
157 /* Offset horizontal position for the next button. */
158 ulX += aButtons[ulIdx].ulCX + 2;
161 /* Set right bound of the text to right bound of the last button and
162 * bottom bound of the text just above the buttons. */
164 aptText[2].x = 25; /* Left bound of text in dlg coordinates. */
165 aptText[2].y = ulButtonsCY + 3; /* Bottom bound of the text in dlg coords. */
166 WinMapDlgPoints(hwnd, &aptText[2], 1, TRUE); /* Convert ^^^ to win. coords */
167 hWndNext = WinWindowFromID(hwnd, IDD_TEXT_MESSAGE);
168 WinQueryWindowRect(hWndNext, &rectlItem);
169 rectlItem.xLeft = aptText[2].x;
170 rectlItem.yBottom = aptText[2].y;
171 /* Right bound of the text equals right bound of the last button. */
172 rectlItem.xRight = aptText[0].x + aptText[1].x;
173 WinSetWindowPos(hWndNext, HWND_TOP, rectlItem.xLeft, rectlItem.yBottom,
174 rectlItem.xRight - rectlItem.xLeft,
175 rectlItem.yTop - rectlItem.yBottom,
176 SWP_MOVE | SWP_SIZE);
179 MRESULT EXPENTRY DynDlgProc(HWND hwnd, USHORT message, MPARAM mp1, MPARAM mp2)
183 _wmInitDlg(hwnd, (MSGBOXDLGDATA*)mp2);
187 switch (SHORT1FROMMP(mp1)) {
189 WinDismissDlg(hwnd, FALSE);
196 return(WinDefDlgProc(hwnd, message, mp1, mp2));
202 static HWND _makeDlg(const SDL_MessageBoxData *messageboxdata)
204 SDL_MessageBoxButtonData*
205 pSDLBtnData = (SDL_MessageBoxButtonData *)messageboxdata->buttons;
206 ULONG cSDLBtnData = messageboxdata->numbuttons;
208 PSZ pszTitle = OS2_UTF8ToSys((PSZ) messageboxdata->title);
209 ULONG cbTitle = (pszTitle == NULL)? 0 : strlen(pszTitle);
210 PSZ pszText = OS2_UTF8ToSys((PSZ) messageboxdata->message);
211 ULONG cbText = (pszText == NULL)? 0 : strlen(pszText);
213 PDLGTEMPLATE pTemplate;
221 const SDL_MessageBoxColor* pSDLColors = (messageboxdata->colorScheme == NULL)?
222 NULL : messageboxdata->colorScheme->colors;
223 const SDL_MessageBoxColor* pSDLColor;
224 MSGBOXDLGDATA stDlgData;
226 /* Build a dialog tamplate in memory */
228 /* Size of template (cbTemplate). */
229 cbTemplate = sizeof(DLGTEMPLATE) + ((2 + cSDLBtnData) * sizeof(DLGTITEM)) +
230 sizeof(ULONG) + /* First item data - frame control data. */
231 cbTitle + 1 + /* First item data - frame title + ZERO. */
232 cbText + 1 + /* Second item data - ststic text + ZERO.*/
233 3; /* Third item data - system icon Id. */
234 /* Button items datas - text for buttons. */
235 for (ulIdx = 0; ulIdx < cSDLBtnData; ulIdx++) {
236 pszBtnText = (PSZ)pSDLBtnData[ulIdx].text;
237 cbTemplate += (pszBtnText == NULL)? 1 : (strlen(pszBtnText) + 1);
239 /* Presentation parameter space. */
240 if (pSDLColors != NULL)
241 cbTemplate += 26 /* PP for frame. */ + 26 /* PP for static text. */ +
242 (48 * cSDLBtnData); /* PP for buttons. */
244 /* Allocate memory for the dialog template. */
245 pTemplate = (PDLGTEMPLATE) SDL_malloc(cbTemplate);
246 /* Pointer on data for dialog items in allocated memory. */
247 pcDlgData = &((PCHAR)pTemplate)[sizeof(DLGTEMPLATE) +
248 ((2 + cSDLBtnData) * sizeof(DLGTITEM))];
251 pTemplate->cbTemplate = cbTemplate; /* size of dialog template to pass to WinCreateDlg() */
252 pTemplate->type = 0; /* Currently always 0. */
253 pTemplate->codepage = 0;
254 pTemplate->offadlgti = 14; /* Offset to array of DLGTITEMs. */
255 pTemplate->fsTemplateStatus = 0; /* Reserved field? */
257 /* Index in array of dlg items of item to get focus, */
258 /* if 0 then focus goes to first control that can have focus. */
259 pTemplate->iItemFocus = 0;
260 pTemplate->coffPresParams = 0;
262 /* First item info - frame */
263 pDlgItem = pTemplate->adlgti;
264 pDlgItem->fsItemStatus = 0; /* Reserved? */
265 /* Number of dialog item child windows owned by this item. */
266 pDlgItem->cChildren = 2 + cSDLBtnData; /* Ststic text + buttons. */
267 /* Length of class name, if 0 then offClassname contains a WC_ value. */
268 pDlgItem->cchClassName = 0;
269 pDlgItem->offClassName = (USHORT)WC_FRAME;
270 /* Length of text. */
271 pDlgItem->cchText = cbTitle + 1; /* +1 - trailing ZERO. */
272 pDlgItem->offText = pcDlgData - (PCHAR)pTemplate; /* Offset to title text. */
273 /* Copy text for the title into the dialog template. */
274 if (pszTitle != NULL) {
275 strcpy(pcDlgData, pszTitle);
279 pcDlgData += pDlgItem->cchText;
281 pDlgItem->flStyle = WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS |
282 FS_DLGBORDER | WS_SAVEBITS;
287 pDlgItem->id = DID_OK; /* An ID value? */
288 if (pSDLColors == NULL)
289 pDlgItem->offPresParams = 0;
291 /* Presentation parameter for the frame - dialog colors. */
292 pDlgItem->offPresParams = pcDlgData - (PCHAR)pTemplate;
293 ((PPRESPARAMS)pcDlgData)->cb = 22;
295 ((PPARAM)pcDlgData)->id = PP_FOREGROUNDCOLOR;
296 ((PPARAM)pcDlgData)->cb = 3;
297 ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT].b;
298 ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT].g;
299 ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT].r;
301 ((PPARAM)pcDlgData)->id = PP_BACKGROUNDCOLOR;
302 ((PPARAM)pcDlgData)->cb = 3;
303 ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_BACKGROUND].b;
304 ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_BACKGROUND].g;
305 ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_BACKGROUND].r;
309 /* Offset to ctl data. */
310 pDlgItem->offCtlData = pcDlgData - (PCHAR)pTemplate;
311 /* Put CtlData for the dialog in here */
312 *((PULONG)pcDlgData) = FCF_TITLEBAR | FCF_SYSMENU;
313 pcDlgData += sizeof(ULONG);
315 /* Second item info - static text (message). */
317 pDlgItem->fsItemStatus = 0;
318 /* No children since its a control, it could have child control */
319 /* (ex. a group box). */
320 pDlgItem->cChildren = 0;
321 /* Length of class name, 0 - offClassname contains a WC_ constant. */
322 pDlgItem->cchClassName = 0;
323 pDlgItem->offClassName = (USHORT)WC_STATIC;
325 pDlgItem->cchText = cbText + 1;
326 pDlgItem->offText = pcDlgData - (PCHAR)pTemplate; /* Offset to the text. */
327 /* Copy message text into the dialog template. */
328 if (pszText != NULL) {
329 strcpy(pcDlgData, pszText);
333 pcDlgData += pDlgItem->cchText;
335 pDlgItem->flStyle = SS_TEXT | DT_TOP | DT_LEFT | DT_WORDBREAK | WS_VISIBLE;
336 /* It will be really set in _wmInitDlg(). */
340 pDlgItem->cy = 62; /* It will be used. */
342 pDlgItem->id = IDD_TEXT_MESSAGE; /* an ID value */
343 if (pSDLColors == NULL)
344 pDlgItem->offPresParams = 0;
346 /* Presentation parameter for the static text - dialog colors. */
347 pDlgItem->offPresParams = pcDlgData - (PCHAR)pTemplate;
348 ((PPRESPARAMS)pcDlgData)->cb = 22;
350 ((PPARAM)pcDlgData)->id = PP_FOREGROUNDCOLOR;
351 ((PPARAM)pcDlgData)->cb = 3;
352 ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT].b;
353 ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT].g;
354 ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT].r;
356 ((PPARAM)pcDlgData)->id = PP_BACKGROUNDCOLOR;
357 ((PPARAM)pcDlgData)->cb = 3;
358 ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_BACKGROUND].b;
359 ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_BACKGROUND].g;
360 ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_BACKGROUND].r;
363 pDlgItem->offCtlData = 0;
365 /* Third item info - static bitmap. */
367 pDlgItem->fsItemStatus = 0;
368 pDlgItem->cChildren = 0;
369 pDlgItem->cchClassName = 0;
370 pDlgItem->offClassName = (USHORT)WC_STATIC;
372 pDlgItem->cchText = 3; /* 0xFF, low byte of the icon Id, high byte of icon Id. */
373 pDlgItem->offText = pcDlgData - (PCHAR)pTemplate; /* Offset to the Id. */
374 /* Write susyem icon ID into dialog template. */
375 *pcDlgData = 0xFF; /* First byte is 0xFF - next 2 bytes is system pointer Id. */
377 *((PUSHORT)pcDlgData) = ((messageboxdata->flags & SDL_MESSAGEBOX_ERROR) != 0)?
379 ((messageboxdata->flags & SDL_MESSAGEBOX_WARNING) != 0)?
380 SPTR_ICONWARNING : SPTR_ICONINFORMATION;
383 pDlgItem->flStyle = SS_SYSICON | WS_VISIBLE;
386 pDlgItem->y = 45; /* It will be really set in _wmInitDlg(). */
390 pDlgItem->id = IDD_BITMAP;
391 pDlgItem->offPresParams = 0;
392 pDlgItem->offCtlData = 0;
394 /* Next items - buttons. */
395 for (ulIdx = 0; ulIdx < cSDLBtnData; ulIdx++) {
398 pDlgItem->fsItemStatus = 0;
399 pDlgItem->cChildren = 0; /* No children. */
400 pDlgItem->cchClassName = 0; /* 0 - offClassname is WC_ constant. */
401 pDlgItem->offClassName = (USHORT)WC_BUTTON;
403 pszBtnText = OS2_UTF8ToSys((PSZ)pSDLBtnData[ulIdx].text);
404 cbBtnText = (pszBtnText == NULL)? 0 : strlen(pszBtnText);
405 pDlgItem->cchText = cbBtnText + 1;
406 pDlgItem->offText = pcDlgData - (PCHAR)pTemplate; /* Offset to the text. */
407 /* Copy text for the button into the dialog template. */
408 if (pszBtnText != NULL) {
409 strcpy(pcDlgData, pszBtnText);
413 pcDlgData += pDlgItem->cchText;
414 SDL_free(pszBtnText);
416 pDlgItem->flStyle = BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE;
417 if (pSDLBtnData[ulIdx].flags == SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) {
418 pDlgItem->flStyle |= BS_DEFAULT;
419 pTemplate->iItemFocus = ulIdx + 3; /* +3 - frame, static text and icon. */
420 pSDLColor = &pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED];
422 pSDLColor = &pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT];
425 /* It will be really set in _wmInitDlg() */
431 pDlgItem->id = IDD_PB_FIRST + ulIdx; /* an ID value */
432 if (pSDLColors == NULL)
433 pDlgItem->offPresParams = 0;
435 /* Presentation parameter for the button - dialog colors. */
436 pDlgItem->offPresParams = pcDlgData - (PCHAR)pTemplate;
437 ((PPRESPARAMS)pcDlgData)->cb = 44;
439 ((PPARAM)pcDlgData)->id = PP_FOREGROUNDCOLOR;
440 ((PPARAM)pcDlgData)->cb = 3;
441 ((PPARAM)pcDlgData)->ab[0] = pSDLColor->b;
442 ((PPARAM)pcDlgData)->ab[1] = pSDLColor->g;
443 ((PPARAM)pcDlgData)->ab[2] = pSDLColor->r;
445 ((PPARAM)pcDlgData)->id = PP_BACKGROUNDCOLOR;
446 ((PPARAM)pcDlgData)->cb = 3;
447 ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].b;
448 ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].g;
449 ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].r;
451 ((PPARAM)pcDlgData)->id = PP_BORDERLIGHTCOLOR;
452 ((PPARAM)pcDlgData)->cb = 3;
453 ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].b;
454 ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].g;
455 ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].r;
457 ((PPARAM)pcDlgData)->id = PP_BORDERDARKCOLOR;
458 ((PPARAM)pcDlgData)->cb = 3;
459 ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].b;
460 ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].g;
461 ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].r;
464 pDlgItem->offCtlData = 0;
466 /* Check, end of templ. data: &((PCHAR)pTemplate)[cbTemplate] == pcDlgData */
468 /* Create the dialog from template. */
469 stDlgData.cb = sizeof(MSGBOXDLGDATA);
470 stDlgData.hwndUnder = (messageboxdata->window != NULL && messageboxdata->window->driverdata != NULL)?
471 ((WINDATA *)messageboxdata->window->driverdata)->hwnd : HWND_DESKTOP;
473 hwnd = WinCreateDlg(HWND_DESKTOP, /* Parent is desktop. */
475 (PFNWP)DynDlgProc, pTemplate, &stDlgData);
484 int OS2_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid)
488 SDL_MessageBoxButtonData
489 *pSDLBtnData = (SDL_MessageBoxButtonData *)messageboxdata->buttons;
490 ULONG cSDLBtnData = messageboxdata->numbuttons;
491 BOOL fVideoInitialized = SDL_WasInit(SDL_INIT_VIDEO);
494 BOOL fSuccess = FALSE;
496 if (!fVideoInitialized) {
500 DosGetInfoBlocks(&tib, &pib);
501 if (pib->pib_ultype == 2 || pib->pib_ultype == 0) {
502 /* VIO windowable or fullscreen protect-mode session */
503 pib->pib_ultype = 3; /* Presentation Manager protect-mode session */
506 hab = WinInitialize(0);
507 if (hab == NULLHANDLE) {
508 debug_os2("WinInitialize() failed");
511 hmq = WinCreateMsgQueue(hab, 0);
512 if (hmq == NULLHANDLE) {
513 debug_os2("WinCreateMsgQueue() failed");
518 /* Create dynamic dialog. */
519 hwnd = _makeDlg(messageboxdata);
520 /* Show dialog and obtain button Id. */
521 ulRC = WinProcessDlg(hwnd);
522 /* Destroy dialog, */
523 WinDestroyWindow(hwnd);
525 if (ulRC == DID_CANCEL) {
526 /* Window closed by ESC, Alt+F4 or system menu. */
529 for (ulIdx = 0; ulIdx < cSDLBtnData; ulIdx++, pSDLBtnData++) {
530 if (pSDLBtnData->flags == SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) {
531 *buttonid = pSDLBtnData->buttonid;
537 /* Button pressed. */
538 ulRC -= IDD_PB_FIRST;
539 if (ulRC < cSDLBtnData) {
540 *buttonid = pSDLBtnData[ulRC].buttonid;
545 if (!fVideoInitialized) {
546 WinDestroyMsgQueue(hmq);
550 return (fSuccess)? 0 : -1;
553 #endif /* SDL_VIDEO_DRIVER_OS2 */
555 /* vi: set ts=4 sw=4 expandtab: */