871 lines
26 KiB
C++
871 lines
26 KiB
C++
|
/*==========================================================================
|
||
|
*
|
||
|
* Copyright (C) 2000 Microsoft Corporation. All Rights Reserved.
|
||
|
*
|
||
|
* File: dwinproc.cpp
|
||
|
* Content: DirectDraw processing of Window messages
|
||
|
* History:
|
||
|
* Date By Reason
|
||
|
* ==== == ======
|
||
|
* 27-Jan-00 kanqiu initial implementation
|
||
|
***************************************************************************/
|
||
|
#include "ddrawpr.h"
|
||
|
|
||
|
#include "swapchan.hpp"
|
||
|
|
||
|
#include "resource.inl"
|
||
|
|
||
|
#ifdef WINNT
|
||
|
|
||
|
#define USESHOWWINDOW
|
||
|
|
||
|
// WindowInfo structure
|
||
|
typedef struct _D3DWINDOWINFO
|
||
|
{
|
||
|
DWORD dwMagic;
|
||
|
HWND hWnd;
|
||
|
WNDPROC lpWndProc;
|
||
|
DWORD dwFlags;
|
||
|
CEnum *pEnum;
|
||
|
DWORD dwDDFlags;
|
||
|
} D3DWINDOWINFO;
|
||
|
|
||
|
// WindowInfo for our single hooked winproc
|
||
|
// This global variable should never never be accessed outside
|
||
|
// of this file.
|
||
|
D3DWINDOWINFO g_WindowInfo = {0, 0, 0, 0, 0, 0};
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CSwapChain::HIDESHOW_IME"
|
||
|
|
||
|
// IME hide/show function
|
||
|
void CSwapChain::HIDESHOW_IME()
|
||
|
{
|
||
|
if (m_lSetIME)
|
||
|
{
|
||
|
SystemParametersInfo(
|
||
|
SPI_SETSHOWIMEUI, m_lSetIME - 1, NULL, 0);
|
||
|
InterlockedExchange(&m_lSetIME, 0);
|
||
|
}
|
||
|
} // HIDESHOW_IME
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CSwapChain::IsWinProcDeactivated"
|
||
|
|
||
|
BOOL CSwapChain::IsWinProcDeactivated() const
|
||
|
{
|
||
|
// Do we even have our own win-proc?
|
||
|
if (g_WindowInfo.hWnd != Device()->FocusWindow())
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// Check to see if our win-proc is deactivated then
|
||
|
if (DDRAWILCL_ACTIVENO & g_WindowInfo.dwDDFlags)
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
} // IsWinProcActive
|
||
|
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CSwapChain::MakeFullscreen"
|
||
|
//
|
||
|
// make the passed window fullscreen and topmost and set a timer
|
||
|
// to make the window topmost again, what a hack.
|
||
|
//
|
||
|
void CSwapChain::MakeFullscreen()
|
||
|
{
|
||
|
// We need to make sure that we don't send this
|
||
|
// size message to the app
|
||
|
g_WindowInfo.dwFlags |= WININFO_SELFSIZE;
|
||
|
|
||
|
// Do the processing
|
||
|
MONITORINFO MonInfo;
|
||
|
MonInfo.rcMonitor.top = MonInfo.rcMonitor.left = 0;
|
||
|
if (1 < Device()->Enum()->GetAdapterCount())
|
||
|
{
|
||
|
HMONITOR hMonitor = Device()->Enum()->
|
||
|
GetAdapterMonitor(Device()->AdapterIndex());
|
||
|
MonInfo.cbSize = sizeof(MONITORINFO);
|
||
|
if (hMonitor)
|
||
|
InternalGetMonitorInfo(hMonitor, &MonInfo);
|
||
|
}
|
||
|
SetWindowPos(m_PresentationData.hDeviceWindow, NULL,
|
||
|
MonInfo.rcMonitor.left,
|
||
|
MonInfo.rcMonitor.top,
|
||
|
Width(),
|
||
|
Height(),
|
||
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
||
|
|
||
|
if (GetForegroundWindow() == Device()->FocusWindow())
|
||
|
{
|
||
|
// If the exclusive mode window is not visible, make it so.
|
||
|
if (!IsWindowVisible(m_PresentationData.hDeviceWindow))
|
||
|
{
|
||
|
ShowWindow(m_PresentationData.hDeviceWindow, SW_SHOW);
|
||
|
}
|
||
|
|
||
|
SetWindowPos(m_PresentationData.hDeviceWindow, HWND_TOPMOST, 0, 0, 0, 0,
|
||
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
|
||
|
|
||
|
// If the exclusive mode window is maximized, restore it.
|
||
|
if (IsZoomed(m_PresentationData.hDeviceWindow))
|
||
|
{
|
||
|
ShowWindow(m_PresentationData.hDeviceWindow, SW_RESTORE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// We're done; so undo the self-size flag
|
||
|
g_WindowInfo.dwFlags &= ~WININFO_SELFSIZE;
|
||
|
|
||
|
} // CSwapChain::MakeFullscreen
|
||
|
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "handleActivateApp"
|
||
|
|
||
|
HRESULT handleActivateApp(BOOL is_active)
|
||
|
{
|
||
|
// We are going to start touching some internal
|
||
|
// data structures of the device and/or enum objects
|
||
|
// so we have to take the critical section for the device
|
||
|
#ifdef DEBUG
|
||
|
CLockD3D _lock(g_WindowInfo.pEnum, DPF_MODNAME, __FILE__);
|
||
|
#else
|
||
|
CLockD3D _lock(g_WindowInfo.pEnum);
|
||
|
#endif
|
||
|
|
||
|
HRESULT ddrval;
|
||
|
BOOL has_excl;
|
||
|
CEnum *pEnum = g_WindowInfo.pEnum;
|
||
|
|
||
|
#ifdef WINNT
|
||
|
if (pEnum->CheckExclusiveMode(NULL, &has_excl, is_active)
|
||
|
&& !has_excl && is_active)
|
||
|
{
|
||
|
// If we didn't get exclusive mode, for example, a different thread came in
|
||
|
DPF_ERR("Could not get exclusive mode when we thought we could");
|
||
|
return E_FAIL;
|
||
|
}
|
||
|
#endif //WINNT
|
||
|
|
||
|
/*
|
||
|
* stuff to do before the mode set if deactivating
|
||
|
*/
|
||
|
if (is_active)
|
||
|
{
|
||
|
/*
|
||
|
* restore exclusive mode. Here we don't release the ref we took on the exclusive mode mutex,
|
||
|
* since we want to keep the exclusive mode mutex.
|
||
|
*/
|
||
|
pEnum->StartExclusiveMode();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
* restore the mode
|
||
|
*/
|
||
|
pEnum->DoneExclusiveMode();
|
||
|
}
|
||
|
return S_OK;
|
||
|
} /* handleActivateApp */
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "WindowProc"
|
||
|
|
||
|
/*
|
||
|
* WindowProc
|
||
|
*/
|
||
|
LRESULT WINAPI WindowProc(
|
||
|
HWND hWnd,
|
||
|
UINT uMsg,
|
||
|
WPARAM wParam,
|
||
|
LPARAM lParam)
|
||
|
{
|
||
|
BOOL is_active;
|
||
|
WNDPROC proc;
|
||
|
BOOL get_away;
|
||
|
LRESULT rc;
|
||
|
|
||
|
/*
|
||
|
* Check the window proc
|
||
|
*/
|
||
|
if (g_WindowInfo.hWnd != hWnd || g_WindowInfo.dwMagic != WININFO_MAGIC)
|
||
|
{
|
||
|
DPF(4, "FATAL ERROR! Window Proc Called for hWnd %08lx, but not in list!", hWnd);
|
||
|
DEBUG_BREAK();
|
||
|
return DefWindowProc(hWnd, uMsg, wParam, lParam);
|
||
|
}
|
||
|
|
||
|
if (g_WindowInfo.dwFlags & WININFO_SELFSIZE)
|
||
|
{
|
||
|
return 0L; // don't send to app, it's caused by MakeFullscreen
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* unhook at destroy (or if the WININFO_UNHOOK bit is set)
|
||
|
*/
|
||
|
proc = g_WindowInfo.lpWndProc;
|
||
|
|
||
|
if (uMsg == WM_NCDESTROY)
|
||
|
{
|
||
|
DPF (4, "*** WM_NCDESTROY unhooking window ***");
|
||
|
g_WindowInfo.dwFlags |= WININFO_UNHOOK;
|
||
|
}
|
||
|
|
||
|
if (g_WindowInfo.dwFlags & WININFO_UNHOOK)
|
||
|
{
|
||
|
DPF (4, "*** Unhooking window proc");
|
||
|
|
||
|
if (g_WindowInfo.dwFlags & WININFO_ZOMBIE)
|
||
|
{
|
||
|
DPF (4, "*** Freeing ZOMBIE WININFO ***");
|
||
|
ZeroMemory(&g_WindowInfo, sizeof(g_WindowInfo));
|
||
|
}
|
||
|
|
||
|
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (INT_PTR) proc);
|
||
|
|
||
|
rc = CallWindowProc(proc, hWnd, uMsg, wParam, lParam);
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Code to defer app activation of minimized app until it is restored.
|
||
|
*/
|
||
|
switch(uMsg)
|
||
|
{
|
||
|
#ifdef WIN95
|
||
|
case WM_POWERBROADCAST:
|
||
|
if ((wParam == PBT_APMSUSPEND) || (wParam == PBT_APMSTANDBY))
|
||
|
#else
|
||
|
//winnt doesn't know about standby vs suspend
|
||
|
case WM_POWER:
|
||
|
if (wParam == PWR_SUSPENDREQUEST)
|
||
|
#endif
|
||
|
{
|
||
|
DPF(4, "WM_POWERBROADCAST: deactivating application");
|
||
|
SendMessage(hWnd, WM_ACTIVATEAPP, 0, GetCurrentThreadId());
|
||
|
}
|
||
|
break;
|
||
|
case WM_SIZE:
|
||
|
DPF(4, "WM_SIZE hWnd=%X wp=%04X, lp=%08X dwFlags=%08lx", hWnd, wParam,
|
||
|
lParam, g_WindowInfo.dwFlags);
|
||
|
|
||
|
if (!(g_WindowInfo.dwFlags & WININFO_INACTIVATEAPP)
|
||
|
&& ((wParam == SIZE_RESTORED) || (wParam == SIZE_MAXIMIZED))
|
||
|
&& (GetForegroundWindow() == hWnd))
|
||
|
{
|
||
|
#ifdef WINNT
|
||
|
//
|
||
|
// Wouldncha know it, but NT's messaging order is HUGELY different when alt-tabbing
|
||
|
// between two exclusive mode apps. The first WM_SIZE sent to the activating app is
|
||
|
// sent BEFORE the deactivating app loses FSE. This WM_SIZE is totally necessary to
|
||
|
// reactivate the activating app, but it has to wait until the app loses FSE.
|
||
|
// So, we simply wait on the exclusive mode mutex. This seems to work!
|
||
|
//
|
||
|
{
|
||
|
DWORD dwWaitResult;
|
||
|
dwWaitResult = WaitForSingleObject(hExclusiveModeMutex, INFINITE);
|
||
|
switch (dwWaitResult)
|
||
|
{
|
||
|
case WAIT_OBJECT_0:
|
||
|
case WAIT_ABANDONED:
|
||
|
ReleaseMutex(hExclusiveModeMutex);
|
||
|
break;
|
||
|
case WAIT_TIMEOUT:
|
||
|
default:
|
||
|
DDASSERT(!"Unexpected return value from WaitForSingleObject");
|
||
|
}
|
||
|
|
||
|
}
|
||
|
#endif
|
||
|
DPF(4, "WM_SIZE: Window restored, sending WM_ACTIVATEAPP");
|
||
|
PostMessage(hWnd, WM_ACTIVATEAPP, 1, GetCurrentThreadId());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPF(4, "WM_SIZE: Window restored, NOT sending WM_ACTIVATEAPP");
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case WM_ACTIVATEAPP:
|
||
|
if (IsIconic(hWnd) && wParam)
|
||
|
{
|
||
|
DPF(4, "WM_ACTIVATEAPP: Ignoring while minimized");
|
||
|
return 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_WindowInfo.dwFlags |= WININFO_INACTIVATEAPP;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* is directdraw involved here?
|
||
|
*/
|
||
|
if (!(g_WindowInfo.dwFlags & WININFO_DDRAWHOOKED))
|
||
|
{
|
||
|
rc = CallWindowProc(proc, hWnd, uMsg, wParam, lParam);
|
||
|
|
||
|
// clear the WININFO_INACTIVATEAPP bit, but make sure to make sure
|
||
|
// we are still hooked!
|
||
|
if (uMsg == WM_ACTIVATEAPP && (g_WindowInfo.hWnd == hWnd))
|
||
|
{
|
||
|
g_WindowInfo.dwFlags &= ~WININFO_INACTIVATEAPP;
|
||
|
}
|
||
|
return rc;
|
||
|
}
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
if (!IsIconic(hWnd))
|
||
|
{
|
||
|
if (GetForegroundWindow() == hWnd)
|
||
|
{
|
||
|
HWND hwndT;
|
||
|
RECT rc,rcT;
|
||
|
|
||
|
GetWindowRect(hWnd, &rc);
|
||
|
|
||
|
for (hwndT = GetWindow(hWnd, GW_HWNDFIRST);
|
||
|
hwndT && hwndT != hWnd;
|
||
|
hwndT = GetWindow(hwndT, GW_HWNDNEXT))
|
||
|
{
|
||
|
if (IsWindowVisible(hwndT))
|
||
|
{
|
||
|
GetWindowRect(hwndT, &rcT);
|
||
|
if (IntersectRect(&rcT, &rcT, &rc))
|
||
|
{
|
||
|
DPF(4, "Window %08x is on top of us!!", hwndT);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* NOTE: we don't take the DLL csect here. By not doing this, we can
|
||
|
* up the performance here. However, this means that the application
|
||
|
* could have a separate thread kill exclusive mode while window
|
||
|
* messages were being processed. This could cause our death.
|
||
|
* Is this OK?
|
||
|
*/
|
||
|
|
||
|
switch(uMsg)
|
||
|
{
|
||
|
/*
|
||
|
* WM_SYSKEYUP
|
||
|
*
|
||
|
* watch for system keys of app trying to switch away from us...
|
||
|
*
|
||
|
* we only need to do this on Win95 because we have disabled all
|
||
|
* the task-switching hot keys. on NT we will get switched
|
||
|
* away from normaly by the system.
|
||
|
*/
|
||
|
case WM_SYSKEYUP:
|
||
|
DPF(4, "WM_SYSKEYUP: wParam=%08lx lParam=%08lx", wParam, lParam);
|
||
|
get_away = FALSE;
|
||
|
if (wParam == VK_TAB)
|
||
|
{
|
||
|
if (lParam & 0x20000000l)
|
||
|
{
|
||
|
if (g_WindowInfo.dwFlags & WININFO_IGNORENEXTALTTAB)
|
||
|
{
|
||
|
DPF(4, "AHHHHHHHHHHHH Ignoring AltTab");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
get_away = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (wParam == VK_ESCAPE)
|
||
|
{
|
||
|
get_away = TRUE;
|
||
|
}
|
||
|
|
||
|
g_WindowInfo.dwFlags &= ~WININFO_IGNORENEXTALTTAB;
|
||
|
|
||
|
if (get_away)
|
||
|
{
|
||
|
DPF(4, "Hot key pressed, switching away from app");
|
||
|
PostMessage(hWnd, WM_ACTIVATEAPP, 0, GetCurrentThreadId());
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
/*
|
||
|
* WM_SYSCOMMAND
|
||
|
*
|
||
|
* watch for screen savers, and don't allow them!
|
||
|
*
|
||
|
*/
|
||
|
case WM_SYSCOMMAND:
|
||
|
|
||
|
switch(wParam)
|
||
|
{
|
||
|
case SC_SCREENSAVE:
|
||
|
DPF(4, "Ignoring screen saver!");
|
||
|
return 1;
|
||
|
// allow window to be restored even if it has popup(s)
|
||
|
case SC_RESTORE:
|
||
|
ShowWindow(hWnd, SW_RESTORE);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
#ifdef USESHOWWINDOW
|
||
|
case WM_DISPLAYCHANGE:
|
||
|
DPF(4, "WM_DISPLAYCHANGE: %dx%dx%d", LOWORD(lParam), HIWORD(lParam), wParam);
|
||
|
|
||
|
//
|
||
|
// WM_DISPLAYCHANGE is *sent* to the thread that called
|
||
|
// change display settings, we will most likely have the
|
||
|
// direct draw lock, make sure we set the WININFO_SELFSIZE
|
||
|
// bit while calling down the chain to prevent deadlock
|
||
|
//
|
||
|
g_WindowInfo.dwFlags |= WININFO_SELFSIZE;
|
||
|
|
||
|
rc = CallWindowProc(proc, hWnd, uMsg, wParam, lParam);
|
||
|
|
||
|
g_WindowInfo.dwFlags &= ~WININFO_SELFSIZE;
|
||
|
|
||
|
return rc;
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* WM_ACTIVATEAPP
|
||
|
*
|
||
|
* the application has been reactivated. In this case, we need to
|
||
|
* reset the mode
|
||
|
*
|
||
|
*/
|
||
|
case WM_ACTIVATEAPP:
|
||
|
|
||
|
is_active = (BOOL)wParam && GetForegroundWindow() == hWnd && !IsIconic(hWnd);
|
||
|
|
||
|
if (!is_active && wParam != 0)
|
||
|
{
|
||
|
DPF(4, "WM_ACTIVATEAPP: setting wParam to 0, not realy active");
|
||
|
wParam = 0;
|
||
|
}
|
||
|
|
||
|
if (is_active)
|
||
|
{
|
||
|
DPF(4, "WM_ACTIVATEAPP: BEGIN Activating app pid=%08lx, tid=%08lx",
|
||
|
GetCurrentProcessId(), GetCurrentThreadId());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPF(4, "WM_ACTIVATEAPP: BEGIN Deactivating app pid=%08lx, tid=%08lx",
|
||
|
GetCurrentProcessId(), GetCurrentThreadId());
|
||
|
}
|
||
|
if (is_active && (g_WindowInfo.dwDDFlags & DDRAWILCL_ACTIVEYES))
|
||
|
{
|
||
|
DPF(4, "*** Already activated");
|
||
|
}
|
||
|
else
|
||
|
if (!is_active && (g_WindowInfo.dwDDFlags & DDRAWILCL_ACTIVENO))
|
||
|
{
|
||
|
DPF(4, "*** Already deactivated");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (FAILED(handleActivateApp(is_active)))
|
||
|
break;
|
||
|
DPF(4, "*** Active state changing");
|
||
|
if (is_active)
|
||
|
{
|
||
|
#ifdef DEBUG
|
||
|
if (GetAsyncKeyState(VK_MENU) < 0)
|
||
|
DPF(4, "ALT key is DOWN");
|
||
|
|
||
|
if (GetKeyState(VK_MENU) < 0)
|
||
|
DPF(4, "we think the ALT key is DOWN");
|
||
|
#endif DEBUG
|
||
|
|
||
|
if (GetAsyncKeyState(VK_MENU) < 0)
|
||
|
{
|
||
|
g_WindowInfo.dwFlags |= WININFO_IGNORENEXTALTTAB;
|
||
|
DPF(4, "AHHHHHHH Setting to ignore next alt tab");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_WindowInfo.dwFlags &= ~WININFO_IGNORENEXTALTTAB;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* In the multi-mon scenario, it's possible that multiple
|
||
|
* devices are using this same window, so we need to do
|
||
|
* the following for each device.
|
||
|
*/
|
||
|
g_WindowInfo.dwDDFlags &= ~(DDRAWILCL_ACTIVEYES|DDRAWILCL_ACTIVENO);
|
||
|
if (is_active)
|
||
|
{
|
||
|
g_WindowInfo.dwDDFlags |= DDRAWILCL_ACTIVEYES;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_WindowInfo.dwDDFlags |= DDRAWILCL_ACTIVENO;
|
||
|
}
|
||
|
}
|
||
|
#ifdef DEBUG
|
||
|
if (is_active)
|
||
|
{
|
||
|
DPF(4, "WM_ACTIVATEAPP: DONE Activating app pid=%08lx, tid=%08lx",
|
||
|
GetCurrentProcessId(), GetCurrentThreadId());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPF(4, "WM_ACTIVATEAPP: DONE Deactivating app pid=%08lx, tid=%08lx",
|
||
|
GetCurrentProcessId(), GetCurrentThreadId());
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
rc = CallWindowProc(proc, hWnd, uMsg, wParam, lParam);
|
||
|
|
||
|
// clear the WININFO_INACTIVATEAPP bit, but make sure to make sure
|
||
|
// we are still hooked!
|
||
|
if (g_WindowInfo.hWnd == hWnd)
|
||
|
{
|
||
|
g_WindowInfo.dwFlags &= ~WININFO_INACTIVATEAPP;
|
||
|
}
|
||
|
return rc;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
rc = CallWindowProc(proc, hWnd, uMsg, wParam, lParam);
|
||
|
return rc;
|
||
|
|
||
|
} /* WindowProc */
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CSwapChain::SetAppHWnd"
|
||
|
|
||
|
/*
|
||
|
* SetAppHWnd
|
||
|
*
|
||
|
* Set the WindowList struct up with the app's hwnd info
|
||
|
* Must be called with Device crit-sec taken and with the
|
||
|
* Global Exclusive Mode Mutex
|
||
|
*/
|
||
|
HRESULT
|
||
|
CSwapChain::SetAppHWnd()
|
||
|
{
|
||
|
|
||
|
HWND hWnd, hEnumWnd;
|
||
|
|
||
|
if (m_PresentationData.Windowed)
|
||
|
hWnd = NULL;
|
||
|
else
|
||
|
hWnd = Device()->FocusWindow();
|
||
|
|
||
|
hEnumWnd = Device()->Enum()->ExclusiveOwnerWindow();
|
||
|
if (hEnumWnd)
|
||
|
{
|
||
|
if (hEnumWnd == Device()->FocusWindow())
|
||
|
{
|
||
|
if (m_PresentationData.Windowed)
|
||
|
{
|
||
|
Device()->Enum()->SetFullScreenDevice(
|
||
|
Device()->AdapterIndex(), NULL);
|
||
|
|
||
|
// If our enum still has a focus-
|
||
|
// window then that means another
|
||
|
// device has gone FS with the same
|
||
|
// focus-window; so do nothing
|
||
|
if (Device()->Enum()->ExclusiveOwnerWindow())
|
||
|
return DD_OK;
|
||
|
|
||
|
// Else, fall through so that
|
||
|
// we tear down the winproc.
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Device()->Enum()->SetFullScreenDevice(
|
||
|
Device()->AdapterIndex(), Device());
|
||
|
// Already hooked - no need to do more
|
||
|
return DD_OK;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* check if this isn't doing anything
|
||
|
*/
|
||
|
if (hWnd == NULL && g_WindowInfo.hWnd == NULL)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// Check if we have a case of different HWND trying to be hooked
|
||
|
if (hWnd && g_WindowInfo.hWnd && g_WindowInfo.hWnd != hWnd)
|
||
|
{
|
||
|
DPF(1, "Hwnd %08lx no good: Different Hwnd (%08lx) already set for Device",
|
||
|
hWnd, g_WindowInfo.hWnd);
|
||
|
return D3DERR_INVALIDCALL;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* are we shutting an HWND down?
|
||
|
*/
|
||
|
if (hWnd == NULL)
|
||
|
{
|
||
|
if (IsWindow(g_WindowInfo.hWnd))
|
||
|
{
|
||
|
WNDPROC proc;
|
||
|
|
||
|
proc = (WNDPROC) GetWindowLongPtr(g_WindowInfo.hWnd, GWLP_WNDPROC);
|
||
|
|
||
|
if (proc != (WNDPROC) WindowProc &&
|
||
|
proc != (WNDPROC) g_WindowInfo.lpWndProc)
|
||
|
{
|
||
|
DPF(3, "Window has been subclassed; cannot restore!");
|
||
|
g_WindowInfo.dwFlags |= WININFO_ZOMBIE;
|
||
|
}
|
||
|
else if (GetWindowThreadProcessId(g_WindowInfo.hWnd, NULL) !=
|
||
|
GetCurrentThreadId())
|
||
|
{
|
||
|
DPF(3, "intra-thread window unhook, letting window proc do it");
|
||
|
g_WindowInfo.dwFlags |= WININFO_UNHOOK;
|
||
|
g_WindowInfo.dwFlags |= WININFO_ZOMBIE;
|
||
|
PostMessage(g_WindowInfo.hWnd, WM_NULL, 0, 0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
DPF(4, "Unsubclassing window %08lx", g_WindowInfo.hWnd);
|
||
|
SetWindowLongPtr(g_WindowInfo.hWnd, GWLP_WNDPROC,
|
||
|
(INT_PTR) g_WindowInfo.lpWndProc);
|
||
|
|
||
|
ZeroMemory(&g_WindowInfo, sizeof(g_WindowInfo));
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ZeroMemory(&g_WindowInfo, sizeof(g_WindowInfo));
|
||
|
}
|
||
|
|
||
|
Device()->Enum()->SetFullScreenDevice(
|
||
|
Device()->AdapterIndex(), NULL);
|
||
|
}
|
||
|
/*
|
||
|
* changing or adding an hwnd then...
|
||
|
*/
|
||
|
else
|
||
|
{
|
||
|
/*
|
||
|
* brand new object...
|
||
|
*/
|
||
|
if (g_WindowInfo.dwMagic == 0)
|
||
|
{
|
||
|
g_WindowInfo.dwMagic = WININFO_MAGIC;
|
||
|
g_WindowInfo.hWnd = hWnd;
|
||
|
g_WindowInfo.lpWndProc = (WNDPROC) GetWindowLongPtr(hWnd, GWLP_WNDPROC);
|
||
|
|
||
|
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (INT_PTR) WindowProc);
|
||
|
}
|
||
|
|
||
|
g_WindowInfo.pEnum = Device()->Enum();
|
||
|
g_WindowInfo.dwFlags |= WININFO_DDRAWHOOKED;
|
||
|
|
||
|
// Sanity check
|
||
|
DXGASSERT(Device()->Enum()->ExclusiveOwnerWindow() == NULL);
|
||
|
|
||
|
Device()->Enum()->SetFullScreenDevice(
|
||
|
Device()->AdapterIndex(), Device());
|
||
|
DPF(4, "Subclassing window %08lx", g_WindowInfo.hWnd);
|
||
|
}
|
||
|
return S_OK;
|
||
|
|
||
|
} /* SetAppHWnd */
|
||
|
extern "C" void ResetUniqueness( HANDLE hDD );
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CSwapChain::DoneExclusiveMode"
|
||
|
/*
|
||
|
* DoneExclusiveMode
|
||
|
*/
|
||
|
void
|
||
|
CSwapChain::DoneExclusiveMode(BOOL bChangeWindow)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
BOOL bMinimize = TRUE;
|
||
|
DPF(4, "DoneExclusiveMode");
|
||
|
if (m_bExclusiveMode)
|
||
|
{
|
||
|
D3D8_SETMODEDATA SetModeData;
|
||
|
m_bExclusiveMode = FALSE;
|
||
|
DPF(4, "INACTIVE: %08lx: Restoring original mode (%dx%dx%dx%d)",
|
||
|
GetCurrentProcessId(), Device()->DesktopMode().Width,
|
||
|
Device()->DesktopMode().Height,Device()->DesktopMode().Format,
|
||
|
Device()->DesktopMode().RefreshRate);
|
||
|
SetModeData.hDD = Device()->GetHandle();
|
||
|
SetModeData.dwWidth = Device()->DesktopMode().Width;
|
||
|
SetModeData.dwHeight = Device()->DesktopMode().Height;
|
||
|
SetModeData.Format = Device()->DesktopMode().Format;
|
||
|
SetModeData.dwRefreshRate = Device()->DesktopMode().RefreshRate;
|
||
|
SetModeData.bRestore = TRUE;
|
||
|
|
||
|
Device()->GetHalCallbacks()->SetMode(&SetModeData);
|
||
|
if (SetModeData.ddRVal != S_OK)
|
||
|
{
|
||
|
DPF_ERR("Unable to restore to original desktop mode");
|
||
|
// return SetModeData.ddRVal;
|
||
|
}
|
||
|
// some part of the runtime count on that SetMode cause device
|
||
|
// lost, that's not true for whistler anymore if this fullscreen
|
||
|
// mode happens to be the same as the original desktop mode.
|
||
|
// so we ResetUniqueness to force the device to get lost.
|
||
|
if (Device()->DesktopMode().Width == Width() &&
|
||
|
Device()->DesktopMode().Height == Height() &&
|
||
|
Device()->DesktopMode().Format == BackBufferFormat())
|
||
|
ResetUniqueness(Device()->GetHandle());
|
||
|
|
||
|
DPF(4, "Enabling error mode, hotkeys");
|
||
|
SetErrorMode(m_uiErrorMode);
|
||
|
|
||
|
#ifdef WINNT
|
||
|
// Restore cursor shadow coming out of fullscreen
|
||
|
SystemParametersInfo(SPI_SETCURSORSHADOW, 0, (LPVOID)m_pCursorShadow, 0);
|
||
|
#endif
|
||
|
|
||
|
// Restore reactive menus coming out of fullscreen:
|
||
|
SystemParametersInfo(SPI_SETHOTTRACKING, 0, (LPVOID)m_pHotTracking, 0);
|
||
|
InterlockedExchange(&m_lSetIME, m_lIMEState + 1);
|
||
|
|
||
|
#ifdef WINNT
|
||
|
// Notify the display driver that we are chaning cooperative level
|
||
|
|
||
|
D3D8_SETEXCLUSIVEMODEDATA ExclusiveData;
|
||
|
|
||
|
ExclusiveData.hDD = Device()->GetHandle();
|
||
|
ExclusiveData.dwEnterExcl = FALSE;
|
||
|
Device()->GetHalCallbacks()->SetExclusiveMode(&ExclusiveData);
|
||
|
/*
|
||
|
* If RestoreDisplayMode failed, we are probably on a different desktop. In this case,
|
||
|
* we should not minimize the window or else things won't work right when we switch
|
||
|
* back to the original desktop.
|
||
|
*/
|
||
|
if (SetModeData.ddRVal != S_OK)
|
||
|
{
|
||
|
HDESK hDesktop;
|
||
|
static BYTE szName1[256];
|
||
|
static BYTE szName2[256];
|
||
|
DWORD dwTemp;
|
||
|
|
||
|
// Get the name of the current desktop
|
||
|
hDesktop = OpenInputDesktop( 0, FALSE, DESKTOP_READOBJECTS );
|
||
|
GetUserObjectInformation( hDesktop, UOI_NAME, szName1, sizeof( szName1 ), &dwTemp );
|
||
|
CloseDesktop( hDesktop );
|
||
|
|
||
|
// Get the name of the apps' desktop
|
||
|
hDesktop = GetThreadDesktop( GetCurrentThreadId() );
|
||
|
GetUserObjectInformation( hDesktop, UOI_NAME, szName2, sizeof( szName2 ), &dwTemp );
|
||
|
if( lstrcmp( (const LPCSTR)szName1, (const LPCSTR)szName2 ) )
|
||
|
{
|
||
|
bMinimize = FALSE;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
if (bChangeWindow)
|
||
|
{
|
||
|
HIDESHOW_IME();
|
||
|
/*
|
||
|
* minimize window if deactivating
|
||
|
*/
|
||
|
if (IsWindowVisible(m_PresentationData.hDeviceWindow) && bMinimize)
|
||
|
{
|
||
|
g_WindowInfo.dwFlags |= WININFO_SELFSIZE;
|
||
|
#ifdef USESHOWWINDOW
|
||
|
ShowWindow(m_PresentationData.hDeviceWindow, SW_SHOWMINNOACTIVE);
|
||
|
#else
|
||
|
SetWindowPos(m_PresentationData.hDeviceWindow, NULL, 0, 0, 0, 0,
|
||
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
||
|
#endif
|
||
|
g_WindowInfo.dwFlags &= ~WININFO_SELFSIZE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} /* DoneExclusiveMode */
|
||
|
|
||
|
#undef DPF_MODNAME
|
||
|
#define DPF_MODNAME "CSwapChain::StartExclusiveMode"
|
||
|
/*
|
||
|
* StartExclusiveMode
|
||
|
*/
|
||
|
void
|
||
|
CSwapChain::StartExclusiveMode(BOOL bChangeWindow)
|
||
|
{
|
||
|
DWORD dwWaitResult;
|
||
|
DPF(4, "StartExclusiveMode");
|
||
|
|
||
|
/*
|
||
|
* Preceeding code should have taken this mutex already.
|
||
|
*/
|
||
|
if (!m_bExclusiveMode)
|
||
|
{
|
||
|
m_bExclusiveMode = TRUE;
|
||
|
#if defined(WINNT) && defined(DEBUG)
|
||
|
dwWaitResult = WaitForSingleObject(hExclusiveModeMutex, 0);
|
||
|
DDASSERT(dwWaitResult == WAIT_OBJECT_0);
|
||
|
ReleaseMutex(hExclusiveModeMutex);
|
||
|
#endif
|
||
|
m_uiErrorMode = SetErrorMode(SEM_NOGPFAULTERRORBOX |
|
||
|
SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
|
||
|
|
||
|
#ifdef WINNT
|
||
|
// Save current cursor shadow setting
|
||
|
SystemParametersInfo(SPI_GETCURSORSHADOW, 0, (LPVOID) &(m_pCursorShadow), 0);
|
||
|
SystemParametersInfo(SPI_SETCURSORSHADOW, 0, 0, 0);
|
||
|
#endif
|
||
|
|
||
|
// Save current hot-tracking setting
|
||
|
SystemParametersInfo(SPI_GETHOTTRACKING, 0, (LPVOID) &(m_pHotTracking), 0);
|
||
|
SystemParametersInfo(SPI_GETSHOWIMEUI, 0, (LPVOID) &(m_lIMEState), 0);
|
||
|
|
||
|
//And turn it off as we go into exclusive mode
|
||
|
SystemParametersInfo(SPI_SETHOTTRACKING, 0, 0, 0);
|
||
|
InterlockedExchange(&m_lSetIME, FALSE + 1);
|
||
|
|
||
|
#ifdef WINNT
|
||
|
// Notify the display driver that we are chaning cooperative level
|
||
|
|
||
|
D3D8_SETEXCLUSIVEMODEDATA ExclusiveData;
|
||
|
|
||
|
ExclusiveData.hDD = Device()->GetHandle();
|
||
|
ExclusiveData.dwEnterExcl = TRUE;
|
||
|
Device()->GetHalCallbacks()->SetExclusiveMode(&ExclusiveData);
|
||
|
#endif
|
||
|
if (bChangeWindow)
|
||
|
{
|
||
|
MakeFullscreen();
|
||
|
HIDESHOW_IME();
|
||
|
if (IsWindowVisible(m_PresentationData.hDeviceWindow))
|
||
|
{
|
||
|
g_WindowInfo.dwFlags |= WININFO_SELFSIZE;
|
||
|
#ifdef USESHOWWINDOW
|
||
|
ShowWindow(m_PresentationData.hDeviceWindow, SW_SHOWNOACTIVATE);
|
||
|
#else
|
||
|
{
|
||
|
RECT rc;
|
||
|
SetRect(&rc,0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
|
||
|
SetWindowPos(g_WindowInfo.hWnd, NULL,rc.left, rc.top,
|
||
|
rc.right - rc.left,rc.bottom - rc.top,
|
||
|
SWP_NOZORDER | SWP_NOACTIVATE);
|
||
|
}
|
||
|
#endif
|
||
|
g_WindowInfo.dwFlags &= ~WININFO_SELFSIZE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} /* StartExclusiveMode */
|
||
|
|
||
|
#endif //WINNT
|
||
|
// End of file : dwinproc.cpp
|