]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - board/MAI/bios_emulator/scitech/src/pm/win32/ddraw.c
* Patch by Thomas Frieden, 13 Nov 2002:
[karo-tx-uboot.git] / board / MAI / bios_emulator / scitech / src / pm / win32 / ddraw.c
1 /****************************************************************************
2 *
3 *                   SciTech Multi-platform Graphics Library
4 *
5 *  ========================================================================
6 *
7 *    The contents of this file are subject to the SciTech MGL Public
8 *    License Version 1.0 (the "License"); you may not use this file
9 *    except in compliance with the License. You may obtain a copy of
10 *    the License at http://www.scitechsoft.com/mgl-license.txt
11 *
12 *    Software distributed under the License is distributed on an
13 *    "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 *    implied. See the License for the specific language governing
15 *    rights and limitations under the License.
16 *
17 *    The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
18 *
19 *    The Initial Developer of the Original Code is SciTech Software, Inc.
20 *    All Rights Reserved.
21 *
22 *  ========================================================================
23 *
24 * Language:     ANSI C
25 * Environment:  Win32
26 *
27 * Description:  Win32 implementation for the SciTech cross platform
28 *               event library.
29 *
30 ****************************************************************************/
31
32 #include "event.h"
33 #include "pmapi.h"
34 #include "win32/oshdr.h"
35 #include "nucleus/graphics.h"
36
37 /*---------------------------- Global Variables ---------------------------*/
38
39 /* Publicly accessible variables */
40
41 int                 _PM_deskX,_PM_deskY;/* Desktop dimentions           */
42 HWND                _PM_hwndConsole;    /* Window handle for console    */
43 #ifdef  __INTEL__
44 uint                _PM_cw_default;     /* Default FPU control word     */
45 #endif
46
47 /* Private internal variables */
48
49 static HINSTANCE    hInstApp = NULL;/* Application instance handle      */
50 static HWND         hwndUser = NULL;/* User window handle               */
51 static HINSTANCE    hInstDD = NULL; /* Handle to DirectDraw DLL         */
52 static LPDIRECTDRAW lpDD = NULL;    /* DirectDraw object                */
53 static LONG         oldWndStyle;    /* Info about old user window       */
54 static LONG         oldExWndStyle;  /* Info about old user window       */
55 static int          oldWinPosX;     /* Old window position X coordinate */
56 static int          oldWinPosY;     /* Old window pisition Y coordinate */
57 static int          oldWinSizeX;    /* Old window size X                */
58 static int          oldWinSizeY;    /* Old window size Y                */
59 static WNDPROC      oldWinProc = NULL;
60 static PM_saveState_cb suspendApp = NULL;
61 static ibool        waitActive = false;
62 static ibool        isFullScreen = false;
63 static ibool        backInGDI = false;
64
65 /* Internal strings */
66
67 static char *szWinClassName     = "SciTechDirectDrawWindow";
68 static char *szAutoPlayKey      = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer";
69 static char *szAutoPlayValue    = "NoDriveTypeAutoRun";
70
71 /* Dynalinks to DirectDraw functions */
72
73 static HRESULT (WINAPI *pDirectDrawCreate)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter);
74
75 /*---------------------------- Implementation -----------------------------*/
76
77 /****************************************************************************
78 REMARKS:
79 Temporarily disables AutoPlay operation while we are running in fullscreen
80 graphics modes.
81 ****************************************************************************/
82 static void DisableAutoPlay(void)
83 {
84     DWORD   dwAutoPlay,dwSize = sizeof(dwAutoPlay);
85     HKEY    hKey;
86
87     if (RegOpenKeyEx(HKEY_CURRENT_USER,szAutoPlayKey,0,KEY_EXECUTE | KEY_WRITE,&hKey) == ERROR_SUCCESS) {
88         RegQueryValueEx(hKey,szAutoPlayValue,NULL,NULL,(void*)&dwAutoPlay,&dwSize);
89         dwAutoPlay |= AUTOPLAY_DRIVE_CDROM;
90         RegSetValueEx(hKey,szAutoPlayValue,0,REG_DWORD,(void*)&dwAutoPlay,dwSize);
91         RegCloseKey(hKey);
92         }
93 }
94
95 /****************************************************************************
96 REMARKS:
97 Re-enables AutoPlay operation when we return to regular GDI mode.
98 ****************************************************************************/
99 static void RestoreAutoPlay(void)
100 {
101     DWORD   dwAutoPlay,dwSize = sizeof(dwAutoPlay);
102     HKEY    hKey;
103
104     if (RegOpenKeyEx(HKEY_CURRENT_USER,szAutoPlayKey,0,KEY_EXECUTE | KEY_WRITE,&hKey) == ERROR_SUCCESS) {
105         RegQueryValueEx(hKey,szAutoPlayValue,NULL,NULL,(void*)&dwAutoPlay,&dwSize);
106         dwAutoPlay &= ~AUTOPLAY_DRIVE_CDROM;
107         RegSetValueEx(hKey,szAutoPlayValue,0,REG_DWORD,(void*)&dwAutoPlay,dwSize);
108         RegCloseKey(hKey);
109         }
110 }
111
112 /****************************************************************************
113 REMARKS:
114 Suspends the application by switching back to the GDI desktop, allowing
115 normal application code to be processed, and then waiting for the
116 application activate command to bring us back to fullscreen mode with our
117 window minimised.
118 ****************************************************************************/
119 static void LeaveFullScreen(void)
120 {
121     int retCode = PM_SUSPEND_APP;
122
123     if (backInGDI)
124         return;
125     if (suspendApp)
126         retCode = suspendApp(PM_DEACTIVATE);
127     RestoreAutoPlay();
128     backInGDI = true;
129
130     /* Now process messages normally until we are re-activated */
131     waitActive = true;
132     if (retCode != PM_NO_SUSPEND_APP) {
133         while (waitActive) {
134             _EVT_pumpMessages();
135             Sleep(200);
136             }
137         }
138 }
139
140 /****************************************************************************
141 REMARKS:
142 Reactivate all the surfaces for DirectDraw and set the system back up for
143 fullscreen rendering.
144 ****************************************************************************/
145 static void RestoreFullScreen(void)
146 {
147     static ibool    firstTime = true;
148
149     if (firstTime) {
150         /* Clear the message queue while waiting for the surfaces to be
151          * restored.
152          */
153         firstTime = false;
154         while (1) {
155             /* Continue looping until out application has been restored
156              * and we have reset the display mode.
157              */
158             _EVT_pumpMessages();
159             if (GetActiveWindow() == _PM_hwndConsole) {
160                 if (suspendApp)
161                     suspendApp(PM_REACTIVATE);
162                 DisableAutoPlay();
163                 backInGDI = false;
164                 waitActive = false;
165                 firstTime = true;
166                 return;
167                 }
168             Sleep(200);
169             }
170         }
171 }
172
173 /****************************************************************************
174 REMARKS:
175 This function suspends the application by switching back to the GDI desktop,
176 allowing normal application code to be processed and then waiting for the
177 application activate command to bring us back to fullscreen mode with our
178 window minimised.
179
180 This version only gets called if we have not captured the screen switch in
181 our activate message loops and will occur if the DirectDraw drivers lose a
182 surface for some reason while rendering. This should not normally happen,
183 but it is included just to be sure (it can happen on WinNT/2000 if the user
184 hits the Ctrl-Alt-Del key combination). Note that this code will always
185 spin loop, and we cannot disable the spin looping from this version (ie:
186 if the user hits Ctrl-Alt-Del under WinNT/2000 the application main loop
187 will cease to be executed until the user switches back to the application).
188 ****************************************************************************/
189 void PMAPI PM_doSuspendApp(void)
190 {
191     static  ibool firstTime = true;
192
193     /* Call system DLL version if found */
194     if (_PM_imports.PM_doSuspendApp != PM_doSuspendApp) {
195         _PM_imports.PM_doSuspendApp();
196         return;
197         }
198
199     if (firstTime) {
200         if (suspendApp)
201             suspendApp(PM_DEACTIVATE);
202         RestoreAutoPlay();
203         firstTime = false;
204         backInGDI = true;
205         }
206     RestoreFullScreen();
207     firstTime = true;
208 }
209
210 /****************************************************************************
211 REMARKS:
212 Main Window proc for the full screen DirectDraw Window that we create while
213 running in full screen mode. Here we capture all mouse and keyboard events
214 for the window and plug them into our event queue.
215 ****************************************************************************/
216 static LONG CALLBACK PM_winProc(
217     HWND hwnd,
218     UINT msg,
219     WPARAM wParam,
220     LONG lParam)
221 {
222     switch (msg) {
223         case WM_SYSCHAR:
224             /* Stop Alt-Space from pausing our application */
225             return 0;
226         case WM_KEYDOWN:
227         case WM_SYSKEYDOWN:
228             if (HIWORD(lParam) & KF_REPEAT) {
229                 if (msg == WM_SYSKEYDOWN)
230                     return 0;
231                 break;
232                 }
233             /* Fall through for keydown events */
234         case WM_KEYUP:
235         case WM_SYSKEYUP:
236             if (msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) {
237                 if ((HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_RETURN)
238                     break;
239                 /* We ignore the remainder of the system keys to stop the
240                  * system menu from being activated from the keyboard and pausing
241                  * our app while fullscreen (ie: pressing the Alt key).
242                  */
243                 return 0;
244                 }
245             break;
246         case WM_SYSCOMMAND:
247             switch (wParam & ~0x0F) {
248                 case SC_SCREENSAVE:
249                 case SC_MONITORPOWER:
250                     /* Ignore screensaver requests in fullscreen modes */
251                     return 0;
252                 }
253             break;
254         case WM_SIZE:
255             if (waitActive && backInGDI && (wParam != SIZE_MINIMIZED)) {
256                 /* Start the re-activation process */
257                 PostMessage(hwnd,WM_DO_SUSPEND_APP,WM_PM_RESTORE_FULLSCREEN,0);
258                 }
259             else if (!waitActive && isFullScreen && !backInGDI && (wParam == SIZE_MINIMIZED)) {
260                 /* Start the de-activation process */
261                 PostMessage(hwnd,WM_DO_SUSPEND_APP,WM_PM_LEAVE_FULLSCREEN,0);
262                 }
263             break;
264         case WM_DO_SUSPEND_APP:
265             switch (wParam) {
266                                 case WM_PM_RESTORE_FULLSCREEN:
267                                         RestoreFullScreen();
268                                         break;
269                                 case WM_PM_LEAVE_FULLSCREEN:
270                                         LeaveFullScreen();
271                                         break;
272                 }
273             return 0;
274         }
275     if (oldWinProc)
276         return oldWinProc(hwnd,msg,wParam,lParam);
277     return DefWindowProc(hwnd,msg,wParam,lParam);
278 }
279
280 /****************************************************************************
281 PARAMETERS:
282 hwnd    - User window to convert
283 width   - Window of the fullscreen window
284 height  - Height of the fullscreen window
285
286 RETURNS:
287 Handle to converted fullscreen Window.
288
289 REMARKS:
290 This function takes the original user window handle and modifies the size,
291 position and attributes for the window to convert it into a fullscreen
292 window that we can use.
293 ****************************************************************************/
294 static PM_HWND _PM_convertUserWindow(
295     HWND hwnd,
296     int width,
297     int height)
298 {
299     RECT    window;
300
301     GetWindowRect(hwnd,&window);
302     oldWinPosX = window.left;
303     oldWinPosY = window.top;
304     oldWinSizeX = window.right - window.left;
305     oldWinSizeY = window.bottom - window.top;
306     oldWndStyle = SetWindowLong(hwnd,GWL_STYLE,WS_POPUP | WS_SYSMENU);
307     oldExWndStyle = SetWindowLong(hwnd,GWL_EXSTYLE,WS_EX_APPWINDOW);
308     ShowWindow(hwnd,SW_SHOW);
309     MoveWindow(hwnd,0,0,width,height,TRUE);
310     SetWindowPos(hwnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
311     oldWinProc = (WNDPROC)SetWindowLong(hwnd,GWL_WNDPROC, (LPARAM)PM_winProc);
312     return hwnd;
313 }
314
315 /****************************************************************************
316 PARAMETERS:
317 hwnd    - User window to restore
318
319 REMARKS:
320 This function restores the original attributes of the user window and put's
321 it back into it's original state before it was converted to a fullscreen
322 window.
323 ****************************************************************************/
324 static void _PM_restoreUserWindow(
325     HWND hwnd)
326 {
327     SetWindowLong(hwnd,GWL_WNDPROC, (LPARAM)oldWinProc);
328     SetWindowLong(hwnd,GWL_EXSTYLE,oldExWndStyle);
329     SetWindowLong(hwnd,GWL_STYLE,oldWndStyle);
330     SetWindowPos(hwnd,HWND_NOTOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
331     ShowWindow(hwnd,SW_SHOW);
332     MoveWindow(hwnd,oldWinPosX,oldWinPosY,oldWinSizeX,oldWinSizeY,TRUE);
333     oldWinProc = NULL;
334 }
335
336 /****************************************************************************
337 PARAMETERS:
338 device  - Index of the device to load DirectDraw for (0 for primary)
339
340 REMARKS:
341 Attempts to dynamically load the DirectDraw DLL's and create the DirectDraw
342 objects that we need.
343 ****************************************************************************/
344 void * PMAPI PM_loadDirectDraw(
345     int device)
346 {
347     HDC         hdc;
348     int         bits;
349
350     /* Call system DLL version if found */
351     if (_PM_imports.PM_loadDirectDraw != PM_loadDirectDraw)
352         return _PM_imports.PM_loadDirectDraw(device);
353
354     // TODO: Handle multi-monitor!!
355     if (device != 0)
356         return NULL;
357
358     /* Load the DirectDraw DLL if not presently loaded */
359     GET_DEFAULT_CW();
360     if (!hInstDD) {
361         hdc = GetDC(NULL);
362         bits = GetDeviceCaps(hdc,BITSPIXEL);
363         ReleaseDC(NULL,hdc);
364         if (bits < 8)
365             return NULL;
366         if ((hInstDD = LoadLibrary("ddraw.dll")) == NULL)
367             return NULL;
368         pDirectDrawCreate = (void*)GetProcAddress(hInstDD,"DirectDrawCreate");
369         if (!pDirectDrawCreate)
370             return NULL;
371         }
372
373     /* Create the DirectDraw object */
374     if (!lpDD && pDirectDrawCreate(NULL, &lpDD, NULL) != DD_OK) {
375         lpDD = NULL;
376         return NULL;
377         }
378     RESET_DEFAULT_CW();
379     return lpDD;
380 }
381
382 /****************************************************************************
383 PARAMETERS:
384 device  - Index of the device to unload DirectDraw for (0 for primary)
385
386 REMARKS:
387 Frees any DirectDraw objects for the device. We never actually explicitly
388 unload the ddraw.dll library, since unloading and reloading it is
389 unnecessary since we only want to unload it when the application exits and
390 that happens automatically.
391 ****************************************************************************/
392 void PMAPI PM_unloadDirectDraw(
393     int device)
394 {
395     /* Call system DLL version if found */
396     if (_PM_imports.PM_unloadDirectDraw != PM_unloadDirectDraw) {
397         _PM_imports.PM_unloadDirectDraw(device);
398         return;
399         }
400     if (lpDD) {
401         IDirectDraw_Release(lpDD);
402         lpDD = NULL;
403         }
404     (void)device;
405 }
406
407 /****************************************************************************
408 REMARKS:
409 Open a console for output to the screen, creating the main event handling
410 window if necessary.
411 ****************************************************************************/
412 PM_HWND PMAPI PM_openConsole(
413     PM_HWND hWndUser,
414     int device,
415     int xRes,
416     int yRes,
417     int bpp,
418     ibool fullScreen)
419 {
420     WNDCLASS        cls;
421     static ibool    classRegistered = false;
422
423     /* Call system DLL version if found */
424     GA_getSystemPMImports();
425     if (_PM_imports.PM_openConsole != PM_openConsole) {
426         if (fullScreen) {
427             _PM_deskX = xRes;
428             _PM_deskY = yRes;
429             }
430         return _PM_imports.PM_openConsole(hWndUser,device,xRes,yRes,bpp,fullScreen);
431         }
432
433     /* Create the fullscreen window if necessary */
434     hwndUser = hWndUser;
435     if (fullScreen) {
436         if (!classRegistered) {
437             /* Create a Window class for the fullscreen window in here, since
438              * we need to register one that will do all our event handling for
439              * us.
440              */
441             hInstApp            = GetModuleHandle(NULL);
442             cls.hCursor         = LoadCursor(NULL,IDC_ARROW);
443             cls.hIcon           = LoadIcon(hInstApp,MAKEINTRESOURCE(1));
444             cls.lpszMenuName    = NULL;
445             cls.lpszClassName   = szWinClassName;
446             cls.hbrBackground   = GetStockObject(BLACK_BRUSH);
447             cls.hInstance       = hInstApp;
448             cls.style           = CS_DBLCLKS;
449             cls.lpfnWndProc     = PM_winProc;
450             cls.cbWndExtra      = 0;
451             cls.cbClsExtra      = 0;
452             if (!RegisterClass(&cls))
453                 return NULL;
454             classRegistered = true;
455             }
456         _PM_deskX = xRes;
457         _PM_deskY = yRes;
458         if (!hwndUser) {
459             char windowTitle[80];
460             if (LoadString(hInstApp,1,windowTitle,sizeof(windowTitle)) == 0)
461                 strcpy(windowTitle,"MGL Fullscreen Application");
462             _PM_hwndConsole = CreateWindowEx(WS_EX_APPWINDOW,szWinClassName,
463                 windowTitle,WS_POPUP | WS_SYSMENU,0,0,xRes,yRes,
464                 NULL,NULL,hInstApp,NULL);
465             }
466         else {
467             _PM_hwndConsole = _PM_convertUserWindow(hwndUser,xRes,yRes);
468             }
469         ShowCursor(false);
470         isFullScreen = true;
471         }
472     else {
473         _PM_hwndConsole = hwndUser;
474         isFullScreen = false;
475         }
476     SetFocus(_PM_hwndConsole);
477     SetForegroundWindow(_PM_hwndConsole);
478     DisableAutoPlay();
479     (void)bpp;
480     return _PM_hwndConsole;
481 }
482
483 /****************************************************************************
484 REMARKS:
485 Find the size of the console state buffer.
486 ****************************************************************************/
487 int PMAPI PM_getConsoleStateSize(void)
488 {
489     /* Call system DLL version if found */
490     if (_PM_imports.PM_getConsoleStateSize != PM_getConsoleStateSize)
491         return _PM_imports.PM_getConsoleStateSize();
492
493     /* Not used in Windows */
494     return 1;
495 }
496
497 /****************************************************************************
498 REMARKS:
499 Save the state of the console.
500 ****************************************************************************/
501 void PMAPI PM_saveConsoleState(
502     void *stateBuf,
503     PM_HWND hwndConsole)
504 {
505     /* Call system DLL version if found */
506     if (_PM_imports.PM_saveConsoleState != PM_saveConsoleState) {
507         _PM_imports.PM_saveConsoleState(stateBuf,hwndConsole);
508         return;
509         }
510
511     /* Not used in Windows */
512     (void)stateBuf;
513     (void)hwndConsole;
514 }
515
516 /****************************************************************************
517 REMARKS:
518 Set the suspend application callback for the fullscreen console.
519 ****************************************************************************/
520 void PMAPI PM_setSuspendAppCallback(
521     PM_saveState_cb saveState)
522 {
523     /* Call system DLL version if found */
524     if (_PM_imports.PM_setSuspendAppCallback != PM_setSuspendAppCallback) {
525         _PM_imports.PM_setSuspendAppCallback(saveState);
526         return;
527         }
528     suspendApp = saveState;
529 }
530
531 /****************************************************************************
532 REMARKS:
533 Restore the console state.
534 ****************************************************************************/
535 void PMAPI PM_restoreConsoleState(
536     const void *stateBuf,
537     PM_HWND hwndConsole)
538 {
539     /* Call system DLL version if found */
540     if (_PM_imports.PM_restoreConsoleState != PM_restoreConsoleState) {
541         _PM_imports.PM_restoreConsoleState(stateBuf,hwndConsole);
542         return;
543         }
544
545     /* Not used in Windows */
546     (void)stateBuf;
547     (void)hwndConsole;
548 }
549
550 /****************************************************************************
551 REMARKS:
552 Close the fullscreen console.
553 ****************************************************************************/
554 void PMAPI PM_closeConsole(
555     PM_HWND hwndConsole)
556 {
557     /* Call system DLL version if found */
558     if (_PM_imports.PM_closeConsole != PM_closeConsole) {
559         _PM_imports.PM_closeConsole(hwndConsole);
560         return;
561         }
562     ShowCursor(true);
563     RestoreAutoPlay();
564     if (hwndUser)
565         _PM_restoreUserWindow(hwndConsole);
566     else
567         DestroyWindow(hwndConsole);
568     hwndUser = NULL;
569     _PM_hwndConsole = NULL;
570 }
571
572 /****************************************************************************
573 REMARKS:
574 Return the DirectDraw window handle used by the application.
575 ****************************************************************************/
576 PM_HWND PMAPI PM_getDirectDrawWindow(void)
577 {
578     /* Call system DLL version if found */
579     if (_PM_imports.PM_getDirectDrawWindow != PM_getDirectDrawWindow)
580         return _PM_imports.PM_getDirectDrawWindow();
581     return _PM_hwndConsole;
582 }
583