diff --git a/DDrawCompat/DDraw/RealPrimarySurface.cpp b/DDrawCompat/DDraw/RealPrimarySurface.cpp index 7f73420..80f6355 100644 --- a/DDrawCompat/DDraw/RealPrimarySurface.cpp +++ b/DDrawCompat/DDraw/RealPrimarySurface.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include namespace diff --git a/DDrawCompat/Gdi/Gdi.cpp b/DDrawCompat/Gdi/Gdi.cpp index 0f5d8be..80f363e 100644 --- a/DDrawCompat/Gdi/Gdi.cpp +++ b/DDrawCompat/Gdi/Gdi.cpp @@ -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) diff --git a/DDrawCompat/Gdi/User32WndProcs.cpp b/DDrawCompat/Gdi/User32WndProcs.cpp index 38aae27..b771a5b 100644 --- a/DDrawCompat/Gdi/User32WndProcs.cpp +++ b/DDrawCompat/Gdi/User32WndProcs.cpp @@ -1,7 +1,9 @@ #include #include +#include #include #include +#include #include #include #include @@ -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(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(dc), 0); - LRESULT result = CallWindowProc(origWndProc, hwnd, msg, reinterpret_cast(dc), lParam); - CALL_ORIG_FUNC(BitBlt)(reinterpret_cast(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(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); } } diff --git a/DDrawCompat/Gdi/WinProc.cpp b/DDrawCompat/Gdi/WinProc.cpp index d961af5..86d63a6 100644 --- a/DDrawCompat/Gdi/WinProc.cpp +++ b/DDrawCompat/Gdi/WinProc.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +28,7 @@ namespace WNDPROC wndProcW; }; + std::map g_menuMaxHeight; std::set 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(wParam)); + break; + case WM_WINDOWPOSCHANGED: onWindowPosChanged(hwnd, *reinterpret_cast(lParam)); break; @@ -88,6 +96,10 @@ namespace } break; + case WM_INITMENUPOPUP: + onInitMenuPopup(reinterpret_cast(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) diff --git a/DDrawCompat/Gdi/Window.cpp b/DDrawCompat/Gdi/Window.cpp index 0f36f93..6e14e49 100644 --- a/DDrawCompat/Gdi/Window.cpp +++ b/DDrawCompat/Gdi/Window.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -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(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) {