From ab35223c2f2cc4a1a0174f1aeeb65b13196dd8fb Mon Sep 17 00:00:00 2001 From: narzoul Date: Sun, 7 Feb 2016 18:30:49 +0100 Subject: [PATCH] Added manual rendering of title bars --- DDrawCompat/CompatGdiTitleBar.cpp | 139 ++++++++++++++++++++++++ DDrawCompat/CompatGdiTitleBar.h | 34 ++++++ DDrawCompat/CompatGdiWinProc.cpp | 38 ++++++- DDrawCompat/DDrawCompat.vcxproj | 2 + DDrawCompat/DDrawCompat.vcxproj.filters | 6 + 5 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 DDrawCompat/CompatGdiTitleBar.cpp create mode 100644 DDrawCompat/CompatGdiTitleBar.h diff --git a/DDrawCompat/CompatGdiTitleBar.cpp b/DDrawCompat/CompatGdiTitleBar.cpp new file mode 100644 index 0000000..b674e88 --- /dev/null +++ b/DDrawCompat/CompatGdiTitleBar.cpp @@ -0,0 +1,139 @@ +#include "CompatGdi.h" +#include "CompatGdiTitleBar.h" + +namespace +{ + enum TitleBarInfoIndex + { + TBII_TITLEBAR = 0, + TBII_MINIMIZE_BUTTON = 2, + TBII_MAXIMIZE_BUTTON = 3, + TBII_HELP_BUTTON = 4, + TBII_CLOSE_BUTTON = 5 + }; +} + +namespace CompatGdi +{ + TitleBar::TitleBar(HWND hwnd, HDC compatDc) : + m_hwnd(hwnd), m_compatDc(compatDc), m_buttonWidth(0), m_buttonHeight(0), m_tbi(), + m_hasTitleBar(false), m_isToolWindow(false) + { + m_hasTitleBar = 0 != (GetWindowLongPtr(hwnd, GWL_STYLE) & WS_CAPTION); + if (!m_hasTitleBar) + { + return; + } + + m_tbi.cbSize = sizeof(m_tbi); + SendMessage(hwnd, WM_GETTITLEBARINFOEX, 0, reinterpret_cast(&m_tbi)); + m_hasTitleBar = !IsRectEmpty(&m_tbi.rcTitleBar); + if (!m_hasTitleBar) + { + return; + } + + POINT origin = {}; + ClientToScreen(hwnd, &origin); + m_tbi.rcTitleBar.left = origin.x; + + RECT windowRect = {}; + GetWindowRect(hwnd, &windowRect); + OffsetRect(&m_tbi.rcTitleBar, -windowRect.left, -windowRect.top); + + m_isToolWindow = 0 != (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW); + m_buttonWidth = GetSystemMetrics(m_isToolWindow ? SM_CXSMSIZE : SM_CXSIZE) - 2; + m_buttonHeight = GetSystemMetrics(m_isToolWindow ? SM_CYSMSIZE : SM_CYSIZE) - 4; + + for (std::size_t i = TBII_MINIMIZE_BUTTON; i <= TBII_CLOSE_BUTTON; ++i) + { + if (isVisible(i)) + { + OffsetRect(&m_tbi.rgrect[i], -windowRect.left, -windowRect.top); + adjustButtonSize(m_tbi.rgrect[i]); + } + } + } + + void TitleBar::adjustButtonSize(RECT& rect) const + { + rect.left += (rect.right - rect.left - m_buttonWidth) / 2; + rect.top += (rect.bottom - rect.top - m_buttonHeight) / 2; + rect.right = rect.left + m_buttonWidth; + rect.bottom = rect.top + m_buttonHeight; + } + + void TitleBar::drawAll() const + { + drawCaption(); + drawButtons(); + } + + void TitleBar::drawButtons() const + { + if (!m_hasTitleBar) + { + return; + } + + drawButton(TBII_MINIMIZE_BUTTON, DFCS_CAPTIONMIN); + drawButton(TBII_MAXIMIZE_BUTTON, IsZoomed(m_hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX); + drawButton(TBII_HELP_BUTTON, DFCS_CAPTIONHELP); + drawButton(TBII_CLOSE_BUTTON, DFCS_CAPTIONCLOSE); + } + + void TitleBar::drawCaption() const + { + if (!m_hasTitleBar) + { + return; + } + + UINT flags = DC_ICON | DC_TEXT; + if (GetActiveWindow() == m_hwnd) + { + flags |= DC_ACTIVE; + } + if (m_isToolWindow) + { + flags |= DC_SMALLCAP; + } + + CALL_ORIG_GDI(DrawCaption)(m_hwnd, m_compatDc, &m_tbi.rcTitleBar, flags); + } + + void TitleBar::drawButton(std::size_t tbiIndex, UINT dfcState) const + { + if (!isVisible(tbiIndex)) + { + return; + } + + DWORD stateFlags = 0; + if (m_tbi.rgstate[tbiIndex] & STATE_SYSTEM_UNAVAILABLE) + { + stateFlags |= DFCS_INACTIVE; + } + else if (m_tbi.rgstate[tbiIndex] & STATE_SYSTEM_PRESSED) + { + stateFlags |= DFCS_PUSHED; + } + + RECT rect = m_tbi.rgrect[tbiIndex]; + CALL_ORIG_GDI(DrawFrameControl)(m_compatDc, &rect, DFC_CAPTION, dfcState | stateFlags); + } + + void TitleBar::excludeFromClipRegion() const + { + if (m_hasTitleBar) + { + const RECT& r = m_tbi.rcTitleBar; + ExcludeClipRect(m_compatDc, r.left, r.top, r.right, r.bottom); + } + } + + bool TitleBar::isVisible(std::size_t tbiIndex) const + { + return !(m_tbi.rgstate[tbiIndex] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_OFFSCREEN)); + } +} diff --git a/DDrawCompat/CompatGdiTitleBar.h b/DDrawCompat/CompatGdiTitleBar.h new file mode 100644 index 0000000..a2581f2 --- /dev/null +++ b/DDrawCompat/CompatGdiTitleBar.h @@ -0,0 +1,34 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN + +#include + +#include + +namespace CompatGdi +{ + class TitleBar + { + public: + TitleBar(HWND hwnd, HDC compatDc); + + void drawAll() const; + void drawButtons() const; + void drawCaption() const; + void excludeFromClipRegion() const; + + private: + void adjustButtonSize(RECT& rect) const; + void drawButton(std::size_t tbiIndex, UINT dfcState) const; + bool isVisible(std::size_t tbiIndex) const; + + HWND m_hwnd; + HDC m_compatDc; + int m_buttonWidth; + int m_buttonHeight; + TITLEBARINFOEX m_tbi; + bool m_hasTitleBar; + bool m_isToolWindow; + }; +} diff --git a/DDrawCompat/CompatGdiWinProc.cpp b/DDrawCompat/CompatGdiWinProc.cpp index 3edfec8..7fec504 100644 --- a/DDrawCompat/CompatGdiWinProc.cpp +++ b/DDrawCompat/CompatGdiWinProc.cpp @@ -5,6 +5,7 @@ #include "CompatGdi.h" #include "CompatGdiDc.h" +#include "CompatGdiTitleBar.h" #include "CompatGdiWinProc.h" #include "DDrawLog.h" @@ -137,7 +138,7 @@ namespace void ncPaint(HWND hwnd) { - if (!CompatGdi::beginGdiRendering()) + if (!hwnd || !CompatGdi::beginGdiRendering()) { return; } @@ -154,6 +155,10 @@ namespace POINT clientOrigin = {}; ClientToScreen(hwnd, &clientOrigin); + CompatGdi::TitleBar titleBar(hwnd, compatDc); + titleBar.drawAll(); + titleBar.excludeFromClipRegion(); + OffsetRect(&clientRect, clientOrigin.x - windowRect.left, clientOrigin.y - windowRect.top); ExcludeClipRect(compatDc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom); CALL_ORIG_GDI(BitBlt)(compatDc, 0, 0, @@ -168,6 +173,35 @@ namespace CompatGdi::endGdiRendering(); } + void CALLBACK objectStateChangeEvent( + HWINEVENTHOOK /*hWinEventHook*/, + DWORD /*event*/, + HWND hwnd, + LONG idObject, + LONG /*idChild*/, + DWORD /*dwEventThread*/, + DWORD /*dwmsEventTime*/) + { + if (OBJID_TITLEBAR == idObject) + { + if (!hwnd || !CompatGdi::beginGdiRendering()) + { + return; + } + + HDC windowDc = GetWindowDC(hwnd); + HDC compatDc = CompatGdiDc::getDc(windowDc); + if (compatDc) + { + CompatGdi::TitleBar(hwnd, compatDc).drawAll(); + CompatGdiDc::releaseDc(windowDc); + } + + ReleaseDC(hwnd, windowDc); + CompatGdi::endGdiRendering(); + } + } + void updateScrolledWindow(HWND hwnd) { RedrawWindow(hwnd, nullptr, nullptr, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE); @@ -181,5 +215,7 @@ namespace CompatGdiWinProc const DWORD threadId = GetCurrentThreadId(); SetWindowsHookEx(WH_CALLWNDPROCRET, callWndRetProc, nullptr, threadId); SetWindowsHookEx(WH_MOUSE, &mouseProc, nullptr, threadId); + SetWinEventHook(EVENT_OBJECT_STATECHANGE, EVENT_OBJECT_STATECHANGE, + nullptr, &objectStateChangeEvent, 0, threadId, WINEVENT_OUTOFCONTEXT); } } diff --git a/DDrawCompat/DDrawCompat.vcxproj b/DDrawCompat/DDrawCompat.vcxproj index fa6ae48..3d8569f 100644 --- a/DDrawCompat/DDrawCompat.vcxproj +++ b/DDrawCompat/DDrawCompat.vcxproj @@ -150,6 +150,7 @@ + @@ -175,6 +176,7 @@ + diff --git a/DDrawCompat/DDrawCompat.vcxproj.filters b/DDrawCompat/DDrawCompat.vcxproj.filters index ed4729d..21611fa 100644 --- a/DDrawCompat/DDrawCompat.vcxproj.filters +++ b/DDrawCompat/DDrawCompat.vcxproj.filters @@ -81,6 +81,9 @@ Header Files + + Header Files + @@ -134,6 +137,9 @@ Source Files + + Source Files +