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/VirtualScreen.h>
|
||||
#include <Gdi/Window.h>
|
||||
#include <Gdi/WinProc.h>
|
||||
#include <Win32/DisplayMode.h>
|
||||
|
||||
namespace
|
||||
|
@ -54,7 +54,8 @@ namespace Gdi
|
||||
bool isDisplayDc(HDC dc)
|
||||
{
|
||||
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)
|
||||
|
@ -1,7 +1,9 @@
|
||||
#include <D3dDdi/ScopedCriticalSection.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <Gdi/CompatDc.h>
|
||||
#include <Gdi/Cursor.h>
|
||||
#include <Gdi/PresentationWindow.h>
|
||||
#include <Gdi/ScrollBar.h>
|
||||
#include <Gdi/ScrollFunctions.h>
|
||||
#include <Gdi/TitleBar.h>
|
||||
@ -297,6 +299,49 @@ namespace
|
||||
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,
|
||||
const std::string& procName, const std::string& className, bool isUnicode)
|
||||
{
|
||||
@ -367,31 +412,14 @@ namespace
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case WM_NCPAINT:
|
||||
CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
||||
return onNcPaint(hwnd, origWndProc);
|
||||
|
||||
case WM_PAINT:
|
||||
case WM_WINDOWPOSCHANGING:
|
||||
{
|
||||
D3dDdi::ScopedCriticalSection lock;
|
||||
RedrawWindow(hwnd, nullptr, nullptr, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME);
|
||||
return onPaint(hwnd, origWndProc);
|
||||
}
|
||||
|
||||
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);
|
||||
LRESULT result = CallWindowProc(origWndProc, hwnd, msg, wParam, lParam);
|
||||
auto& wp = *reinterpret_cast<WINDOWPOS*>(lParam);
|
||||
if (Gdi::Cursor::isEmulated() && !(wp.flags & SWP_NOMOVE))
|
||||
{
|
||||
fixPopupMenuPosition(wp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -402,21 +430,15 @@ namespace
|
||||
if (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;
|
||||
}
|
||||
|
||||
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:
|
||||
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 <Dll/Dll.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <DDraw/Surfaces/PrimarySurface.h>
|
||||
#include <Gdi/CompatDc.h>
|
||||
#include <Gdi/Cursor.h>
|
||||
#include <Gdi/Dc.h>
|
||||
@ -27,6 +28,7 @@ namespace
|
||||
WNDPROC wndProcW;
|
||||
};
|
||||
|
||||
std::map<HMENU, UINT> g_menuMaxHeight;
|
||||
std::set<Gdi::WindowPosChangeNotifyFunc> g_windowPosChangeNotifyFuncs;
|
||||
|
||||
Compat::SrwLock g_windowProcSrwLock;
|
||||
@ -38,6 +40,8 @@ namespace
|
||||
void onCreateWindow(HWND hwnd);
|
||||
void onDestroyWindow(HWND hwnd);
|
||||
void onGetMinMaxInfo(MINMAXINFO& mmi);
|
||||
void onInitMenuPopup(HMENU menu);
|
||||
void onUninitMenuPopup(HMENU menu);
|
||||
void onWindowPosChanged(HWND hwnd, const WINDOWPOS& wp);
|
||||
void onWindowPosChanging(HWND hwnd, WINDOWPOS& wp);
|
||||
void setWindowProc(HWND hwnd, WNDPROC wndProcA, WNDPROC wndProcW);
|
||||
@ -71,6 +75,10 @@ namespace
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_UNINITMENUPOPUP:
|
||||
onUninitMenuPopup(reinterpret_cast<HMENU>(wParam));
|
||||
break;
|
||||
|
||||
case WM_WINDOWPOSCHANGED:
|
||||
onWindowPosChanged(hwnd, *reinterpret_cast<WINDOWPOS*>(lParam));
|
||||
break;
|
||||
@ -88,6 +96,10 @@ namespace
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_INITMENUPOPUP:
|
||||
onInitMenuPopup(reinterpret_cast<HMENU>(wParam));
|
||||
break;
|
||||
|
||||
case WM_NCDESTROY:
|
||||
onDestroyWindow(hwnd);
|
||||
break;
|
||||
@ -234,6 +246,40 @@ namespace
|
||||
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)
|
||||
{
|
||||
for (auto notifyFunc : g_windowPosChangeNotifyFuncs)
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <D3dDdi/KernelModeThunks.h>
|
||||
#include <D3dDdi/ScopedCriticalSection.h>
|
||||
#include <DDraw/RealPrimarySurface.h>
|
||||
#include <Gdi/Gdi.h>
|
||||
#include <Gdi/PresentationWindow.h>
|
||||
#include <Gdi/VirtualScreen.h>
|
||||
#include <Gdi/Window.h>
|
||||
@ -31,6 +32,7 @@ namespace
|
||||
Gdi::Region windowRegion;
|
||||
Gdi::Region visibleRegion;
|
||||
Gdi::Region invalidatedRegion;
|
||||
bool isMenu;
|
||||
bool isLayered;
|
||||
bool isVisibleRegionChanged;
|
||||
|
||||
@ -40,6 +42,7 @@ namespace
|
||||
, windowRect{}
|
||||
, clientRect{}
|
||||
, windowRegion(nullptr)
|
||||
, isMenu(Gdi::MENU_ATOM == GetClassLong(hwnd, GCW_ATOM))
|
||||
, isLayered(true)
|
||||
, isVisibleRegionChanged(false)
|
||||
{
|
||||
@ -196,7 +199,7 @@ namespace
|
||||
g_windowZOrder.push_back(&it->second);
|
||||
|
||||
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);
|
||||
bool setPresentationWindowRgn = false;
|
||||
|
||||
@ -243,7 +246,10 @@ namespace
|
||||
visibleRegion = wi.rcWindow;
|
||||
}
|
||||
visibleRegion &= context.virtualScreenRegion;
|
||||
visibleRegion -= context.obscuredRegion;
|
||||
if (!it->second.isMenu)
|
||||
{
|
||||
visibleRegion -= context.obscuredRegion;
|
||||
}
|
||||
|
||||
if (!isLayered && !(exStyle & WS_EX_TRANSPARENT))
|
||||
{
|
||||
@ -327,7 +333,7 @@ namespace Gdi
|
||||
{
|
||||
D3dDdi::ScopedCriticalSection lock;
|
||||
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;
|
||||
if (isLayered != it->second.isLayered)
|
||||
@ -356,16 +362,15 @@ namespace Gdi
|
||||
it->second.isVisibleRegionChanged = false;
|
||||
const LONG origWndProc = CALL_ORIG_FUNC(GetWindowLongA)(hwnd, GWL_WNDPROC);
|
||||
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 |= REGION_OVERRIDE_MARKER_RECT;
|
||||
SetWindowRgn(hwnd, rgn, FALSE);
|
||||
}
|
||||
if (SetWindowRgn(hwnd, rgn, FALSE))
|
||||
{
|
||||
rgn.release();
|
||||
}
|
||||
CALL_ORIG_FUNC(SetWindowLongA)(hwnd, GWL_WNDPROC, origWndProc);
|
||||
}
|
||||
@ -485,9 +490,9 @@ namespace Gdi
|
||||
SelectClipRgn(dstDc, rgn);
|
||||
|
||||
COLORREF colorKey = 0;
|
||||
BYTE alpha = 0;
|
||||
DWORD flags = 0;
|
||||
if (CALL_ORIG_FUNC(GetLayeredWindowAttributes)(window.hwnd, &colorKey, &alpha, &flags))
|
||||
BYTE alpha = 255;
|
||||
DWORD flags = ULW_ALPHA;
|
||||
if (window.isMenu || CALL_ORIG_FUNC(GetLayeredWindowAttributes)(window.hwnd, &colorKey, &alpha, &flags))
|
||||
{
|
||||
if (flags & LWA_COLORKEY)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user