2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2009 Sam Lantinga
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with this library; if not, write to the Free
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "SDL_config.h"
24 #define _ULS_CALLCONV_
25 #define CALLCONV _System
26 #include <unidef.h> // Unicode API
27 #include <uconv.h> // Unicode API (codepage conversion)
32 #include "SDL_video.h"
33 #include "SDL_mouse.h"
34 #include "../SDL_sysvideo.h"
35 #include "../SDL_pixels_c.h"
36 #include "../../events/SDL_events_c.h"
38 #include "SDL_os2fslib.h"
40 static ULONG ulFCFToUse =
49 static int bMouseCaptured = 0;
50 static int bMouseCapturable = 0;
51 static HPOINTER hptrGlobalPointer = NULL;
52 static HPOINTER hptrCurrentIcon = NULL;
53 static int iWindowSizeX = 320;
54 static int iWindowSizeY = 200;
55 static int bWindowResized = 0;
58 typedef struct BMPINFO
67 DECLSPEC void SDLCALL SDL_OS2FSLIB_SetFCFToUse(ULONG ulFCF)
72 // Configuration defines:
74 // We have to report empty alpha mask, otherwise SDL will select
75 // alpha blitters, and this will have unwanted results, as we don't
76 // support alpha channel in FSLib yet.
77 #define REPORT_EMPTY_ALPHA_MASK
79 // Experimental: Move every FSLib_BitBlt() call into window message
80 // processing function.
81 // This may fix dirt left on desktop. Or not.
82 //#define BITBLT_IN_WINMESSAGEPROC
84 // Experimental-2: Use WinLockWindowUpdate() in around bitblts!
85 // This is not enabled, because it seems to cause more problems
87 //#define USE_WINLOCKWINDOWUPDATE_AROUND_BITBLTS
89 // Use the following to show resized image instead of black stuff
90 // even if the surface is resizable.
91 //#define RESIZE_EVEN_IF_RESIZABLE
93 /* The translation table from a VK keysym to a SDL keysym */
94 static SDLKey HWScanKeyMap[256];
95 static SDL_keysym *TranslateKey(int vkey, int chcode, int scancode, SDL_keysym *keysym, int iPressed);
96 static int iShiftIsPressed;
98 #ifdef BITBLT_IN_WINMESSAGEPROC
99 #define WM_UPDATERECTSREQUEST WM_USER+50
102 #ifdef USE_WINLOCKWINDOWUPDATE_AROUND_BITBLTS
103 #define FSLIB_BITBLT(hwnd, buffer, top, left, width, height) \
105 WinLockWindowUpdate(HWND_DESKTOP, HWND_DESKTOP); \
106 FSLib_BitBlt(hwnd, buffer, top, left, width, height); \
107 WinLockWindowUpdate(HWND_DESKTOP, NULL); \
110 #define FSLIB_BITBLT(hwnd, buffer, top, left, width, height) \
111 FSLib_BitBlt(hwnd, buffer, top, left, width, height);
114 /////////////////////////////////////////////////////////////////////
116 // SetAccessableWindowPos
118 // Same as WinSetWindowPos(), but takes care for the window to be
119 // always on the screen, the titlebar will be accessable everytime.
121 /////////////////////////////////////////////////////////////////////
122 static BOOL SetAccessableWindowPos(HWND hwnd, HWND hwndInsertBehind,
129 WinQueryWindowPos(HWND_DESKTOP, &swpDesktop);
131 if ((fl & SWP_MOVE) && (fl & SWP_SIZE))
133 // If both moving and sizing, then change size and pos now!!
134 if (x+cx>swpDesktop.cx)
135 x = swpDesktop.cx - cx;
140 if (y+cy>swpDesktop.cy)
141 y = swpDesktop.cy - cy;
142 return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
147 WinQueryWindowPos(hwnd, &swp);
148 if (x+swp.cx>swpDesktop.cx)
149 x = swpDesktop.cx - swp.cx;
154 if (y+swp.cy>swpDesktop.cy)
155 y = swpDesktop.cy - swp.cy;
156 return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
161 WinQueryWindowPos(hwnd, &swp);
164 if (x+cx>swpDesktop.cx)
165 x = swpDesktop.cx - cx;
170 if (y+cy>swpDesktop.cy)
171 y = swpDesktop.cy - cy;
172 return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl | SWP_MOVE);
174 return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
177 static UniChar NativeCharToUniChar(int chcode)
179 UniChar ucResult = (UniChar) chcode;
188 size_t iNonIdentical;
190 // Create unicode convert object
191 rc = UniCreateUconvObject(L"", &ucoTemp);
194 // Could not create convert object!
198 // Convert language code string to unicode string
199 achFrom[0] = (char) chcode;
201 iFromCount = sizeof(char) * 2;
202 iToCount = sizeof(UniChar) * 2;
204 pchFrom = &(achFrom[0]);
206 rc = UniUconvToUcs(ucoTemp,
215 // Could not convert language code to UCS string!
216 UniFreeUconvObject(ucoTemp);
220 UniFreeUconvObject(ucoTemp);
223 printf("%02x converted to %02x\n", (int) chcode, (int) (aucTo[0]));
229 /////////////////////////////////////////////////////////////////////
233 // This creates SDL Keycodes from VK_ and hardware scan codes
235 /////////////////////////////////////////////////////////////////////
236 static SDL_keysym *TranslateKey(int vkey, int chcode, int scancode, SDL_keysym *keysym, int iPressed)
238 keysym->scancode = (unsigned char) scancode;
239 keysym->mod = KMOD_NONE;
242 if (iPressed && SDL_TranslateUNICODE)
245 keysym->unicode = NativeCharToUniChar(chcode);
247 keysym->unicode = vkey;
250 keysym->sym = HWScanKeyMap[scancode];
252 // Now stuffs based on state of shift key(s)!
253 if (vkey == VK_SHIFT)
255 iShiftIsPressed = iPressed;
258 if ((iShiftIsPressed) && (SDL_TranslateUNICODE))
260 // Change syms, if Unicode stuff is required
261 // I think it's silly, but it's SDL...
268 keysym->sym = SDLK_EXCLAIM;
271 keysym->sym = SDLK_AT;
274 keysym->sym = SDLK_HASH;
277 keysym->sym = SDLK_DOLLAR;
283 keysym->sym = SDLK_CARET;
286 keysym->sym = SDLK_AMPERSAND;
289 keysym->sym = SDLK_ASTERISK;
292 keysym->sym = SDLK_LEFTPAREN;
295 keysym->sym = SDLK_RIGHTPAREN;
298 keysym->sym = SDLK_UNDERSCORE;
301 keysym->sym = SDLK_EQUALS;
304 case SDLK_LEFTBRACKET:
307 case SDLK_RIGHTBRACKET:
312 keysym->sym = SDLK_COLON;
315 keysym->sym = SDLK_QUOTEDBL;
322 keysym->sym = SDLK_LESS;
325 keysym->sym = SDLK_GREATER;
328 keysym->sym = SDLK_QUESTION;
338 #define CONVERTMOUSEPOSITION() \
339 /* We have to inverse the mouse position, because every non-os/2 system */ \
340 /* has a coordinate system where the (0;0) is the top-left corner, */ \
341 /* while on os/2 it's the bottom left corner! */ \
342 if (FSLib_QueryFSMode(hwnd)) \
344 /* We're in FS mode! */ \
345 /* In FS mode our window is as big as fullscreen mode, but not necessary as */ \
346 /* big as the source buffer (can be bigger) */ \
347 /* So, limit mouse pos to source buffer size! */ \
348 if (ppts->x<0) ppts->x = 0; \
349 if (ppts->y<0) ppts->y = 0; \
350 if (ppts->x>=pVideo->hidden->SrcBufferDesc.uiXResolution) ppts->x = pVideo->hidden->SrcBufferDesc.uiXResolution-1; \
351 if (ppts->y>=pVideo->hidden->SrcBufferDesc.uiYResolution) ppts->y = pVideo->hidden->SrcBufferDesc.uiYResolution-1; \
352 pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */ \
353 ptl.x = ppts->x; ptl.y = ppts->y; \
354 WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1); \
355 WinSetPointerPos(HWND_DESKTOP, ptl.x, ptl.y); \
356 /* Then convert OS/2 position to SDL position */ \
357 ppts->y = pVideo->hidden->SrcBufferDesc.uiYResolution - ppts->y - 1; \
361 /* We're in windowed mode! */ \
362 WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient); \
363 /* Convert OS/2 mouse position to SDL position, and also scale it! */ \
364 (ppts->x) = (ppts->x) * pVideo->hidden->SrcBufferDesc.uiXResolution / swpClient.cx; \
365 (ppts->y) = (ppts->y) * pVideo->hidden->SrcBufferDesc.uiYResolution / swpClient.cy; \
366 (ppts->y) = pVideo->hidden->SrcBufferDesc.uiYResolution - (ppts->y) - 1; \
371 /////////////////////////////////////////////////////////////////////
375 // This is the message processing window procedure for the
376 // SDLWindowClass, which is the client window in our application.
377 // It handles switching back and away from the app (taking care of
378 // going out and back to and from fullscreen mode), sending keystrokes
379 // and mouse events to where it has to be sent, etc...
381 /////////////////////////////////////////////////////////////////////
382 static MRESULT EXPENTRY WndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
386 SDL_VideoDevice *pVideo = NULL;
390 case WM_CHAR: // Keypress notification
392 // printf("WM_CHAR\n"); fflush(stdout);
394 pVideo = WinQueryWindowPtr(hwnd, 0);
398 // We skip repeated keys:
399 if (CHARMSG(&msg)->cRepeat>1)
402 // printf("Repeated key (%d), skipping...\n", CHARMSG(&msg)->cRepeat); fflush(stdout);
404 return (MRESULT) TRUE;
408 // If it's not repeated, then let's see if its pressed or released!
409 if (SHORT1FROMMP(mp1) & KC_KEYUP)
411 // A key has been released
415 // printf("WM_CHAR, keyup, code is [0x%0x]\n", CHAR4FROMMP(mp1)); // HW scan code
418 // One problem is with F1, which gets only the keyup message because
419 // it is a system key.
420 // So, when we get keyup message, we simulate keydown too!
422 // This problem should be solved now, that the accelerator keys are
423 // disabled for this window!
425 if (SHORT2FROMMP(mp2)==VK_F1)
427 SDL_PrivateKeyboard(SDL_PRESSED, TranslateKey(SHORT2FROMMP(mp2), // VK_ code
428 SHORT1FROMMP(mp2), // Character code
429 CHAR4FROMMP(mp1), // HW Scan code
433 SDL_PrivateKeyboard(SDL_RELEASED, TranslateKey(SHORT2FROMMP(mp2), // VK_ code
434 SHORT1FROMMP(mp2), // Character code
435 CHAR4FROMMP(mp1), // HW Scan code
440 // A key has been pressed
444 // printf("WM_CHAR, keydown, code is [0x%0x]\n", CHAR4FROMMP(mp1)); // HW scan code
446 // Check for fastkeys: ALT+HOME to toggle FS mode
447 // ALT+END to close app
448 if ((SHORT1FROMMP(mp1) & KC_ALT) &&
449 (SHORT2FROMMP(mp2) == VK_HOME))
452 printf(" Pressed ALT+HOME!\n"); fflush(stdout);
454 // Only switch between fullscreen and back if it's not
457 (!pVideo->hidden->pSDLSurface) ||
458 ((pVideo->hidden->pSDLSurface)
459 && ((pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE)==0)
462 FSLib_ToggleFSMode(hwnd, !FSLib_QueryFSMode(hwnd));
465 printf(" Resizable mode, so discarding ALT+HOME!\n"); fflush(stdout);
468 if ((SHORT1FROMMP(mp1) & KC_ALT) &&
469 (SHORT2FROMMP(mp2) == VK_END))
472 printf(" Pressed ALT+END!\n"); fflush(stdout);
474 // Close window, and get out of loop!
475 // Also send event to SDL application, but we won't
476 // wait for it to be processed!
478 WinPostMsg(hwnd, WM_QUIT, 0, 0);
482 SDL_PrivateKeyboard(SDL_PRESSED, TranslateKey(SHORT2FROMMP(mp2), // VK_ code
483 SHORT1FROMMP(mp2), // Character code
484 CHAR4FROMMP(mp1), // HW Scan code
490 return (MRESULT) TRUE;
492 case WM_TRANSLATEACCEL:
498 if (pqmsg->msg == WM_CHAR)
501 // Let's filter the ALT keypress and all other acceleration keys!
502 return (MRESULT) FALSE;
505 break; // Default processing (pass to parent until frame control)
508 case WM_PAINT: // Window redraw!
510 printf("WM_PAINT (0x%x)\n", hwnd); fflush(stdout);
512 ps = WinBeginPaint(hwnd,0,&rcl);
513 pVideo = FSLib_GetUserParm(hwnd);
516 if (!pVideo->hidden->pSDLSurface)
519 // So, don't blit now!
521 printf("WM_PAINT : Skipping blit while resizing (Pre!)!\n"); fflush(stdout);
523 WinQueryWindowRect(hwnd, &rclRect);
525 WinFillRect(ps, &rclRect, CLR_BLACK);
528 if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, 1000)==NO_ERROR)
530 int iTop, iLeft, iWidth, iHeight;
531 int iXScaleError, iYScaleError;
532 int iXScaleError2, iYScaleError2;
535 // Re-blit the modified area!
536 // For this, we have to calculate the points, scaled!
537 WinQueryWindowPos(hwnd, &swp);
539 printf("WM_PAINT : WinSize: %d %d, BufSize: %d %d\n",
542 pVideo->hidden->SrcBufferDesc.uiXResolution,
543 pVideo->hidden->SrcBufferDesc.uiYResolution
548 #ifndef RESIZE_EVEN_IF_RESIZABLE
549 // But only blit if the window is not resizable, or if
550 // the window is resizable and the source buffer size is the
551 // same as the destination buffer size!
552 if ((!pVideo->hidden->pSDLSurface) ||
553 ((pVideo->hidden->pSDLSurface) &&
554 (pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
555 ((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
556 (swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
558 (!FSLib_QueryFSMode(hwnd))
563 // Resizable surface and in resizing!
564 // So, don't blit now!
566 printf("WM_PAINT : Skipping blit while resizing!\n"); fflush(stdout);
568 WinQueryWindowRect(hwnd, &rclRect);
570 WinFillRect(ps, &rclRect, CLR_BLACK);
575 iXScaleError = (pVideo->hidden->SrcBufferDesc.uiXResolution-1) / swp.cx;
576 iYScaleError = (pVideo->hidden->SrcBufferDesc.uiYResolution-1) / swp.cy;
577 if (iXScaleError<0) iXScaleError = 0;
578 if (iYScaleError<0) iYScaleError = 0;
579 iXScaleError2 = (swp.cx-1)/(pVideo->hidden->SrcBufferDesc.uiXResolution);
580 iYScaleError2 = (swp.cy-1)/(pVideo->hidden->SrcBufferDesc.uiYResolution);
581 if (iXScaleError2<0) iXScaleError2 = 0;
582 if (iYScaleError2<0) iYScaleError2 = 0;
584 iTop = (swp.cy - rcl.yTop) * pVideo->hidden->SrcBufferDesc.uiYResolution / swp.cy - iYScaleError;
585 iLeft = rcl.xLeft * pVideo->hidden->SrcBufferDesc.uiXResolution / swp.cx - iXScaleError;
586 iWidth = ((rcl.xRight-rcl.xLeft) * pVideo->hidden->SrcBufferDesc.uiXResolution + swp.cx-1)
587 / swp.cx + 2*iXScaleError;
588 iHeight = ((rcl.yTop-rcl.yBottom) * pVideo->hidden->SrcBufferDesc.uiYResolution + swp.cy-1)
589 / swp.cy + 2*iYScaleError;
591 iWidth+=iXScaleError2;
592 iHeight+=iYScaleError2;
594 if (iTop<0) iTop = 0;
595 if (iLeft<0) iLeft = 0;
596 if (iTop+iHeight>pVideo->hidden->SrcBufferDesc.uiYResolution) iHeight = pVideo->hidden->SrcBufferDesc.uiYResolution-iTop;
597 if (iLeft+iWidth>pVideo->hidden->SrcBufferDesc.uiXResolution) iWidth = pVideo->hidden->SrcBufferDesc.uiXResolution-iLeft;
600 printf("WM_PAINT : BitBlt: %d %d -> %d %d (Buf %d x %d)\n",
601 iTop, iLeft, iWidth, iHeight,
602 pVideo->hidden->SrcBufferDesc.uiXResolution,
603 pVideo->hidden->SrcBufferDesc.uiYResolution
608 FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer, iTop, iLeft, iWidth, iHeight);
611 DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
618 printf("WM_PAINT : No pVideo!\n"); fflush(stdout);
623 printf("WM_PAINT : Done.\n");
631 printf("WM_SIZE : (%d %d)\n",
632 SHORT1FROMMP(mp2), SHORT2FROMMP(mp2)); fflush(stdout);
634 iWindowSizeX = SHORT1FROMMP(mp2);
635 iWindowSizeY = SHORT2FROMMP(mp2);
638 // Make sure the window will be redrawn
639 WinInvalidateRegion(hwnd, NULL, TRUE);
643 case WM_FSLIBNOTIFICATION:
645 printf("WM_FSLIBNOTIFICATION\n"); fflush(stdout);
647 if ((int)mp1 == FSLN_TOGGLEFSMODE)
649 // FS mode changed, reblit image!
650 pVideo = FSLib_GetUserParm(hwnd);
653 if (!pVideo->hidden->pSDLSurface)
655 // Resizable surface and in resizing!
656 // So, don't blit now!
658 printf("WM_FSLIBNOTIFICATION : Can not blit if there is no surface, doing nothing.\n"); fflush(stdout);
662 if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, 1000)==NO_ERROR)
664 if (pVideo->hidden->pSDLSurface)
666 #ifndef RESIZE_EVEN_IF_RESIZABLE
669 // But only blit if the window is not resizable, or if
670 // the window is resizable and the source buffer size is the
671 // same as the destination buffer size!
672 WinQueryWindowPos(hwnd, &swp);
673 if ((!pVideo->hidden->pSDLSurface) ||
675 (pVideo->hidden->pSDLSurface) &&
676 (pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
677 ((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
678 (swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
680 (!FSLib_QueryFSMode(hwnd))
684 // Resizable surface and in resizing!
685 // So, don't blit now!
687 printf("WM_FSLIBNOTIFICATION : Cannot blit while resizing, doing nothing.\n"); fflush(stdout);
693 printf("WM_FSLIBNOTIFICATION : Blitting!\n"); fflush(stdout);
695 FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer,
697 pVideo->hidden->SrcBufferDesc.uiXResolution,
698 pVideo->hidden->SrcBufferDesc.uiYResolution);
703 printf("WM_FSLIBNOTIFICATION : No public surface!\n"); fflush(stdout);
706 DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
715 printf("WM_ACTIVATE\n"); fflush(stdout);
718 pVideo = FSLib_GetUserParm(hwnd);
721 pVideo->hidden->fInFocus = (int) mp1;
722 if (pVideo->hidden->fInFocus)
725 if ((pVideo->hidden->iMouseVisible) && (!bMouseCaptured))
726 WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
728 WinSetPointer(HWND_DESKTOP, NULL);
730 if (bMouseCapturable)
732 // Re-capture the mouse, if we captured it before!
733 WinSetCapture(HWND_DESKTOP, hwnd);
738 // Center the mouse to the middle of the window!
739 WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
740 ptl.x = 0; ptl.y = 0;
741 WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
742 pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
743 WinSetPointerPos(HWND_DESKTOP,
744 ptl.x + swpClient.cx/2,
745 ptl.y + swpClient.cy/2);
751 WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
756 WinSetCapture(HWND_DESKTOP, hwnd);
762 printf("WM_ACTIVATE done\n"); fflush(stdout);
769 printf("WM_BUTTON1DOWN\n"); fflush(stdout);
772 pVideo = FSLib_GetUserParm(hwnd);
775 SDL_PrivateMouseButton(SDL_PRESSED,
777 0, 0); // Don't report mouse movement!
779 if (bMouseCapturable)
781 // We should capture the mouse!
784 WinSetCapture(HWND_DESKTOP, hwnd);
785 WinSetPointer(HWND_DESKTOP, NULL);
790 // Center the mouse to the middle of the window!
791 WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
792 ptl.x = 0; ptl.y = 0;
793 WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
794 pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
795 WinSetPointerPos(HWND_DESKTOP,
796 ptl.x + swpClient.cx/2,
797 ptl.y + swpClient.cy/2);
805 printf("WM_BUTTON1UP\n"); fflush(stdout);
807 SDL_PrivateMouseButton(SDL_RELEASED,
809 0, 0); // Don't report mouse movement!
813 printf("WM_BUTTON2DOWN\n"); fflush(stdout);
816 pVideo = FSLib_GetUserParm(hwnd);
819 SDL_PrivateMouseButton(SDL_PRESSED,
821 0, 0); // Don't report mouse movement!
823 if (bMouseCapturable)
825 // We should capture the mouse!
828 WinSetCapture(HWND_DESKTOP, hwnd);
829 WinSetPointer(HWND_DESKTOP, NULL);
834 // Center the mouse to the middle of the window!
835 WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
836 ptl.x = 0; ptl.y = 0;
837 WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
838 pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
839 WinSetPointerPos(HWND_DESKTOP,
840 ptl.x + swpClient.cx/2,
841 ptl.y + swpClient.cy/2);
850 printf("WM_BUTTON2UP\n"); fflush(stdout);
852 SDL_PrivateMouseButton(SDL_RELEASED,
854 0, 0); // Don't report mouse movement!
858 printf("WM_BUTTON3DOWN\n"); fflush(stdout);
861 pVideo = FSLib_GetUserParm(hwnd);
864 SDL_PrivateMouseButton(SDL_PRESSED,
866 0, 0); // Don't report mouse movement!
868 if (bMouseCapturable)
870 // We should capture the mouse!
873 WinSetCapture(HWND_DESKTOP, hwnd);
874 WinSetPointer(HWND_DESKTOP, NULL);
879 // Center the mouse to the middle of the window!
880 WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
881 ptl.x = 0; ptl.y = 0;
882 WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
883 pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
884 WinSetPointerPos(HWND_DESKTOP,
885 ptl.x + swpClient.cx/2,
886 ptl.y + swpClient.cy/2);
894 printf("WM_BUTTON3UP\n"); fflush(stdout);
896 SDL_PrivateMouseButton(SDL_RELEASED,
898 0, 0); // Don't report mouse movement!
902 // printf("WM_MOUSEMOVE\n"); fflush(stdout);
905 pVideo = FSLib_GetUserParm(hwnd);
908 if (pVideo->hidden->iSkipWMMOUSEMOVE)
910 pVideo->hidden->iSkipWMMOUSEMOVE--;
913 POINTS *ppts = (POINTS *) (&mp1);
920 WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
922 // Send relative mouse position, and re-center the mouse
923 // Reposition the mouse to the center of the screen/window
924 SDL_PrivateMouseMotion(0, // Buttons not changed
925 1, // Relative position
926 ppts->x - (swpClient.cx/2),
927 (swpClient.cy/2) - ppts->y);
929 ptl.x = 0; ptl.y = 0;
930 WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
931 pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
932 // Center the mouse to the middle of the window!
933 WinSetPointerPos(HWND_DESKTOP,
934 ptl.x + swpClient.cx/2,
935 ptl.y + swpClient.cy/2);
938 CONVERTMOUSEPOSITION();
940 // Send absolute mouse position
941 SDL_PrivateMouseMotion(0, // Buttons not changed
942 0, // Absolute position
947 if ((pVideo->hidden->iMouseVisible) && (!bMouseCaptured))
950 // printf("WM_MOUSEMOVE : ptr = %p\n", hptrGlobalPointer); fflush(stdout);
953 if (hptrGlobalPointer)
954 WinSetPointer(HWND_DESKTOP, hptrGlobalPointer);
956 WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
960 WinSetPointer(HWND_DESKTOP, NULL);
964 // printf("WM_MOUSEMOVE done\n"); fflush(stdout);
967 return (MRESULT) FALSE;
968 case WM_CLOSE: // Window close
970 printf("WM_CLOSE\n"); fflush(stdout);
973 pVideo = FSLib_GetUserParm(hwnd);
976 // Send Quit message to the SDL application!
982 #ifdef BITBLT_IN_WINMESSAGEPROC
983 case WM_UPDATERECTSREQUEST:
984 pVideo = FSLib_GetUserParm(hwnd);
985 if ((pVideo) && (pVideo->hidden->pSDLSurface))
987 if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
994 numrects = (int) mp1;
995 rects = (SDL_Rect *) mp2;
997 WinQueryWindowPos(hwnd, &swp);
998 #ifndef RESIZE_EVEN_IF_RESIZABLE
999 if ((!pVideo->hidden->pSDLSurface) ||
1001 (pVideo->hidden->pSDLSurface) &&
1002 (pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
1003 ((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
1004 (swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
1006 (!FSLib_QueryFSMode(hwnd))
1010 // Resizable surface and in resizing!
1011 // So, don't blit now!
1013 printf("[WM_UPDATERECTSREQUEST] : Skipping blit while resizing!\n"); fflush(stdout);
1019 printf("[WM_UPDATERECTSREQUEST] : Blitting!\n"); fflush(stdout);
1022 // Blit the changed areas
1023 for (i=0; i<numrects; i++)
1024 FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer,
1025 rects[i].y, rects[i].x, rects[i].w, rects[i].h);
1027 DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
1035 printf("Unhandled: %x\n", msg); fflush(stdout);
1040 // Run the default window procedure for unhandled stuffs
1041 return WinDefWindowProc(hwnd, msg, mp1, mp2);
1044 /////////////////////////////////////////////////////////////////////
1048 // This is the message processing window procedure for the
1049 // frame window of SDLWindowClass.
1051 /////////////////////////////////////////////////////////////////////
1052 static MRESULT EXPENTRY FrameWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
1054 PFNWP pOldFrameProc;
1057 int cx, cy, ncx, ncy;
1061 SDL_VideoDevice *pVideo = NULL;
1063 pVideo = (SDL_VideoDevice *) WinQueryWindowULong(hwnd, QWL_USER);
1065 pOldFrameProc = pVideo->hidden->pfnOldFrameProc;
1067 if ((pVideo->hidden->bProportionalResize) &&
1068 (msg==WM_ADJUSTWINDOWPOS) &&
1069 (!FSLib_QueryFSMode(pVideo->hidden->hwndClient))
1072 pswpTemp = (PSWP) mp1;
1075 if (pswpTemp->fl & SWP_SIZE)
1077 /* Calculate client size */
1078 rclTemp.xLeft = pswpTemp->x;
1079 rclTemp.xRight = pswpTemp->x + pswpTemp->cx;
1080 rclTemp.yBottom = pswpTemp->y;
1081 rclTemp.yTop = pswpTemp->y + pswpTemp->cy;
1082 WinCalcFrameRect(hwnd, &rclTemp, TRUE);
1084 ncx = cx = rclTemp.xRight - rclTemp.xLeft;
1085 ncy = cy = rclTemp.yTop - rclTemp.yBottom;
1087 /* Calculate new size to keep it proportional */
1089 if ((pVideo->hidden->ulResizingFlag & TF_LEFT) || (pVideo->hidden->ulResizingFlag & TF_RIGHT))
1091 /* The window is resized horizontally */
1092 ncy = pVideo->hidden->SrcBufferDesc.uiYResolution * cx / pVideo->hidden->SrcBufferDesc.uiXResolution;
1094 if ((pVideo->hidden->ulResizingFlag & TF_TOP) || (pVideo->hidden->ulResizingFlag & TF_BOTTOM))
1096 /* The window is resized vertically */
1097 ncx = pVideo->hidden->SrcBufferDesc.uiXResolution * cy / pVideo->hidden->SrcBufferDesc.uiYResolution;
1100 /* Calculate back frame coordinates */
1101 rclTemp.xLeft = pswpTemp->x;
1102 rclTemp.xRight = pswpTemp->x + ncx;
1103 rclTemp.yBottom = pswpTemp->y;
1104 rclTemp.yTop = pswpTemp->y + ncy;
1105 WinCalcFrameRect(hwnd, &rclTemp, FALSE);
1107 /* Store new size/position info */
1108 pswpTemp->cx = rclTemp.xRight - rclTemp.xLeft;
1110 if (!(pVideo->hidden->ulResizingFlag & TF_TOP))
1112 pswpTemp->y = pswpTemp->y + pswpTemp->cy - (rclTemp.yTop - rclTemp.yBottom);
1113 pswpTemp->cy = rclTemp.yTop - rclTemp.yBottom;
1116 pswpTemp->cy = rclTemp.yTop - rclTemp.yBottom;
1121 result = (*pOldFrameProc)(hwnd, msg, mp1, mp2);
1123 if ((pVideo->hidden->bProportionalResize) && (msg==WM_QUERYTRACKINFO))
1125 ti = (PTRACKINFO) mp2;
1127 /* Store the direction of resizing */
1128 if ((ti->fs & TF_LEFT) || (ti->fs & TF_RIGHT) ||
1129 (ti->fs & TF_TOP) || (ti->fs & TF_BOTTOM))
1130 pVideo->hidden->ulResizingFlag = ti->fs;
1136 /////////////////////////////////////////////////////////////////////
1140 // This function implements the PM-Thread, which initializes the
1141 // application window itself, the DIVE, and start message processing.
1143 /////////////////////////////////////////////////////////////////////
1144 int iNumOfPMThreadInstances = 0; // Global!
1145 static void PMThreadFunc(void *pParm)
1147 SDL_VideoDevice *pVideo = pParm;
1154 printf("[PMThreadFunc] : Starting\n"); fflush(stdout);
1157 iNumOfPMThreadInstances++;
1159 // Initialize PM, create a message queue.
1161 hab=WinInitialize(0);
1162 hmq=WinCreateMsgQueue(hab,0);
1166 printf("[PMThreadFunc] : Could not create message queue!\n");
1167 printf(" It might be that the application using SDL is not a PM app!\n");
1170 pVideo->hidden->iPMThreadStatus = 2;
1176 fcf = ulFCFToUse; // Get from global setting
1179 printf("[PMThreadFunc] : FSLib_CreateWindow()!\n");
1183 rc = FSLib_CreateWindow(HWND_DESKTOP, 0, &fcf,
1186 &(pVideo->hidden->SrcBufferDesc),
1188 &(pVideo->hidden->hwndClient),
1189 &(pVideo->hidden->hwndFrame));
1192 printf("[PMThreadFunc] : FSLib_CreateWindow() rc = %d\n", rc);
1199 printf("[PMThreadFunc] : Could not create FSLib window!\n");
1202 pVideo->hidden->iPMThreadStatus = 3;
1206 printf("[PMThreadFunc] : FSLib_AddUserParm()!\n");
1210 // Store pVideo pointer in window data for client window, so
1211 // it will know the instance to which it belongs to.
1212 FSLib_AddUserParm(pVideo->hidden->hwndClient, pVideo);
1214 // Now set default image width height and fourcc!
1216 printf("[PMThreadFunc] : SetWindowPos()!\n");
1220 // Set the position and size of the main window,
1221 // and make it visible!
1222 // Calculate frame window size from client window size
1225 rectl.xRight = pVideo->hidden->SrcBufferDesc.uiXResolution; // Noninclusive
1226 rectl.yTop = pVideo->hidden->SrcBufferDesc.uiYResolution; // Noninclusive
1227 WinCalcFrameRect(pVideo->hidden->hwndFrame, &rectl, FALSE);
1229 SetAccessableWindowPos(pVideo->hidden->hwndFrame,
1231 (WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN) - (rectl.xRight-rectl.xLeft)) / 2,
1232 (WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN) - (rectl.yTop-rectl.yBottom)) / 2,
1233 (rectl.xRight-rectl.xLeft),
1234 (rectl.yTop-rectl.yBottom),
1235 SWP_SIZE | SWP_ACTIVATE | SWP_SHOW | SWP_MOVE);
1237 // Subclass frame procedure and store old window proc address
1238 pVideo->hidden->pfnOldFrameProc =
1239 WinSubclassWindow(pVideo->hidden->hwndFrame, FrameWndProc);
1240 WinSetWindowULong(pVideo->hidden->hwndFrame, QWL_USER, (ULONG) pVideo);
1243 printf("[PMThreadFunc] : Entering message loop\n"); fflush(stdout);
1245 pVideo->hidden->iPMThreadStatus = 1;
1247 while (WinGetMsg(hab, (PQMSG)&msg, 0, 0, 0))
1248 WinDispatchMsg(hab, (PQMSG) &msg);
1251 printf("[PMThreadFunc] : Leaving message loop\n"); fflush(stdout);
1253 // We should release the captured the mouse!
1256 WinSetCapture(HWND_DESKTOP, NULLHANDLE);
1259 // Destroy our window
1260 WinDestroyWindow(pVideo->hidden->hwndFrame); pVideo->hidden->hwndFrame=NULL;
1261 // Show pointer to make sure it will not be left hidden.
1262 WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
1263 WinShowPointer(HWND_DESKTOP, TRUE);
1266 WinDestroyMsgQueue(hmq);
1268 pVideo->hidden->iPMThreadStatus = 0;
1271 /* Commented out, should not be needed anymore, because we send it
1273 // Notify SDL that it should really die now...
1274 SDL_PrivateQuit(); SDL_PrivateQuit(); SDL_PrivateQuit(); //... :))
1277 printf("[PMThreadFunc] : End, status is %d!\n", pVideo->hidden->iPMThreadStatus); fflush(stdout);
1280 iNumOfPMThreadInstances--;
1282 // HACK to prevent zombie and hanging SDL applications, which does not take
1283 // care of closing the window for some reason:
1284 // There are some apps which do not process messages, so do a lot of things
1285 // without noticing that the application should close. To close these,
1286 // I've thought about the following:
1287 // If the window is closed (the execution came here), I wait a bit to
1288 // give time to the app to finish its execution. If it does not, I kill it
1289 // using DosExit(). Brute force, but should work.
1290 if (pVideo->hidden->iPMThreadStatus==0)
1292 DosSleep(5000); // Wait 5 secs
1293 // If a new PM thread has been spawned (reinitializing video mode), then all right.
1294 // Otherwise, we have a problem, the app doesn't want to stop. Kill!
1295 if (iNumOfPMThreadInstances==0)
1298 printf("[PMThreadFunc] : It seems that the application haven't terminated itself\n"); fflush(stdout);
1299 printf("[PMThreadFunc] : in the last 5 seconds, so we go berserk.\n"); fflush(stdout);
1300 printf("[PMThreadFunc] : Brute force mode. :) Killing process! Dieeeee...\n"); fflush(stdout);
1302 DosExit(EXIT_PROCESS, -1);
1315 /* Free a window manager cursor */
1316 void os2fslib_FreeWMCursor(_THIS, WMcursor *cursor)
1320 GpiDeleteBitmap(cursor->hbm);
1321 WinDestroyPointer(cursor->hptr);
1322 SDL_free(cursor->pchData);
1327 /* Local functions to convert the SDL cursor mask into OS/2 format */
1328 static void memnot(Uint8 *dst, Uint8 *src, int len)
1333 static void memxor(Uint8 *dst, Uint8 *src1, Uint8 *src2, int len)
1336 *dst++ = (*src1++)^(*src2++);
1339 /* Create a black/white window manager cursor */
1340 WMcursor *os2fslib_CreateWMCursor_Win(_THIS, Uint8 *data, Uint8 *mask,
1341 int w, int h, int hot_x, int hot_y)
1345 BITMAPINFOHEADER bmih;
1354 maxx = WinQuerySysValue(HWND_DESKTOP, SV_CXPOINTER);
1355 maxy = WinQuerySysValue(HWND_DESKTOP, SV_CYPOINTER);
1357 // Check for max size!
1358 if ((w>maxx) || (h>maxy))
1359 return (WMcursor *) NULL;
1361 pResult = (WMcursor *) SDL_malloc(sizeof(WMcursor));
1362 if (!pResult) return (WMcursor *) NULL;
1364 pchTemp = (char *) SDL_malloc((maxx + 7)/8 * maxy*2);
1368 return (WMcursor *) NULL;
1371 SDL_memset(pchTemp, 0, (maxx + 7)/8 * maxy*2);
1373 hps = WinGetPS(_this->hidden->hwndClient);
1375 bmi.cbFix = sizeof(BITMAPINFOHEADER);
1380 bmi.argbColor[0].bBlue = 0x00;
1381 bmi.argbColor[0].bGreen = 0x00;
1382 bmi.argbColor[0].bRed = 0x00;
1383 bmi.argbColor[1].bBlue = 0x00;
1384 bmi.argbColor[1].bGreen = 0x00;
1385 bmi.argbColor[1].bRed = 0xff;
1387 SDL_memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
1388 bmih.cbFix = sizeof(BITMAPINFOHEADER);
1395 pad = (maxx+7)/8 - run;
1399 xptr = pchTemp + (maxx+7)/8 * (maxy-1-i);
1400 aptr = pchTemp + (maxx+7)/8 * (maxy+maxy-1-i);
1401 memxor(xptr, data, mask, run);
1404 memnot(aptr, mask, run);
1407 SDL_memset(xptr, 0, pad);
1409 SDL_memset(aptr, ~0, pad);
1413 for (i=h ; i<maxy; i++ )
1415 xptr = pchTemp + (maxx+7)/8 * (maxy-1-i);
1416 aptr = pchTemp + (maxx+7)/8 * (maxy+maxy-1-i);
1418 SDL_memset(xptr, 0, (maxx+7)/8);
1420 SDL_memset(aptr, ~0, (maxx+7)/8);
1424 hbm = GpiCreateBitmap(hps, (PBITMAPINFOHEADER2)&bmih, CBM_INIT, (PBYTE) pchTemp, (PBITMAPINFO2)&bmi);
1425 hptr = WinCreatePointer(HWND_DESKTOP, hbm, TRUE, hot_x, maxy - hot_y - 1);
1428 printf("HotSpot : %d ; %d\n", hot_x, hot_y);
1429 printf("HPS returned : %x\n", (ULONG)hps);
1430 printf("HBITMAP returned : %x\n", (ULONG)hbm);
1431 printf("HPOINTER returned: %x\n", (ULONG)hptr);
1437 printf("[CreateWMCursor] : ptr = %p\n", hptr); fflush(stdout);
1440 pResult->hptr = hptr;
1442 pResult->pchData = pchTemp;
1445 printf("[CreateWMCursor] : ptr = %p return.\n", hptr); fflush(stdout);
1448 return (WMcursor *) pResult;
1451 WMcursor *os2fslib_CreateWMCursor_FS(_THIS, Uint8 *data, Uint8 *mask,
1452 int w, int h, int hot_x, int hot_y)
1455 printf("[CreateWMCursor_FS] : returning pointer NULL\n"); fflush(stdout);
1458 // In FS mode we'll use software cursor
1459 return (WMcursor *) NULL;
1462 /* Show the specified cursor, or hide if cursor is NULL */
1463 int os2fslib_ShowWMCursor(_THIS, WMcursor *cursor)
1466 printf("[ShowWMCursor] : ptr = %p\n", cursor); fflush(stdout);
1471 WinSetPointer(HWND_DESKTOP, cursor->hptr);
1472 hptrGlobalPointer = cursor->hptr;
1473 _this->hidden->iMouseVisible = 1;
1477 WinSetPointer(HWND_DESKTOP, FALSE);
1478 hptrGlobalPointer = NULL;
1479 _this->hidden->iMouseVisible = 0;
1483 printf("[ShowWMCursor] : ptr = %p, DONE\n", cursor); fflush(stdout);
1489 /* Warp the window manager cursor to (x,y)
1490 If NULL, a mouse motion event is posted internally.
1492 void os2fslib_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
1497 WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
1498 ptlPoints.x = swpClient.x;
1499 ptlPoints.y = swpClient.y;
1500 WinMapWindowPoints(_this->hidden->hwndFrame, HWND_DESKTOP, &ptlPoints, 1);
1501 lx = ptlPoints.x + (x*swpClient.cx) / _this->hidden->SrcBufferDesc.uiXResolution;
1502 ly = ptlPoints.y + swpClient.cy - ((y*swpClient.cy) / _this->hidden->SrcBufferDesc.uiYResolution) - 1;
1504 SDL_PrivateMouseMotion(0, // Buttons not changed
1505 0, // Absolute position
1509 WinSetPointerPos(HWND_DESKTOP, lx, ly);
1513 /* If not NULL, this is called when a mouse motion event occurs */
1514 void os2fslib_MoveWMCursor(_THIS, int x, int y)
1520 printf("[MoveWMCursor] : at %d ; %d\n", x, y); fflush(stdout);
1527 os2fslib_UpdateRects(_this, 1, &rect);
1532 /* Determine whether the mouse should be in relative mode or not.
1533 This function is called when the input grab state or cursor
1534 visibility state changes.
1535 If the cursor is not visible, and the input is grabbed, the
1536 driver can place the mouse in relative mode, which may result
1537 in higher accuracy sampling of the pointer motion.
1539 void os2fslib_CheckMouseMode(_THIS)
1543 static void os2fslib_PumpEvents(_THIS)
1545 // Notify SDL that if window has been resized!
1547 (_this->hidden->pSDLSurface) &&
1548 (_this->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
1550 (_this->hidden->SrcBufferDesc.uiXResolution!=iWindowSizeX) ||
1551 (_this->hidden->SrcBufferDesc.uiYResolution!=iWindowSizeY)
1557 static time_t prev_time;
1560 curr_time = time(NULL);
1561 if ((difftime(curr_time, prev_time)>=0.25) ||
1564 // Make sure we won't flood the event queue with resize events,
1565 // only send them at 250 msecs!
1566 // (or when the window is resized)
1568 printf("[os2fslib_PumpEvents] : Calling PrivateResize (%d %d).\n",
1569 iWindowSizeX, iWindowSizeY);
1572 // Tell SDL the new size
1573 SDL_PrivateResize(iWindowSizeX, iWindowSizeY);
1574 prev_time = curr_time;
1580 /* We don't actually allow hardware surfaces other than the main one */
1581 static int os2fslib_AllocHWSurface(_THIS, SDL_Surface *surface)
1585 static void os2fslib_FreeHWSurface(_THIS, SDL_Surface *surface)
1590 /* We need to wait for vertical retrace on page flipped displays */
1591 static int os2fslib_LockHWSurface(_THIS, SDL_Surface *surface)
1596 static void os2fslib_UnlockHWSurface(_THIS, SDL_Surface *surface)
1601 static int os2fslib_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
1603 printf("[os2fslib_SetColors] : TODO!\n"); fflush(stdout);
1604 // TODO: Implement paletted modes
1608 static void os2fslib_DestroyIcon(HWND hwndFrame)
1610 if (hptrCurrentIcon)
1612 WinDestroyPointer(hptrCurrentIcon);
1613 hptrCurrentIcon = NULL;
1615 WinSendMsg(hwndFrame,
1623 /* Set the window icon image */
1624 void os2fslib_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask)
1627 SDL_Surface *icon_rgb;
1630 BITMAPINFOHEADER bmih;
1634 char *pptr, *mptr, *dptr, *dmptr;
1635 int maxx, maxy, w, h, x, y;
1639 printf("[os2fslib_SetIcon] : Creating and setting new icon\n"); fflush(stdout);
1642 hwndFrame = WinQueryWindow(_this->hidden->hwndClient, QW_PARENT);
1644 // Make sure the old icon resource will be free'd!
1645 os2fslib_DestroyIcon(hwndFrame);
1647 if ((!icon) || (!mask))
1653 maxx = WinQuerySysValue(HWND_DESKTOP, SV_CXICON);
1654 maxy = WinQuerySysValue(HWND_DESKTOP, SV_CYICON);
1656 // Check for max size!
1657 if ((w>maxx) || (h>maxy))
1660 pchTemp = (char *) SDL_malloc(w * h*2 * 4);
1664 SDL_memset(pchTemp, 0, w * h*2 * 4);
1666 // Convert surface to RGB, if it's not RGB yet!
1667 icon_rgb = SDL_CreateRGBSurface(SDL_SWSURFACE, icon->w, icon->h,
1669 if ( icon_rgb == NULL )
1678 if ( SDL_LowerBlit(icon, &bounds, icon_rgb, &bounds) < 0 )
1680 SDL_FreeSurface(icon_rgb);
1685 /* Copy pixels upside-down from RGB surface into BMP, masked with the icon mask */
1688 pptr = (char *) (icon_rgb->pixels);
1694 unsigned char uchMaskByte;
1697 dptr = pchTemp + w*4 * (h-y-1);
1699 dmptr = pchTemp + w*h*4 + w*4 * (h-y-1);
1705 uchMaskByte = (unsigned char) (*mptr);
1710 if (uchMaskByte & 0x80)
1724 // Set pixels to fully transparent
1725 *dptr++ = 0; pptr++;
1726 *dptr++ = 0; pptr++;
1727 *dptr++ = 0; pptr++;
1728 *dptr++ = 0; pptr++;
1738 // There is no more need for the RGB surface
1739 SDL_FreeSurface(icon_rgb);
1741 hps = WinGetPS(_this->hidden->hwndClient);
1743 bmi.cbFix = sizeof(BITMAPINFOHEADER);
1749 SDL_memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
1750 bmih.cbFix = sizeof(BITMAPINFOHEADER);
1754 bmih.cBitCount = 32;
1756 hbm = GpiCreateBitmap(hps, (PBITMAPINFOHEADER2)&bmih, CBM_INIT, (PBYTE) pchTemp, (PBITMAPINFO2)&bmi);
1757 hptrIcon = WinCreatePointer(HWND_DESKTOP, hbm, FALSE, 0, 0);
1764 // Change icon in frame window
1765 WinSendMsg(hwndFrame,
1771 // Change icon in switchlist
1772 // Seems like it's not needed, the WM_SETICON already does it.
1775 HSWITCH hswitchFrame;
1778 WinQueryWindowProcess(hwndFrame, &pidFrame, NULL);
1779 hswitchFrame = WinQuerySwitchHandle(hwndFrame, pidFrame);
1780 WinQuerySwitchEntry(hswitchFrame, &swctl);
1782 swctl.hwndIcon = hptrIcon;
1784 WinChangeSwitchEntry(hswitchFrame, &swctl);
1788 // Store icon handle in global variable
1789 hptrCurrentIcon = hptrIcon;
1792 // ------------------------ REAL FUNCTIONS -----------------
1795 static void os2fslib_SetCursorManagementFunctions(_THIS, int iForWindowedMode)
1797 if (iForWindowedMode)
1799 _this->FreeWMCursor = os2fslib_FreeWMCursor;
1800 _this->CreateWMCursor = os2fslib_CreateWMCursor_Win;
1801 _this->ShowWMCursor = os2fslib_ShowWMCursor;
1802 _this->WarpWMCursor = os2fslib_WarpWMCursor;
1803 _this->MoveWMCursor = os2fslib_MoveWMCursor;
1804 _this->CheckMouseMode = NULL;//os2fslib_CheckMouseMode;
1807 // We'll have software mouse cursor in FS mode!
1808 _this->FreeWMCursor = os2fslib_FreeWMCursor;
1809 _this->CreateWMCursor = os2fslib_CreateWMCursor_FS;
1810 _this->ShowWMCursor = os2fslib_ShowWMCursor;
1811 _this->WarpWMCursor = os2fslib_WarpWMCursor;
1812 _this->MoveWMCursor = os2fslib_MoveWMCursor;
1813 _this->CheckMouseMode = NULL;//os2fslib_CheckMouseMode;
1817 static void os2fslib_InitOSKeymap(_THIS)
1821 iShiftIsPressed = 0;
1823 /* Map the VK and CH keysyms */
1824 for ( i=0; i<=255; ++i )
1825 HWScanKeyMap[i] = SDLK_UNKNOWN;
1827 // First line of keyboard:
1828 HWScanKeyMap[0x1] = SDLK_ESCAPE;
1829 HWScanKeyMap[0x3b] = SDLK_F1;
1830 HWScanKeyMap[0x3c] = SDLK_F2;
1831 HWScanKeyMap[0x3d] = SDLK_F3;
1832 HWScanKeyMap[0x3e] = SDLK_F4;
1833 HWScanKeyMap[0x3f] = SDLK_F5;
1834 HWScanKeyMap[0x40] = SDLK_F6;
1835 HWScanKeyMap[0x41] = SDLK_F7;
1836 HWScanKeyMap[0x42] = SDLK_F8;
1837 HWScanKeyMap[0x43] = SDLK_F9;
1838 HWScanKeyMap[0x44] = SDLK_F10;
1839 HWScanKeyMap[0x57] = SDLK_F11;
1840 HWScanKeyMap[0x58] = SDLK_F12;
1841 HWScanKeyMap[0x5d] = SDLK_PRINT;
1842 HWScanKeyMap[0x46] = SDLK_SCROLLOCK;
1843 HWScanKeyMap[0x5f] = SDLK_PAUSE;
1845 // Second line of keyboard:
1846 HWScanKeyMap[0x29] = SDLK_BACKQUOTE;
1847 HWScanKeyMap[0x2] = SDLK_1;
1848 HWScanKeyMap[0x3] = SDLK_2;
1849 HWScanKeyMap[0x4] = SDLK_3;
1850 HWScanKeyMap[0x5] = SDLK_4;
1851 HWScanKeyMap[0x6] = SDLK_5;
1852 HWScanKeyMap[0x7] = SDLK_6;
1853 HWScanKeyMap[0x8] = SDLK_7;
1854 HWScanKeyMap[0x9] = SDLK_8;
1855 HWScanKeyMap[0xa] = SDLK_9;
1856 HWScanKeyMap[0xb] = SDLK_0;
1857 HWScanKeyMap[0xc] = SDLK_MINUS;
1858 HWScanKeyMap[0xd] = SDLK_EQUALS;
1859 HWScanKeyMap[0xe] = SDLK_BACKSPACE;
1860 HWScanKeyMap[0x68] = SDLK_INSERT;
1861 HWScanKeyMap[0x60] = SDLK_HOME;
1862 HWScanKeyMap[0x62] = SDLK_PAGEUP;
1863 HWScanKeyMap[0x45] = SDLK_NUMLOCK;
1864 HWScanKeyMap[0x5c] = SDLK_KP_DIVIDE;
1865 HWScanKeyMap[0x37] = SDLK_KP_MULTIPLY;
1866 HWScanKeyMap[0x4a] = SDLK_KP_MINUS;
1868 // Third line of keyboard:
1869 HWScanKeyMap[0xf] = SDLK_TAB;
1870 HWScanKeyMap[0x10] = SDLK_q;
1871 HWScanKeyMap[0x11] = SDLK_w;
1872 HWScanKeyMap[0x12] = SDLK_e;
1873 HWScanKeyMap[0x13] = SDLK_r;
1874 HWScanKeyMap[0x14] = SDLK_t;
1875 HWScanKeyMap[0x15] = SDLK_y;
1876 HWScanKeyMap[0x16] = SDLK_u;
1877 HWScanKeyMap[0x17] = SDLK_i;
1878 HWScanKeyMap[0x18] = SDLK_o;
1879 HWScanKeyMap[0x19] = SDLK_p;
1880 HWScanKeyMap[0x1a] = SDLK_LEFTBRACKET;
1881 HWScanKeyMap[0x1b] = SDLK_RIGHTBRACKET;
1882 HWScanKeyMap[0x1c] = SDLK_RETURN;
1883 HWScanKeyMap[0x69] = SDLK_DELETE;
1884 HWScanKeyMap[0x65] = SDLK_END;
1885 HWScanKeyMap[0x67] = SDLK_PAGEDOWN;
1886 HWScanKeyMap[0x47] = SDLK_KP7;
1887 HWScanKeyMap[0x48] = SDLK_KP8;
1888 HWScanKeyMap[0x49] = SDLK_KP9;
1889 HWScanKeyMap[0x4e] = SDLK_KP_PLUS;
1891 // Fourth line of keyboard:
1892 HWScanKeyMap[0x3a] = SDLK_CAPSLOCK;
1893 HWScanKeyMap[0x1e] = SDLK_a;
1894 HWScanKeyMap[0x1f] = SDLK_s;
1895 HWScanKeyMap[0x20] = SDLK_d;
1896 HWScanKeyMap[0x21] = SDLK_f;
1897 HWScanKeyMap[0x22] = SDLK_g;
1898 HWScanKeyMap[0x23] = SDLK_h;
1899 HWScanKeyMap[0x24] = SDLK_j;
1900 HWScanKeyMap[0x25] = SDLK_k;
1901 HWScanKeyMap[0x26] = SDLK_l;
1902 HWScanKeyMap[0x27] = SDLK_SEMICOLON;
1903 HWScanKeyMap[0x28] = SDLK_QUOTE;
1904 HWScanKeyMap[0x2b] = SDLK_BACKSLASH;
1905 HWScanKeyMap[0x4b] = SDLK_KP4;
1906 HWScanKeyMap[0x4c] = SDLK_KP5;
1907 HWScanKeyMap[0x4d] = SDLK_KP6;
1909 // Fifth line of keyboard:
1910 HWScanKeyMap[0x2a] = SDLK_LSHIFT;
1911 HWScanKeyMap[0x56] = SDLK_WORLD_1; // Code 161, letter i' on hungarian keyboard
1912 HWScanKeyMap[0x2c] = SDLK_z;
1913 HWScanKeyMap[0x2d] = SDLK_x;
1914 HWScanKeyMap[0x2e] = SDLK_c;
1915 HWScanKeyMap[0x2f] = SDLK_v;
1916 HWScanKeyMap[0x30] = SDLK_b;
1917 HWScanKeyMap[0x31] = SDLK_n;
1918 HWScanKeyMap[0x32] = SDLK_m;
1919 HWScanKeyMap[0x33] = SDLK_COMMA;
1920 HWScanKeyMap[0x34] = SDLK_PERIOD;
1921 HWScanKeyMap[0x35] = SDLK_SLASH;
1922 HWScanKeyMap[0x36] = SDLK_RSHIFT;
1923 HWScanKeyMap[0x61] = SDLK_UP;
1924 HWScanKeyMap[0x4f] = SDLK_KP1;
1925 HWScanKeyMap[0x50] = SDLK_KP2;
1926 HWScanKeyMap[0x51] = SDLK_KP3;
1927 HWScanKeyMap[0x5a] = SDLK_KP_ENTER;
1929 // Sixth line of keyboard:
1930 HWScanKeyMap[0x1d] = SDLK_LCTRL;
1931 HWScanKeyMap[0x7e] = SDLK_LSUPER; // Windows key
1932 HWScanKeyMap[0x38] = SDLK_LALT;
1933 HWScanKeyMap[0x39] = SDLK_SPACE;
1934 HWScanKeyMap[0x5e] = SDLK_RALT;// Actually, altgr on my keyboard...
1935 HWScanKeyMap[0x7f] = SDLK_RSUPER;
1936 HWScanKeyMap[0x7c] = SDLK_MENU;
1937 HWScanKeyMap[0x5b] = SDLK_RCTRL;
1938 HWScanKeyMap[0x63] = SDLK_LEFT;
1939 HWScanKeyMap[0x66] = SDLK_DOWN;
1940 HWScanKeyMap[0x64] = SDLK_RIGHT;
1941 HWScanKeyMap[0x52] = SDLK_KP0;
1942 HWScanKeyMap[0x53] = SDLK_KP_PERIOD;
1946 /* Iconify the window.
1947 This function returns 1 if there is a window manager and the
1948 window was actually iconified, it returns 0 otherwise.
1950 int os2fslib_IconifyWindow(_THIS)
1956 // If there is no more window, nothing we can do!
1957 if (_this->hidden->iPMThreadStatus!=1) return 0;
1959 // Cannot do anything in fullscreen mode!
1960 if (FSLib_QueryFSMode(_this->hidden->hwndClient))
1963 // Make sure this thread is prepared for using the Presentation Manager!
1964 hab = WinInitialize(0);
1965 hmq = WinCreateMsgQueue(hab,0);
1966 // Remember if there was an error at WinCreateMsgQueue(), because we don't
1967 // want to destroy somebody else's queue later. :)
1968 hmqerror = WinGetLastError(hab);
1970 WinSetWindowPos(_this->hidden->hwndFrame, HWND_TOP,
1971 0, 0, 0, 0, SWP_MINIMIZE);
1973 // Now destroy the message queue, if we've created it!
1974 if (ERRORIDERROR(hmqerror)==0)
1975 WinDestroyMsgQueue(hmq);
1980 static SDL_GrabMode os2fslib_GrabInput(_THIS, SDL_GrabMode mode)
1987 // If there is no more window, nothing we can do!
1988 if (_this->hidden->iPMThreadStatus!=1)
1989 return SDL_GRAB_OFF;
1991 // Make sure this thread is prepared for using the Presentation Manager!
1992 hab = WinInitialize(0);
1993 hmq = WinCreateMsgQueue(hab,0);
1994 // Remember if there was an error at WinCreateMsgQueue(), because we don't
1995 // want to destroy somebody else's queue later. :)
1996 hmqerror = WinGetLastError(hab);
1999 if (mode == SDL_GRAB_OFF)
2002 printf("[os2fslib_GrabInput] : Releasing mouse\n"); fflush(stdout);
2005 // Release the mouse
2006 bMouseCapturable = 0;
2009 WinSetCapture(HWND_DESKTOP, NULLHANDLE);
2015 printf("[os2fslib_GrabInput] : Capturing mouse\n"); fflush(stdout);
2018 // Capture the mouse
2019 bMouseCapturable = 1;
2020 if (WinQueryFocus(HWND_DESKTOP) == _this->hidden->hwndClient)
2022 WinSetCapture(HWND_DESKTOP, _this->hidden->hwndClient);
2027 // Center the mouse to the middle of the window!
2028 WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
2029 ptl.x = 0; ptl.y = 0;
2030 WinMapWindowPoints(_this->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
2031 _this->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
2032 WinSetPointerPos(HWND_DESKTOP,
2033 ptl.x + swpClient.cx/2,
2034 ptl.y + swpClient.cy/2);
2039 // Now destroy the message queue, if we've created it!
2040 if (ERRORIDERROR(hmqerror)==0)
2041 WinDestroyMsgQueue(hmq);
2046 /* Set the title and icon text */
2047 static void os2fslib_SetCaption(_THIS, const char *title, const char *icon)
2053 // If there is no more window, nothing we can do!
2054 if (_this->hidden->iPMThreadStatus!=1) return;
2056 // Make sure this thread is prepared for using the Presentation Manager!
2057 hab = WinInitialize(0);
2058 hmq = WinCreateMsgQueue(hab,0);
2059 // Remember if there was an error at WinCreateMsgQueue(), because we don't
2060 // want to destroy somebody else's queue later. :)
2061 hmqerror = WinGetLastError(hab);
2063 WinSetWindowText(_this->hidden->hwndFrame, (char *) title);
2065 // Now destroy the message queue, if we've created it!
2066 if (ERRORIDERROR(hmqerror)==0)
2067 WinDestroyMsgQueue(hmq);
2070 static int os2fslib_ToggleFullScreen(_THIS, int on)
2073 printf("[os2fslib_ToggleFullScreen] : %d\n", on); fflush(stdout);
2075 // If there is no more window, nothing we can do!
2076 if (_this->hidden->iPMThreadStatus!=1) return 0;
2078 FSLib_ToggleFSMode(_this->hidden->hwndClient, on);
2079 /* Cursor manager functions to Windowed/FS mode*/
2080 os2fslib_SetCursorManagementFunctions(_this, !on);
2084 /* This is called after the video mode has been set, to get the
2085 initial mouse state. It should queue events as necessary to
2086 properly represent the current mouse focus and position.
2088 static void os2fslib_UpdateMouse(_THIS)
2096 // If there is no more window, nothing we can do!
2097 if (_this->hidden->iPMThreadStatus!=1) return;
2100 // Make sure this thread is prepared for using the Presentation Manager!
2101 hab = WinInitialize(0);
2102 hmq = WinCreateMsgQueue(hab,0);
2103 // Remember if there was an error at WinCreateMsgQueue(), because we don't
2104 // want to destroy somebody else's queue later. :)
2105 hmqerror = WinGetLastError(hab);
2109 if (_this->hidden->fInFocus)
2111 // If our app is in focus
2112 SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
2113 SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
2114 SDL_PrivateAppActive(1, SDL_APPACTIVE);
2115 WinQueryPointerPos(HWND_DESKTOP, &ptl);
2116 WinMapWindowPoints(HWND_DESKTOP, _this->hidden->hwndClient, &ptl, 1);
2117 WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
2118 // Convert OS/2 mouse position to SDL position, and also scale it!
2119 ptl.x = ptl.x * _this->hidden->SrcBufferDesc.uiXResolution / swpClient.cx;
2120 ptl.y = ptl.y * _this->hidden->SrcBufferDesc.uiYResolution / swpClient.cy;
2121 ptl.y = _this->hidden->SrcBufferDesc.uiYResolution - ptl.y - 1;
2122 SDL_PrivateMouseMotion(0, 0, (Sint16) (ptl.x), (Sint16) (ptl.y));
2125 // If we're not in focus
2126 SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
2127 SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
2128 SDL_PrivateAppActive(0, SDL_APPACTIVE);
2129 SDL_PrivateMouseMotion(0, 0, (Sint16) -1, (Sint16) -1);
2132 // Now destroy the message queue, if we've created it!
2133 if (ERRORIDERROR(hmqerror)==0)
2134 WinDestroyMsgQueue(hmq);
2138 /* This pointer should exist in the native video subsystem and should
2139 point to an appropriate update function for the current video mode
2141 static void os2fslib_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
2143 // If there is no more window, nothing we can do!
2144 if (_this->hidden->iPMThreadStatus!=1) return;
2146 #ifdef BITBLT_IN_WINMESSAGEPROC
2147 WinSendMsg(_this->hidden->hwndClient,
2148 WM_UPDATERECTSREQUEST,
2152 if (DosRequestMutexSem(_this->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
2156 if (_this->hidden->pSDLSurface)
2158 #ifndef RESIZE_EVEN_IF_RESIZABLE
2160 // But only blit if the window is not resizable, or if
2161 // the window is resizable and the source buffer size is the
2162 // same as the destination buffer size!
2163 WinQueryWindowPos(_this->hidden->hwndClient, &swp);
2164 if ((_this->hidden->pSDLSurface) &&
2165 (_this->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
2166 ((swp.cx != _this->hidden->SrcBufferDesc.uiXResolution) ||
2167 (swp.cy != _this->hidden->SrcBufferDesc.uiYResolution)
2169 (!FSLib_QueryFSMode(_this->hidden->hwndClient))
2172 // Resizable surface and in resizing!
2173 // So, don't blit now!
2175 printf("[UpdateRects] : Skipping blit while resizing!\n"); fflush(stdout);
2181 // Blit the whole window
2182 FSLIB_BITBLT(_this->hidden->hwndClient, _this->hidden->pchSrcBuffer,
2184 _this->hidden->SrcBufferDesc.uiXResolution,
2185 _this->hidden->SrcBufferDesc.uiYResolution);
2188 printf("[os2fslib_UpdateRects] : Blitting!\n"); fflush(stdout);
2191 // Blit the changed areas
2192 for (i=0; i<numrects; i++)
2193 FSLIB_BITBLT(_this->hidden->hwndClient, _this->hidden->pchSrcBuffer,
2194 rects[i].y, rects[i].x, rects[i].w, rects[i].h);
2199 printf("[os2fslib_UpdateRects] : No public surface!\n"); fflush(stdout);
2201 DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
2205 printf("[os2fslib_UpdateRects] : Error in mutex!\n"); fflush(stdout);
2211 /* Reverse the effects VideoInit() -- called if VideoInit() fails
2212 or if the application is shutting down the video subsystem.
2214 static void os2fslib_VideoQuit(_THIS)
2217 printf("[os2fslib_VideoQuit]\n"); fflush(stdout);
2219 // Close PM stuff if running!
2220 if (_this->hidden->iPMThreadStatus == 1)
2223 WinPostMsg(_this->hidden->hwndFrame, WM_QUIT, (MPARAM) 0, (MPARAM) 0);
2224 // HACK: We had this line before:
2225 //DosWaitThread((TID *) &(_this->hidden->tidPMThread), DCWW_WAIT);
2226 // We don't use it, because the PMThread will never stop, or if it stops,
2227 // it will kill the whole process as a emergency fallback.
2228 // So, we only check for the iPMThreadStatus stuff!
2230 printf("[os2fslib_VideoQuit] : Waiting for PM thread to die\n"); fflush(stdout);
2234 while ((_this->hidden->iPMThreadStatus == 1) && (iTimeout<100))
2241 printf("[os2fslib_VideoQuit] : End of wait.\n"); fflush(stdout);
2244 if (_this->hidden->iPMThreadStatus == 1)
2247 printf("[os2fslib_VideoQuit] : Killing PM thread!\n"); fflush(stdout);
2250 _this->hidden->iPMThreadStatus = 0;
2251 DosKillThread(_this->hidden->tidPMThread);
2253 if (_this->hidden->hwndFrame)
2256 printf("[os2fslib_VideoQuit] : Destroying PM window!\n"); fflush(stdout);
2259 WinDestroyWindow(_this->hidden->hwndFrame); _this->hidden->hwndFrame=NULL;
2265 // Free result of an old ListModes() call, because there is
2266 // no FreeListModes() call in SDL!
2267 if (_this->hidden->pListModesResult)
2269 SDL_free(_this->hidden->pListModesResult); _this->hidden->pListModesResult = NULL;
2272 // Free list of available fullscreen modes
2273 if (_this->hidden->pAvailableFSLibVideoModes)
2275 FSLib_FreeVideoModeList(_this->hidden->pAvailableFSLibVideoModes);
2276 _this->hidden->pAvailableFSLibVideoModes = NULL;
2279 // Free application icon if we had one
2280 if (hptrCurrentIcon)
2282 WinDestroyPointer(hptrCurrentIcon);
2283 hptrCurrentIcon = NULL;
2287 /* Set the requested video mode, returning a surface which will be
2288 set to the SDL_VideoSurface. The width and height will already
2289 be verified by ListModes(), and the video subsystem is free to
2290 set the mode to a supported bit depth different from the one
2291 specified -- the desired bpp will be emulated with a shadow
2292 surface if necessary. If a new mode is returned, this function
2293 should take care of cleaning up the current mode.
2295 static SDL_Surface *os2fslib_SetVideoMode(_THIS, SDL_Surface *current,
2296 int width, int height, int bpp, Uint32 flags)
2298 static int bFirstCall = 1;
2299 FSLib_VideoMode_p pModeInfo, pModeInfoFound;
2300 FSLib_VideoMode TempModeInfo;
2305 SDL_Surface *pResult;
2307 // If there is no more window, nothing we can do!
2308 if (_this->hidden->iPMThreadStatus!=1) return NULL;
2311 printf("[os2fslib_SetVideoMode] : Request for %dx%d @ %dBPP, flags=0x%x\n", width, height, bpp, flags); fflush(stdout);
2314 // We don't support palette modes!
2317 // Also, we don't support resizable modes in fullscreen mode.
2318 if (flags & SDL_RESIZABLE)
2319 flags &= ~SDL_FULLSCREEN;
2321 // No double buffered mode
2322 if (flags & SDL_DOUBLEBUF)
2323 flags &= ~SDL_DOUBLEBUF;
2325 // And, we don't support HWSURFACE yet.
2326 if (flags & SDL_HWSURFACE)
2328 flags &= ~SDL_HWSURFACE;
2329 flags |= SDL_SWSURFACE;
2333 printf("[os2fslib_SetVideoMode] : Changed request to %dx%d @ %dBPP, flags=0x%x\n", width, height, bpp, flags); fflush(stdout);
2336 // First check if there is such a video mode they want!
2337 pModeInfoFound = NULL;
2339 // For fullscreen mode we don't support every resolution!
2340 // So, go through the video modes, and check for such a resolution!
2341 pModeInfoFound = NULL;
2342 pModeInfo = _this->hidden->pAvailableFSLibVideoModes;
2346 // Check all available fullscreen modes for this resolution
2347 if ((pModeInfo->uiXResolution == width) &&
2348 (pModeInfo->uiYResolution == height) &&
2349 (pModeInfo->uiBPP!=8)) // palettized modes not yet supported
2351 // If good resolution, try to find the exact BPP, or at least
2352 // something similar...
2353 if (!pModeInfoFound)
2354 pModeInfoFound = pModeInfo;
2356 if ((pModeInfoFound->uiBPP!=bpp) &&
2357 (pModeInfoFound->uiBPP<pModeInfo->uiBPP))
2358 pModeInfoFound = pModeInfo;
2360 pModeInfo = pModeInfo->pNext;
2363 // If we did not find a good fullscreen mode, then try a similar
2364 if (!pModeInfoFound)
2367 printf("[os2fslib_SetVideoMode] : Requested video mode not found, looking for a similar one!\n"); fflush(stdout);
2369 // Go through the video modes again, and find a similar resolution!
2370 pModeInfo = _this->hidden->pAvailableFSLibVideoModes;
2373 // Check all available fullscreen modes for this resolution
2374 if ((pModeInfo->uiXResolution >= width) &&
2375 (pModeInfo->uiYResolution >= height) &&
2376 (pModeInfo->uiBPP == bpp))
2378 if (!pModeInfoFound)
2379 pModeInfoFound = pModeInfo;
2381 if (((pModeInfoFound->uiXResolution-width)*(pModeInfoFound->uiYResolution-height))>
2382 ((pModeInfo->uiXResolution-width)*(pModeInfo->uiYResolution-height)))
2384 // Found a mode which is closer than the current one
2385 pModeInfoFound = pModeInfo;
2388 pModeInfo = pModeInfo->pNext;
2392 // If we did not find a good fullscreen mode, then return NULL
2393 if (!pModeInfoFound)
2396 printf("[os2fslib_SetVideoMode] : Requested video mode not found!\n"); fflush(stdout);
2402 printf("[os2fslib_SetVideoMode] : Found mode!\n"); fflush(stdout);
2405 // We'll possibly adjust the structure, so copy out the values
2406 // into TempModeInfo!
2407 SDL_memcpy(&TempModeInfo, pModeInfoFound, sizeof(TempModeInfo));
2408 pModeInfoFound = &TempModeInfo;
2410 if (flags & SDL_RESIZABLE)
2413 printf("[os2fslib_SetVideoMode] : Requested mode is resizable, changing width/height\n"); fflush(stdout);
2415 // Change width and height to requested one!
2416 TempModeInfo.uiXResolution = width;
2417 TempModeInfo.uiYResolution = height;
2418 TempModeInfo.uiScanLineSize = width * ((TempModeInfo.uiBPP+7)/8);
2421 // We can try create new surface!
2423 // Make sure this thread is prepared for using the Presentation Manager!
2424 hab = WinInitialize(0);
2425 hmq = WinCreateMsgQueue(hab,0);
2426 // Remember if there was an error at WinCreateMsgQueue(), because we don't
2427 // want to destroy somebody else's queue later. :)
2428 hmqerror = WinGetLastError(hab);
2432 if (DosRequestMutexSem(_this->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
2435 printf("[os2fslib_SetVideoMode] : Creating new SW surface\n"); fflush(stdout);
2438 // Create new software surface!
2439 pResult = SDL_CreateRGBSurface(SDL_SWSURFACE,
2440 pModeInfoFound->uiXResolution,
2441 pModeInfoFound->uiYResolution,
2442 pModeInfoFound->uiBPP,
2443 ((unsigned int) pModeInfoFound->PixelFormat.ucRedMask) << pModeInfoFound->PixelFormat.ucRedPosition,
2444 ((unsigned int) pModeInfoFound->PixelFormat.ucGreenMask) << pModeInfoFound->PixelFormat.ucGreenPosition,
2445 ((unsigned int) pModeInfoFound->PixelFormat.ucBlueMask) << pModeInfoFound->PixelFormat.ucBluePosition,
2446 ((unsigned int) pModeInfoFound->PixelFormat.ucAlphaMask) << pModeInfoFound->PixelFormat.ucAlphaPosition);
2448 if (pResult == NULL)
2450 DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
2456 printf("[os2fslib_SetVideoMode] : Adjusting pixel format\n"); fflush(stdout);
2459 // Adjust pixel format mask!
2460 pResult->format->Rmask = ((unsigned int) pModeInfoFound->PixelFormat.ucRedMask) << pModeInfoFound->PixelFormat.ucRedPosition;
2461 pResult->format->Rshift = pModeInfoFound->PixelFormat.ucRedPosition;
2462 pResult->format->Rloss = pModeInfoFound->PixelFormat.ucRedAdjust;
2463 pResult->format->Gmask = ((unsigned int) pModeInfoFound->PixelFormat.ucGreenMask) << pModeInfoFound->PixelFormat.ucGreenPosition;
2464 pResult->format->Gshift = pModeInfoFound->PixelFormat.ucGreenPosition;
2465 pResult->format->Gloss = pModeInfoFound->PixelFormat.ucGreenAdjust;
2466 pResult->format->Bmask = ((unsigned int) pModeInfoFound->PixelFormat.ucBlueMask) << pModeInfoFound->PixelFormat.ucBluePosition;
2467 pResult->format->Bshift = pModeInfoFound->PixelFormat.ucBluePosition;
2468 pResult->format->Bloss = pModeInfoFound->PixelFormat.ucBlueAdjust;
2469 pResult->format->Amask = ((unsigned int) pModeInfoFound->PixelFormat.ucAlphaMask) << pModeInfoFound->PixelFormat.ucAlphaPosition;
2470 pResult->format->Ashift = pModeInfoFound->PixelFormat.ucAlphaPosition;
2471 pResult->format->Aloss = pModeInfoFound->PixelFormat.ucAlphaAdjust;
2473 #ifdef REPORT_EMPTY_ALPHA_MASK
2474 pResult->format->Amask =
2475 pResult->format->Ashift =
2476 pResult->format->Aloss = 0;
2479 // Adjust surface flags
2480 pResult->flags |= (flags & SDL_FULLSCREEN);
2481 pResult->flags |= (flags & SDL_RESIZABLE);
2483 // It might be that the software surface pitch is not the same as
2484 // the pitch we have, so adjust that!
2485 pModeInfoFound->uiScanLineSize = pResult->pitch;
2487 // Store new source buffer parameters!
2488 SDL_memcpy(&(_this->hidden->SrcBufferDesc), pModeInfoFound, sizeof(*pModeInfoFound));
2489 _this->hidden->pchSrcBuffer = pResult->pixels;
2492 printf("[os2fslib_SetVideoMode] : Telling FSLib the stuffs\n"); fflush(stdout);
2495 // Tell the FSLib window the new source image format
2496 FSLib_SetSrcBufferDesc(_this->hidden->hwndClient, &(_this->hidden->SrcBufferDesc));
2499 ((flags & SDL_RESIZABLE)==0) ||
2505 printf("[os2fslib_SetVideoMode] : Modifying window size\n"); fflush(stdout);
2508 // Calculate frame window size from client window size
2511 rectl.xRight = pModeInfoFound->uiXResolution; // Noninclusive
2512 rectl.yTop = pModeInfoFound->uiYResolution; // Noninclusive
2513 WinCalcFrameRect(_this->hidden->hwndFrame, &rectl, FALSE);
2515 // Set the new size of the main window
2516 SetAccessableWindowPos(_this->hidden->hwndFrame,
2519 (rectl.xRight-rectl.xLeft),
2520 (rectl.yTop-rectl.yBottom),
2521 SWP_SIZE | SWP_ACTIVATE | SWP_SHOW);
2524 // Set fullscreen mode flag, and switch to fullscreen if needed!
2525 if (flags & SDL_FULLSCREEN)
2528 printf("[os2fslib_SetVideoMode] : Also trying to switch to fullscreen\n");
2531 FSLib_ToggleFSMode(_this->hidden->hwndClient, 1);
2532 /* Cursor manager functions to FS mode*/
2533 os2fslib_SetCursorManagementFunctions(_this, 0);
2537 printf("[os2fslib_SetVideoMode] : Also trying to switch to desktop mode\n");
2540 FSLib_ToggleFSMode(_this->hidden->hwndClient, 0);
2541 /* Cursor manager functions to Windowed mode*/
2542 os2fslib_SetCursorManagementFunctions(_this, 1);
2545 _this->hidden->pSDLSurface = pResult;
2547 DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
2551 printf("[os2fslib_SetVideoMode] : Could not get hmtxUseSrcBuffer!\n"); fflush(stdout);
2557 // As we have the new surface, we don't need the current one anymore!
2558 if ((pResult) && (current))
2561 printf("[os2fslib_SetVideoMode] : Freeing old surface\n"); fflush(stdout);
2563 SDL_FreeSurface(current);
2567 WinInvalidateRegion(_this->hidden->hwndClient, NULL, TRUE);
2569 // Now destroy the message queue, if we've created it!
2570 if (ERRORIDERROR(hmqerror)==0)
2573 printf("[os2fslib_SetVideoMode] : Destroying message queue\n"); fflush(stdout);
2575 WinDestroyMsgQueue(hmq);
2579 printf("[os2fslib_SetVideoMode] : Done\n"); fflush(stdout);
2584 // Return with the new surface!
2588 /* List the available video modes for the given pixel format, sorted
2589 from largest to smallest.
2591 static SDL_Rect **os2fslib_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
2594 printf("[os2fslib_ListModes] : ListModes of %d Bpp\n", format->BitsPerPixel);
2596 // Destroy result of previous call, if there is any
2597 if (_this->hidden->pListModesResult)
2599 SDL_free(_this->hidden->pListModesResult); _this->hidden->pListModesResult = NULL;
2602 // For resizable and windowed mode we support every resolution!
2603 if ((flags & SDL_RESIZABLE) && ((flags & SDL_FULLSCREEN) == 0))
2604 return (SDL_Rect **)-1;
2606 // Check if they need fullscreen or non-fullscreen video modes!
2607 if ((flags & SDL_FULLSCREEN) == 0)
2610 // For windowed mode we support every resolution!
2611 return (SDL_Rect **)-1;
2614 FSLib_VideoMode_p pFSMode;
2615 // For fullscreen mode we don't support every resolution!
2616 // Now create a new list
2617 pFSMode = _this->hidden->pAvailableFSLibVideoModes;
2620 if (pFSMode->uiBPP == format->BitsPerPixel)
2622 SDL_Rect *pRect = (SDL_Rect *) SDL_malloc(sizeof(SDL_Rect));
2628 pRect->w = pFSMode->uiXResolution;
2629 pRect->h = pFSMode->uiYResolution;
2631 // printf("!!! Seems to be good!\n");
2632 // printf("F: %dx%d\n", pRect->w, pRect->h);
2634 // And insert into list of pRects
2635 if (!(_this->hidden->pListModesResult))
2638 // printf("!!! Inserting to beginning\n");
2641 // We're the first one to be inserted!
2642 _this->hidden->pListModesResult = (SDL_Rect**) SDL_malloc(2*sizeof(SDL_Rect*));
2643 if (_this->hidden->pListModesResult)
2645 _this->hidden->pListModesResult[0] = pRect;
2646 _this->hidden->pListModesResult[1] = NULL;
2653 // We're not the first ones, so find the place where we
2654 // have to insert ourselves
2655 SDL_Rect **pNewList;
2656 int iPlace, iNumOfSlots, i;
2659 // printf("!!! Searching where to insert\n");
2662 iPlace = -1; iNumOfSlots = 1; // Count the last NULL too!
2663 for (i=0; _this->hidden->pListModesResult[i]; i++)
2668 if ((_this->hidden->pListModesResult[i]->w*_this->hidden->pListModesResult[i]->h)<
2669 (pRect->w*pRect->h))
2675 if (iPlace==-1) iPlace = iNumOfSlots-1;
2678 // printf("!!! From %d slots, it will be at %d\n", iNumOfSlots, iPlace);
2681 pNewList = (SDL_Rect**) SDL_realloc(_this->hidden->pListModesResult, (iNumOfSlots+1)*sizeof(SDL_Rect*));
2684 for (i=iNumOfSlots;i>iPlace;i--)
2685 pNewList[i] = pNewList[i-1];
2686 pNewList[iPlace] = pRect;
2687 _this->hidden->pListModesResult = pNewList;
2695 pFSMode = pFSMode->pNext;
2699 // printf("Returning list\n");
2701 return _this->hidden->pListModesResult;
2704 /* Initialize the native video subsystem, filling 'vformat' with the
2705 "best" display pixel format, returning 0 or -1 if there's an error.
2707 static int os2fslib_VideoInit(_THIS, SDL_PixelFormat *vformat)
2709 FSLib_VideoMode_p pDesktopMode;
2712 printf("[os2fslib_VideoInit] : Enter\n"); fflush(stdout);
2715 // Report the best pixel format. For this,
2716 // we'll use the current desktop format.
2717 pDesktopMode = FSLib_GetDesktopVideoMode();
2720 SDL_SetError("Could not query desktop video mode!");
2722 printf("[os2fslib_VideoInit] : Could not query desktop video mode!\n");
2727 /* Determine the current screen size */
2728 _this->info.current_w = pDesktopMode->uiXResolution;
2729 _this->info.current_h = pDesktopMode->uiYResolution;
2731 /* Determine the screen depth */
2732 vformat->BitsPerPixel = pDesktopMode->uiBPP;
2733 vformat->BytesPerPixel = (vformat->BitsPerPixel+7)/8;
2735 vformat->Rmask = ((unsigned int) pDesktopMode->PixelFormat.ucRedMask) << pDesktopMode->PixelFormat.ucRedPosition;
2736 vformat->Rshift = pDesktopMode->PixelFormat.ucRedPosition;
2737 vformat->Rloss = pDesktopMode->PixelFormat.ucRedAdjust;
2738 vformat->Gmask = ((unsigned int) pDesktopMode->PixelFormat.ucGreenMask) << pDesktopMode->PixelFormat.ucGreenPosition;
2739 vformat->Gshift = pDesktopMode->PixelFormat.ucGreenPosition;
2740 vformat->Gloss = pDesktopMode->PixelFormat.ucGreenAdjust;
2741 vformat->Bmask = ((unsigned int) pDesktopMode->PixelFormat.ucBlueMask) << pDesktopMode->PixelFormat.ucBluePosition;
2742 vformat->Bshift = pDesktopMode->PixelFormat.ucBluePosition;
2743 vformat->Bloss = pDesktopMode->PixelFormat.ucBlueAdjust;
2744 vformat->Amask = ((unsigned int) pDesktopMode->PixelFormat.ucAlphaMask) << pDesktopMode->PixelFormat.ucAlphaPosition;
2745 vformat->Ashift = pDesktopMode->PixelFormat.ucAlphaPosition;
2746 vformat->Aloss = pDesktopMode->PixelFormat.ucAlphaAdjust;
2748 #ifdef REPORT_EMPTY_ALPHA_MASK
2754 // Fill in some window manager capabilities
2755 _this->info.wm_available = 1;
2757 // Initialize some internal variables
2758 _this->hidden->pListModesResult = NULL;
2759 _this->hidden->fInFocus = 0;
2760 _this->hidden->iSkipWMMOUSEMOVE = 0;
2761 _this->hidden->iMouseVisible = 1;
2763 if (getenv("SDL_USE_PROPORTIONAL_WINDOW"))
2764 _this->hidden->bProportionalResize = 1;
2769 char *pchFileName, *pchTemp;
2770 char achConfigFile[CCHMAXPATH];
2773 /* No environment variable to have proportional window.
2774 * Ok, let's check if this executable is in config file!
2776 _this->hidden->bProportionalResize = 0;
2778 DosGetInfoBlocks(&tib, &pib);
2779 pchTemp = pchFileName = pib->pib_pchcmd;
2783 pchFileName = pchTemp+1;
2788 sprintf(achConfigFile, "%s\\.sdl.proportionals", getenv("HOME"));
2789 hFile = fopen(achConfigFile, "rt");
2792 /* Seems like the file cannot be opened or does not exist.
2793 * Let's try to create it with defaults!
2795 hFile = fopen(achConfigFile, "wt");
2798 fprintf(hFile, "; This file is a config file of SDL/2, containing\n");
2799 fprintf(hFile, "; the list of executables that must have proportional\n");
2800 fprintf(hFile, "; windows.\n");
2801 fprintf(hFile, ";\n");
2802 fprintf(hFile, "; You can add executable filenames into this file,\n");
2803 fprintf(hFile, "; one under the other. If SDL finds that a given\n");
2804 fprintf(hFile, "; program is in this list, then that application\n");
2805 fprintf(hFile, "; will have proportional windows, just like if\n");
2806 fprintf(hFile, "; the SET SDL_USE_PROPORTIONAL_WINDOW env. variable\n");
2807 fprintf(hFile, "; would have been set for that process.\n");
2808 fprintf(hFile, ";\n");
2809 fprintf(hFile, "\n");
2810 fprintf(hFile, "dosbox.exe\n");
2814 hFile = fopen(achConfigFile, "rt");
2819 while (fgets(achConfigFile, sizeof(achConfigFile), hFile))
2821 /* Cut \n from end of string */
2823 while (achConfigFile[strlen(achConfigFile)-1] == '\n')
2824 achConfigFile[strlen(achConfigFile)-1] = 0;
2827 if (stricmp(achConfigFile, pchFileName)==0)
2829 /* Found it in config file! */
2830 _this->hidden->bProportionalResize = 1;
2839 DosCreateMutexSem(NULL, &(_this->hidden->hmtxUseSrcBuffer), 0, FALSE);
2841 // Now create our window with a default size
2843 // For this, we select the first available fullscreen mode as
2844 // current window size!
2845 SDL_memcpy(&(_this->hidden->SrcBufferDesc), _this->hidden->pAvailableFSLibVideoModes, sizeof(_this->hidden->SrcBufferDesc));
2846 // Allocate new video buffer!
2847 _this->hidden->pchSrcBuffer = (char *) SDL_malloc(_this->hidden->pAvailableFSLibVideoModes->uiScanLineSize * _this->hidden->pAvailableFSLibVideoModes->uiYResolution);
2848 if (!_this->hidden->pchSrcBuffer)
2851 printf("[os2fslib_VideoInit] : Yikes, not enough memory for new video buffer!\n"); fflush(stdout);
2853 SDL_SetError("Not enough memory for new video buffer!\n");
2857 // For this, we need a message processing thread.
2858 // We'll create a new thread for this, which will do everything
2859 // what is related to PM
2860 _this->hidden->iPMThreadStatus = 0;
2861 _this->hidden->tidPMThread = _beginthread(PMThreadFunc, NULL, 65536, (void *) _this);
2862 if (_this->hidden->tidPMThread <= 0)
2865 printf("[os2fslib_VideoInit] : Could not create PM thread!\n");
2867 SDL_SetError("Could not create PM thread");
2870 #ifdef USE_DOSSETPRIORITY
2871 // Burst the priority of PM Thread!
2872 DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, _this->hidden->tidPMThread);
2874 // Wait for the PM thread to initialize!
2875 while (_this->hidden->iPMThreadStatus==0)
2877 // If the PM thread could not set up everything, then
2879 if (_this->hidden->iPMThreadStatus!=1)
2882 printf("[os2fslib_VideoInit] : PMThread reported an error : %d\n", _this->hidden->iPMThreadStatus);
2884 SDL_SetError("Error initializing PM thread");
2892 static void os2fslib_DeleteDevice(_THIS)
2895 printf("[os2fslib_DeleteDevice]\n"); fflush(stdout);
2898 FSLib_FreeVideoModeList(_this->hidden->pAvailableFSLibVideoModes);
2899 if (_this->hidden->pListModesResult)
2900 SDL_free(_this->hidden->pListModesResult);
2901 if (_this->hidden->pchSrcBuffer)
2902 SDL_free(_this->hidden->pchSrcBuffer);
2903 DosCloseMutexSem(_this->hidden->hmtxUseSrcBuffer);
2904 SDL_free(_this->hidden);
2906 FSLib_Uninitialize();
2909 static int os2fslib_Available(void)
2912 // If we can run, it means that we could load FSLib,
2913 // so we assume that it's available then!
2917 static void os2fslib_MorphToPM()
2922 DosGetInfoBlocks(&tib, &pib);
2924 // Change flag from VIO to PM:
2925 if (pib->pib_ultype==2) pib->pib_ultype = 3;
2928 static SDL_VideoDevice *os2fslib_CreateDevice(int devindex)
2930 SDL_VideoDevice *device;
2933 printf("[os2fslib_CreateDevice] : Enter\n"); fflush(stdout);
2936 /* Initialize all variables that we clean on shutdown */
2937 device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
2940 SDL_memset(device, 0, (sizeof *device));
2941 // Also allocate memory for private data
2942 device->hidden = (struct SDL_PrivateVideoData *) SDL_malloc((sizeof(struct SDL_PrivateVideoData)));
2944 if ( (device == NULL) || (device->hidden == NULL) )
2951 SDL_memset(device->hidden, 0, (sizeof *device->hidden));
2953 /* Set the function pointers */
2955 printf("[os2fslib_CreateDevice] : VideoInit is %p\n", os2fslib_VideoInit); fflush(stdout);
2958 /* Initialization/Query functions */
2959 device->VideoInit = os2fslib_VideoInit;
2960 device->ListModes = os2fslib_ListModes;
2961 device->SetVideoMode = os2fslib_SetVideoMode;
2962 device->ToggleFullScreen = os2fslib_ToggleFullScreen;
2963 device->UpdateMouse = os2fslib_UpdateMouse;
2964 device->CreateYUVOverlay = NULL;
2965 device->SetColors = os2fslib_SetColors;
2966 device->UpdateRects = os2fslib_UpdateRects;
2967 device->VideoQuit = os2fslib_VideoQuit;
2968 /* Hardware acceleration functions */
2969 device->AllocHWSurface = os2fslib_AllocHWSurface;
2970 device->CheckHWBlit = NULL;
2971 device->FillHWRect = NULL;
2972 device->SetHWColorKey = NULL;
2973 device->SetHWAlpha = NULL;
2974 device->LockHWSurface = os2fslib_LockHWSurface;
2975 device->UnlockHWSurface = os2fslib_UnlockHWSurface;
2976 device->FlipHWSurface = NULL;
2977 device->FreeHWSurface = os2fslib_FreeHWSurface;
2978 /* Window manager functions */
2979 device->SetCaption = os2fslib_SetCaption;
2980 device->SetIcon = os2fslib_SetIcon;
2981 device->IconifyWindow = os2fslib_IconifyWindow;
2982 device->GrabInput = os2fslib_GrabInput;
2983 device->GetWMInfo = NULL;
2984 /* Cursor manager functions to Windowed mode*/
2985 os2fslib_SetCursorManagementFunctions(device, 1);
2986 /* Event manager functions */
2987 device->InitOSKeymap = os2fslib_InitOSKeymap;
2988 device->PumpEvents = os2fslib_PumpEvents;
2989 /* The function used to dispose of this structure */
2990 device->free = os2fslib_DeleteDevice;
2992 // Make sure we'll be able to use Win* API even if the application
2993 // was linked to be a VIO application!
2994 os2fslib_MorphToPM();
2996 // Now initialize FSLib, and query available video modes!
2997 if (!FSLib_Initialize())
2999 // Could not initialize FSLib!
3001 printf("[os2fslib_CreateDevice] : Could not initialize FSLib!\n");
3003 SDL_SetError("Could not initialize FSLib!");
3004 SDL_free(device->hidden);
3008 device->hidden->pAvailableFSLibVideoModes =
3009 FSLib_GetVideoModeList();
3014 VideoBootStrap OS2FSLib_bootstrap = {
3015 "os2fslib", "OS/2 Video Output using FSLib",
3016 os2fslib_Available, os2fslib_CreateDevice