1 /****************************************************************************
3 * SciTech Multi-platform Graphics Library
5 * ========================================================================
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
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.
17 * The Original Code is Copyright (C) 1991-1998 SciTech Software, Inc.
19 * The Initial Developer of the Original Code is SciTech Software, Inc.
20 * All Rights Reserved.
22 * ========================================================================
27 * Description: Win32 implementation for the SciTech cross platform
30 ****************************************************************************/
34 #include "win32/oshdr.h"
35 #include "nucleus/graphics.h"
37 /*---------------------------- Global Variables ---------------------------*/
39 /* Publicly accessible variables */
41 int _PM_deskX,_PM_deskY;/* Desktop dimentions */
42 HWND _PM_hwndConsole; /* Window handle for console */
44 uint _PM_cw_default; /* Default FPU control word */
47 /* Private internal variables */
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;
65 /* Internal strings */
67 static char *szWinClassName = "SciTechDirectDrawWindow";
68 static char *szAutoPlayKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer";
69 static char *szAutoPlayValue = "NoDriveTypeAutoRun";
71 /* Dynalinks to DirectDraw functions */
73 static HRESULT (WINAPI *pDirectDrawCreate)(GUID FAR *lpGUID, LPDIRECTDRAW FAR *lplpDD, IUnknown FAR *pUnkOuter);
75 /*---------------------------- Implementation -----------------------------*/
77 /****************************************************************************
79 Temporarily disables AutoPlay operation while we are running in fullscreen
81 ****************************************************************************/
82 static void DisableAutoPlay(void)
84 DWORD dwAutoPlay,dwSize = sizeof(dwAutoPlay);
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);
95 /****************************************************************************
97 Re-enables AutoPlay operation when we return to regular GDI mode.
98 ****************************************************************************/
99 static void RestoreAutoPlay(void)
101 DWORD dwAutoPlay,dwSize = sizeof(dwAutoPlay);
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);
112 /****************************************************************************
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
118 ****************************************************************************/
119 static void LeaveFullScreen(void)
121 int retCode = PM_SUSPEND_APP;
126 retCode = suspendApp(PM_DEACTIVATE);
130 /* Now process messages normally until we are re-activated */
132 if (retCode != PM_NO_SUSPEND_APP) {
140 /****************************************************************************
142 Reactivate all the surfaces for DirectDraw and set the system back up for
143 fullscreen rendering.
144 ****************************************************************************/
145 static void RestoreFullScreen(void)
147 static ibool firstTime = true;
150 /* Clear the message queue while waiting for the surfaces to be
155 /* Continue looping until out application has been restored
156 * and we have reset the display mode.
159 if (GetActiveWindow() == _PM_hwndConsole) {
161 suspendApp(PM_REACTIVATE);
173 /****************************************************************************
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
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)
191 static ibool firstTime = true;
193 /* Call system DLL version if found */
194 if (_PM_imports.PM_doSuspendApp != PM_doSuspendApp) {
195 _PM_imports.PM_doSuspendApp();
201 suspendApp(PM_DEACTIVATE);
210 /****************************************************************************
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(
224 /* Stop Alt-Space from pausing our application */
228 if (HIWORD(lParam) & KF_REPEAT) {
229 if (msg == WM_SYSKEYDOWN)
233 /* Fall through for keydown events */
236 if (msg == WM_SYSKEYDOWN || msg == WM_SYSKEYUP) {
237 if ((HIWORD(lParam) & KF_ALTDOWN) && wParam == VK_RETURN)
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).
247 switch (wParam & ~0x0F) {
249 case SC_MONITORPOWER:
250 /* Ignore screensaver requests in fullscreen modes */
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);
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);
264 case WM_DO_SUSPEND_APP:
266 case WM_PM_RESTORE_FULLSCREEN:
269 case WM_PM_LEAVE_FULLSCREEN:
276 return oldWinProc(hwnd,msg,wParam,lParam);
277 return DefWindowProc(hwnd,msg,wParam,lParam);
280 /****************************************************************************
282 hwnd - User window to convert
283 width - Window of the fullscreen window
284 height - Height of the fullscreen window
287 Handle to converted fullscreen Window.
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(
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);
315 /****************************************************************************
317 hwnd - User window to restore
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
323 ****************************************************************************/
324 static void _PM_restoreUserWindow(
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);
336 /****************************************************************************
338 device - Index of the device to load DirectDraw for (0 for primary)
341 Attempts to dynamically load the DirectDraw DLL's and create the DirectDraw
342 objects that we need.
343 ****************************************************************************/
344 void * PMAPI PM_loadDirectDraw(
350 /* Call system DLL version if found */
351 if (_PM_imports.PM_loadDirectDraw != PM_loadDirectDraw)
352 return _PM_imports.PM_loadDirectDraw(device);
354 // TODO: Handle multi-monitor!!
358 /* Load the DirectDraw DLL if not presently loaded */
362 bits = GetDeviceCaps(hdc,BITSPIXEL);
366 if ((hInstDD = LoadLibrary("ddraw.dll")) == NULL)
368 pDirectDrawCreate = (void*)GetProcAddress(hInstDD,"DirectDrawCreate");
369 if (!pDirectDrawCreate)
373 /* Create the DirectDraw object */
374 if (!lpDD && pDirectDrawCreate(NULL, &lpDD, NULL) != DD_OK) {
382 /****************************************************************************
384 device - Index of the device to unload DirectDraw for (0 for primary)
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(
395 /* Call system DLL version if found */
396 if (_PM_imports.PM_unloadDirectDraw != PM_unloadDirectDraw) {
397 _PM_imports.PM_unloadDirectDraw(device);
401 IDirectDraw_Release(lpDD);
407 /****************************************************************************
409 Open a console for output to the screen, creating the main event handling
411 ****************************************************************************/
412 PM_HWND PMAPI PM_openConsole(
421 static ibool classRegistered = false;
423 /* Call system DLL version if found */
424 GA_getSystemPMImports();
425 if (_PM_imports.PM_openConsole != PM_openConsole) {
430 return _PM_imports.PM_openConsole(hWndUser,device,xRes,yRes,bpp,fullScreen);
433 /* Create the fullscreen window if necessary */
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
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;
452 if (!RegisterClass(&cls))
454 classRegistered = true;
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);
467 _PM_hwndConsole = _PM_convertUserWindow(hwndUser,xRes,yRes);
473 _PM_hwndConsole = hwndUser;
474 isFullScreen = false;
476 SetFocus(_PM_hwndConsole);
477 SetForegroundWindow(_PM_hwndConsole);
480 return _PM_hwndConsole;
483 /****************************************************************************
485 Find the size of the console state buffer.
486 ****************************************************************************/
487 int PMAPI PM_getConsoleStateSize(void)
489 /* Call system DLL version if found */
490 if (_PM_imports.PM_getConsoleStateSize != PM_getConsoleStateSize)
491 return _PM_imports.PM_getConsoleStateSize();
493 /* Not used in Windows */
497 /****************************************************************************
499 Save the state of the console.
500 ****************************************************************************/
501 void PMAPI PM_saveConsoleState(
505 /* Call system DLL version if found */
506 if (_PM_imports.PM_saveConsoleState != PM_saveConsoleState) {
507 _PM_imports.PM_saveConsoleState(stateBuf,hwndConsole);
511 /* Not used in Windows */
516 /****************************************************************************
518 Set the suspend application callback for the fullscreen console.
519 ****************************************************************************/
520 void PMAPI PM_setSuspendAppCallback(
521 PM_saveState_cb saveState)
523 /* Call system DLL version if found */
524 if (_PM_imports.PM_setSuspendAppCallback != PM_setSuspendAppCallback) {
525 _PM_imports.PM_setSuspendAppCallback(saveState);
528 suspendApp = saveState;
531 /****************************************************************************
533 Restore the console state.
534 ****************************************************************************/
535 void PMAPI PM_restoreConsoleState(
536 const void *stateBuf,
539 /* Call system DLL version if found */
540 if (_PM_imports.PM_restoreConsoleState != PM_restoreConsoleState) {
541 _PM_imports.PM_restoreConsoleState(stateBuf,hwndConsole);
545 /* Not used in Windows */
550 /****************************************************************************
552 Close the fullscreen console.
553 ****************************************************************************/
554 void PMAPI PM_closeConsole(
557 /* Call system DLL version if found */
558 if (_PM_imports.PM_closeConsole != PM_closeConsole) {
559 _PM_imports.PM_closeConsole(hwndConsole);
565 _PM_restoreUserWindow(hwndConsole);
567 DestroyWindow(hwndConsole);
569 _PM_hwndConsole = NULL;
572 /****************************************************************************
574 Return the DirectDraw window handle used by the application.
575 ****************************************************************************/
576 PM_HWND PMAPI PM_getDirectDrawWindow(void)
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;