mirror of
https://github.com/narzoul/DDrawCompat
synced 2024-12-30 08:55:36 +01:00
Fixed popup menu position in scaled fullscreen mode
This commit is contained in:
parent
f7962f6e3b
commit
0584a0007a
@ -22,6 +22,7 @@
|
|||||||
#include <Gdi/Palette.h>
|
#include <Gdi/Palette.h>
|
||||||
#include <Gdi/VirtualScreen.h>
|
#include <Gdi/VirtualScreen.h>
|
||||||
#include <Gdi/Window.h>
|
#include <Gdi/Window.h>
|
||||||
|
#include <Gdi/WinProc.h>
|
||||||
#include <Win32/DisplayMode.h>
|
#include <Win32/DisplayMode.h>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -54,7 +54,8 @@ namespace Gdi
|
|||||||
bool isDisplayDc(HDC dc)
|
bool isDisplayDc(HDC dc)
|
||||||
{
|
{
|
||||||
return dc && OBJ_DC == GetObjectType(dc) && DT_RASDISPLAY == CALL_ORIG_FUNC(GetDeviceCaps)(dc, TECHNOLOGY) &&
|
return dc && OBJ_DC == GetObjectType(dc) && DT_RASDISPLAY == CALL_ORIG_FUNC(GetDeviceCaps)(dc, TECHNOLOGY) &&
|
||||||
!(CALL_ORIG_FUNC(GetWindowLongA)(CALL_ORIG_FUNC(WindowFromDC)(dc), GWL_EXSTYLE) & WS_EX_LAYERED);
|
!(CALL_ORIG_FUNC(GetWindowLongA)(CALL_ORIG_FUNC(WindowFromDC)(dc), GWL_EXSTYLE) & WS_EX_LAYERED) &&
|
||||||
|
MENU_ATOM != GetClassLong(CALL_ORIG_FUNC(WindowFromDC)(dc), GCW_ATOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
void redraw(HRGN rgn)
|
void redraw(HRGN rgn)
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
#include <D3dDdi/ScopedCriticalSection.h>
|
#include <D3dDdi/ScopedCriticalSection.h>
|
||||||
#include <DDraw/RealPrimarySurface.h>
|
#include <DDraw/RealPrimarySurface.h>
|
||||||
|
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||||
#include <Gdi/CompatDc.h>
|
#include <Gdi/CompatDc.h>
|
||||||
#include <Gdi/Cursor.h>
|
#include <Gdi/Cursor.h>
|
||||||
|
#include <Gdi/PresentationWindow.h>
|
||||||
#include <Gdi/ScrollBar.h>
|
#include <Gdi/ScrollBar.h>
|
||||||
#include <Gdi/ScrollFunctions.h>
|
#include <Gdi/ScrollFunctions.h>
|
||||||
#include <Gdi/TitleBar.h>
|
#include <Gdi/TitleBar.h>
|
||||||
@ -297,6 +299,49 @@ namespace
|
|||||||
return defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
return defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void fixPopupMenuPosition(WINDOWPOS& wp)
|
||||||
|
{
|
||||||
|
RECT mr = DDraw::PrimarySurface::getMonitorRect();
|
||||||
|
if (wp.flags & SWP_NOSIZE)
|
||||||
|
{
|
||||||
|
RECT r = {};
|
||||||
|
GetWindowRect(wp.hwnd, &r);
|
||||||
|
wp.cx = r.right - r.left;
|
||||||
|
wp.cy = r.bottom - r.top;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wp.cx > mr.right - mr.left)
|
||||||
|
{
|
||||||
|
wp.cx = mr.right - mr.left;
|
||||||
|
wp.flags &= ~SWP_NOSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wp.x + wp.cx > mr.right)
|
||||||
|
{
|
||||||
|
HWND parent = GetNextWindow(wp.hwnd, GW_HWNDNEXT);
|
||||||
|
while (Gdi::PresentationWindow::isPresentationWindow(parent))
|
||||||
|
{
|
||||||
|
parent = GetNextWindow(parent, GW_HWNDNEXT);
|
||||||
|
}
|
||||||
|
ATOM atom = parent ? static_cast<ATOM>(GetClassLong(parent, GCW_ATOM)) : 0;
|
||||||
|
if (Gdi::MENU_ATOM == atom)
|
||||||
|
{
|
||||||
|
RECT parentRect = {};
|
||||||
|
GetWindowRect(parent, &parentRect);
|
||||||
|
wp.x = max(parentRect.left + 3 - wp.cx, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wp.x = mr.right - wp.cx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wp.y + wp.cy > mr.bottom)
|
||||||
|
{
|
||||||
|
wp.y = mr.bottom - wp.cy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void hookUser32WndProc(User32WndProc& user32WndProc, WNDPROC newWndProc,
|
void hookUser32WndProc(User32WndProc& user32WndProc, WNDPROC newWndProc,
|
||||||
const std::string& procName, const std::string& className, bool isUnicode)
|
const std::string& procName, const std::string& className, bool isUnicode)
|
||||||
{
|
{
|
||||||
@ -367,31 +412,14 @@ namespace
|
|||||||
{
|
{
|
||||||
switch (msg)
|
switch (msg)
|
||||||
{
|
{
|
||||||
case WM_NCPAINT:
|
case WM_WINDOWPOSCHANGING:
|
||||||
CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
|
||||||
return onNcPaint(hwnd, origWndProc);
|
|
||||||
|
|
||||||
case WM_PAINT:
|
|
||||||
{
|
{
|
||||||
D3dDdi::ScopedCriticalSection lock;
|
LRESULT result = CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
||||||
RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME);
|
auto& wp = *reinterpret_cast<WINDOWPOS*>(lParam);
|
||||||
return onPaint(hwnd, origWndProc);
|
if (Gdi::Cursor::isEmulated() && !(wp.flags & SWP_NOMOVE))
|
||||||
}
|
{
|
||||||
|
fixPopupMenuPosition(wp);
|
||||||
case WM_PRINTCLIENT:
|
}
|
||||||
{
|
|
||||||
RECT r = {};
|
|
||||||
GetClientRect(hwnd, &r);
|
|
||||||
HDC dc = CreateCompatibleDC(nullptr);
|
|
||||||
const bool useDefaultPalette = true;
|
|
||||||
HBITMAP dib = Gdi::VirtualScreen::createOffScreenDib(r.right, r.bottom, useDefaultPalette);
|
|
||||||
HGDIOBJ origBitmap = SelectObject(dc, dib);
|
|
||||||
CallWindowProc(origWndProc, hwnd, WM_ERASEBKGND, reinterpret_cast<WPARAM>(dc), 0);
|
|
||||||
LRESULT result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast<WPARAM>(dc), lParam);
|
|
||||||
CALL_ORIG_FUNC(BitBlt)(reinterpret_cast<HDC>(wParam), 0, 0, r.right, r.bottom, dc, 0, 0, SRCCOPY);
|
|
||||||
SelectObject(dc, origBitmap);
|
|
||||||
DeleteObject(dib);
|
|
||||||
DeleteDC(dc);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -402,21 +430,15 @@ namespace
|
|||||||
if (exStyle & WS_EX_LAYERED)
|
if (exStyle & WS_EX_LAYERED)
|
||||||
{
|
{
|
||||||
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_LAYERED);
|
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_LAYERED);
|
||||||
RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_UPDATENOW);
|
|
||||||
}
|
}
|
||||||
|
RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_UPDATENOW);
|
||||||
|
DDraw::RealPrimarySurface::scheduleUpdate();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 0x1e5:
|
|
||||||
if (-1 == wParam)
|
|
||||||
{
|
|
||||||
D3dDdi::ScopedCriticalSection lock;
|
|
||||||
RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW);
|
|
||||||
}
|
|
||||||
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return defPaintProc(hwnd, msg, wParam, lParam, origWndProc);
|
DDraw::RealPrimarySurface::scheduleUpdate();
|
||||||
|
return CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <Common/ScopedSrwLock.h>
|
#include <Common/ScopedSrwLock.h>
|
||||||
#include <Dll/Dll.h>
|
#include <Dll/Dll.h>
|
||||||
#include <DDraw/RealPrimarySurface.h>
|
#include <DDraw/RealPrimarySurface.h>
|
||||||
|
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||||
#include <Gdi/CompatDc.h>
|
#include <Gdi/CompatDc.h>
|
||||||
#include <Gdi/Cursor.h>
|
#include <Gdi/Cursor.h>
|
||||||
#include <Gdi/Dc.h>
|
#include <Gdi/Dc.h>
|
||||||
@ -27,6 +28,7 @@ namespace
|
|||||||
WNDPROC wndProcW;
|
WNDPROC wndProcW;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::map<HMENU, UINT> g_menuMaxHeight;
|
||||||
std::set<Gdi::WindowPosChangeNotifyFunc> g_windowPosChangeNotifyFuncs;
|
std::set<Gdi::WindowPosChangeNotifyFunc> g_windowPosChangeNotifyFuncs;
|
||||||
|
|
||||||
Compat::SrwLock g_windowProcSrwLock;
|
Compat::SrwLock g_windowProcSrwLock;
|
||||||
@ -38,6 +40,8 @@ namespace
|
|||||||
void onCreateWindow(HWND hwnd);
|
void onCreateWindow(HWND hwnd);
|
||||||
void onDestroyWindow(HWND hwnd);
|
void onDestroyWindow(HWND hwnd);
|
||||||
void onGetMinMaxInfo(MINMAXINFO& mmi);
|
void onGetMinMaxInfo(MINMAXINFO& mmi);
|
||||||
|
void onInitMenuPopup(HMENU menu);
|
||||||
|
void onUninitMenuPopup(HMENU menu);
|
||||||
void onWindowPosChanged(HWND hwnd, const WINDOWPOS& wp);
|
void onWindowPosChanged(HWND hwnd, const WINDOWPOS& wp);
|
||||||
void onWindowPosChanging(HWND hwnd, WINDOWPOS& wp);
|
void onWindowPosChanging(HWND hwnd, WINDOWPOS& wp);
|
||||||
void setWindowProc(HWND hwnd, WNDPROC wndProcA, WNDPROC wndProcW);
|
void setWindowProc(HWND hwnd, WNDPROC wndProcA, WNDPROC wndProcW);
|
||||||
@ -71,6 +75,10 @@ namespace
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WM_UNINITMENUPOPUP:
|
||||||
|
onUninitMenuPopup(reinterpret_cast<HMENU>(wParam));
|
||||||
|
break;
|
||||||
|
|
||||||
case WM_WINDOWPOSCHANGED:
|
case WM_WINDOWPOSCHANGED:
|
||||||
onWindowPosChanged(hwnd, *reinterpret_cast<WINDOWPOS*>(lParam));
|
onWindowPosChanged(hwnd, *reinterpret_cast<WINDOWPOS*>(lParam));
|
||||||
break;
|
break;
|
||||||
@ -88,6 +96,10 @@ namespace
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case WM_INITMENUPOPUP:
|
||||||
|
onInitMenuPopup(reinterpret_cast<HMENU>(wParam));
|
||||||
|
break;
|
||||||
|
|
||||||
case WM_NCDESTROY:
|
case WM_NCDESTROY:
|
||||||
onDestroyWindow(hwnd);
|
onDestroyWindow(hwnd);
|
||||||
break;
|
break;
|
||||||
@ -234,6 +246,40 @@ namespace
|
|||||||
mmi.ptMaxSize.y = mi.rcMonitor.bottom - 2 * mmi.ptMaxPosition.y;
|
mmi.ptMaxSize.y = mi.rcMonitor.bottom - 2 * mmi.ptMaxPosition.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void onInitMenuPopup(HMENU menu)
|
||||||
|
{
|
||||||
|
if (Gdi::Cursor::isEmulated())
|
||||||
|
{
|
||||||
|
MENUINFO mi = {};
|
||||||
|
mi.cbSize = sizeof(mi);
|
||||||
|
mi.fMask = MIM_MAXHEIGHT;
|
||||||
|
GetMenuInfo(menu, &mi);
|
||||||
|
|
||||||
|
RECT mr = DDraw::PrimarySurface::getMonitorRect();
|
||||||
|
UINT maxHeight = mr.bottom - mr.top;
|
||||||
|
if (0 == mi.cyMax || mi.cyMax > maxHeight)
|
||||||
|
{
|
||||||
|
g_menuMaxHeight[menu] = mi.cyMax;
|
||||||
|
mi.cyMax = maxHeight;
|
||||||
|
SetMenuInfo(menu, &mi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void onUninitMenuPopup(HMENU menu)
|
||||||
|
{
|
||||||
|
auto it = g_menuMaxHeight.find(menu);
|
||||||
|
if (it != g_menuMaxHeight.end())
|
||||||
|
{
|
||||||
|
MENUINFO mi = {};
|
||||||
|
mi.cbSize = sizeof(mi);
|
||||||
|
mi.fMask = MIM_MAXHEIGHT;
|
||||||
|
mi.cyMax = it->second;
|
||||||
|
SetMenuInfo(menu, &mi);
|
||||||
|
g_menuMaxHeight.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void onWindowPosChanged(HWND hwnd, const WINDOWPOS& wp)
|
void onWindowPosChanged(HWND hwnd, const WINDOWPOS& wp)
|
||||||
{
|
{
|
||||||
for (auto notifyFunc : g_windowPosChangeNotifyFuncs)
|
for (auto notifyFunc : g_windowPosChangeNotifyFuncs)
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include <D3dDdi/KernelModeThunks.h>
|
#include <D3dDdi/KernelModeThunks.h>
|
||||||
#include <D3dDdi/ScopedCriticalSection.h>
|
#include <D3dDdi/ScopedCriticalSection.h>
|
||||||
#include <DDraw/RealPrimarySurface.h>
|
#include <DDraw/RealPrimarySurface.h>
|
||||||
|
#include <Gdi/Gdi.h>
|
||||||
#include <Gdi/PresentationWindow.h>
|
#include <Gdi/PresentationWindow.h>
|
||||||
#include <Gdi/VirtualScreen.h>
|
#include <Gdi/VirtualScreen.h>
|
||||||
#include <Gdi/Window.h>
|
#include <Gdi/Window.h>
|
||||||
@ -31,6 +32,7 @@ namespace
|
|||||||
Gdi::Region windowRegion;
|
Gdi::Region windowRegion;
|
||||||
Gdi::Region visibleRegion;
|
Gdi::Region visibleRegion;
|
||||||
Gdi::Region invalidatedRegion;
|
Gdi::Region invalidatedRegion;
|
||||||
|
bool isMenu;
|
||||||
bool isLayered;
|
bool isLayered;
|
||||||
bool isVisibleRegionChanged;
|
bool isVisibleRegionChanged;
|
||||||
|
|
||||||
@ -40,6 +42,7 @@ namespace
|
|||||||
, windowRect{}
|
, windowRect{}
|
||||||
, clientRect{}
|
, clientRect{}
|
||||||
, windowRegion(nullptr)
|
, windowRegion(nullptr)
|
||||||
|
, isMenu(Gdi::MENU_ATOM == GetClassLong(hwnd, GCW_ATOM))
|
||||||
, isLayered(true)
|
, isLayered(true)
|
||||||
, isVisibleRegionChanged(false)
|
, isVisibleRegionChanged(false)
|
||||||
{
|
{
|
||||||
@ -196,7 +199,7 @@ namespace
|
|||||||
g_windowZOrder.push_back(&it->second);
|
g_windowZOrder.push_back(&it->second);
|
||||||
|
|
||||||
const LONG exStyle = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_EXSTYLE);
|
const LONG exStyle = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_EXSTYLE);
|
||||||
const bool isLayered = exStyle & WS_EX_LAYERED;
|
const bool isLayered = it->second.isMenu || (exStyle & WS_EX_LAYERED);
|
||||||
const bool isVisible = IsWindowVisible(hwnd) && !IsIconic(hwnd);
|
const bool isVisible = IsWindowVisible(hwnd) && !IsIconic(hwnd);
|
||||||
bool setPresentationWindowRgn = false;
|
bool setPresentationWindowRgn = false;
|
||||||
|
|
||||||
@ -243,7 +246,10 @@ namespace
|
|||||||
visibleRegion = wi.rcWindow;
|
visibleRegion = wi.rcWindow;
|
||||||
}
|
}
|
||||||
visibleRegion &= context.virtualScreenRegion;
|
visibleRegion &= context.virtualScreenRegion;
|
||||||
visibleRegion -= context.obscuredRegion;
|
if (!it->second.isMenu)
|
||||||
|
{
|
||||||
|
visibleRegion -= context.obscuredRegion;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isLayered && !(exStyle & WS_EX_TRANSPARENT))
|
if (!isLayered && !(exStyle & WS_EX_TRANSPARENT))
|
||||||
{
|
{
|
||||||
@ -327,7 +333,7 @@ namespace Gdi
|
|||||||
{
|
{
|
||||||
D3dDdi::ScopedCriticalSection lock;
|
D3dDdi::ScopedCriticalSection lock;
|
||||||
auto it = g_windows.find(hwnd);
|
auto it = g_windows.find(hwnd);
|
||||||
if (it != g_windows.end())
|
if (it != g_windows.end() && !it->second.isMenu)
|
||||||
{
|
{
|
||||||
const bool isLayered = GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED;
|
const bool isLayered = GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_LAYERED;
|
||||||
if (isLayered != it->second.isLayered)
|
if (isLayered != it->second.isLayered)
|
||||||
@ -356,16 +362,15 @@ namespace Gdi
|
|||||||
it->second.isVisibleRegionChanged = false;
|
it->second.isVisibleRegionChanged = false;
|
||||||
const LONG origWndProc = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_WNDPROC);
|
const LONG origWndProc = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_WNDPROC);
|
||||||
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, reinterpret_cast<LONG>(CALL_ORIG_FUNC(DefWindowProcA)));
|
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, reinterpret_cast<LONG>(CALL_ORIG_FUNC(DefWindowProcA)));
|
||||||
if (it->second.isLayered)
|
Gdi::Region rgn(it->second.isLayered ? it->second.windowRegion : it->second.visibleRegion);
|
||||||
|
if (!it->second.isLayered)
|
||||||
{
|
{
|
||||||
SetWindowRgn(hwnd, Gdi::Region(it->second.windowRegion).release(), FALSE);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Gdi::Region rgn(it->second.visibleRegion);
|
|
||||||
rgn.offset(-it->second.windowRect.left, -it->second.windowRect.top);
|
rgn.offset(-it->second.windowRect.left, -it->second.windowRect.top);
|
||||||
rgn |= REGION_OVERRIDE_MARKER_RECT;
|
rgn |= REGION_OVERRIDE_MARKER_RECT;
|
||||||
SetWindowRgn(hwnd, rgn, FALSE);
|
}
|
||||||
|
if (SetWindowRgn(hwnd, rgn, FALSE))
|
||||||
|
{
|
||||||
|
rgn.release();
|
||||||
}
|
}
|
||||||
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, origWndProc);
|
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, origWndProc);
|
||||||
}
|
}
|
||||||
@ -485,9 +490,9 @@ namespace Gdi
|
|||||||
SelectClipRgn(dstDc, rgn);
|
SelectClipRgn(dstDc, rgn);
|
||||||
|
|
||||||
COLORREF colorKey = 0;
|
COLORREF colorKey = 0;
|
||||||
BYTE alpha = 0;
|
BYTE alpha = 255;
|
||||||
DWORD flags = 0;
|
DWORD flags = ULW_ALPHA;
|
||||||
if (CALL_ORIG_FUNC(GetLayeredWindowAttributes)(window.hwnd, &colorKey, &alpha, &flags))
|
if (window.isMenu || CALL_ORIG_FUNC(GetLayeredWindowAttributes)(window.hwnd, &colorKey, &alpha, &flags))
|
||||||
{
|
{
|
||||||
if (flags & LWA_COLORKEY)
|
if (flags & LWA_COLORKEY)
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user