Skip to content
This repository has been archived by the owner on Dec 19, 2023. It is now read-only.

Commit

Permalink
win: some minor improvements
Browse files Browse the repository at this point in the history
Signed-off-by: Yuhang Zhao <[email protected]>
  • Loading branch information
wangwenx190 committed Nov 11, 2022
1 parent 766c1e1 commit 524f65c
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 48 deletions.
1 change: 1 addition & 0 deletions include/FramelessHelper/Core/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ FRAMELESSHELPER_CORE_API void enableNonClientAreaDpiScalingForWindow(const WId w
FRAMELESSHELPER_CORE_API void fixupChildWindowsDpiMessage(const WId windowId);
FRAMELESSHELPER_CORE_API void fixupDialogsDpiScaling();
FRAMELESSHELPER_CORE_API void setDarkModeAllowedForApp(const bool allow = true);
FRAMELESSHELPER_CORE_API void bringWindowToFront(const WId windowId);
#endif // Q_OS_WINDOWS

#ifdef Q_OS_LINUX
Expand Down
2 changes: 1 addition & 1 deletion src/core/framelesshelper_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -805,7 +805,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
// we have to use another way to judge this if we are running
// on Windows 7 or Windows 8.
if (WindowsVersionHelper::isWin8Point1OrGreater()) {
MONITORINFO monitorInfo;
MONITORINFOEXW monitorInfo;
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
monitorInfo.cbSize = sizeof(monitorInfo);
const HMONITOR monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
Expand Down
8 changes: 4 additions & 4 deletions src/core/framelesshelpercore_global.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,16 +260,16 @@ void uninitialize()

VersionInfo version()
{
static const VersionInfo result = []() -> VersionInfo {
const char *_compiler = []() -> const char * { return COMPILER_STRING; }();
const bool _debug = []() -> bool {
static const auto result = []() -> VersionInfo {
const auto _compiler = []() -> const char * { return COMPILER_STRING; }();
const auto _debug = []() -> bool {
#ifdef _DEBUG
return true;
#else
return false;
#endif
}();
const bool _static = []() -> bool {
const auto _static = []() -> bool {
#ifdef FRAMELESSHELPER_CORE_STATIC
return true;
#else
Expand Down
6 changes: 3 additions & 3 deletions src/core/framelessmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ FRAMELESSHELPER_STRING_CONSTANT2(IconFontFamilyName_common, "micon_nb")

[[nodiscard]] static inline QString iconFontFamilyName()
{
static const QString result = []() -> QString {
static const auto result = []() -> QString {
#ifdef Q_OS_WINDOWS
if (WindowsVersionHelper::isWin11OrGreater()) {
return kIconFontFamilyName_win11;
Expand Down Expand Up @@ -158,7 +158,7 @@ void FramelessManagerPrivate::initializeIconFont()

QFont FramelessManagerPrivate::getIconFont()
{
static const QFont font = []() -> QFont {
static const auto font = []() -> QFont {
QFont f = {};
f.setFamily(iconFontFamilyName());
f.setPointSize(kIconFontPointSize);
Expand Down Expand Up @@ -338,7 +338,7 @@ void FramelessManagerPrivate::notifyWallpaperHasChangedOrNot()

bool FramelessManagerPrivate::usePureQtImplementation()
{
static const bool result = []() -> bool {
static const auto result = []() -> bool {
#ifdef Q_OS_WINDOWS
return FramelessConfig::instance()->isSet(Option::UseCrossPlatformQtImplementation);
#else
Expand Down
2 changes: 1 addition & 1 deletion src/core/utils_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ WallpaperAspectStyle Utils::getWallpaperAspectStyle()

bool Utils::isBlurBehindWindowSupported()
{
static const bool result = []() -> bool {
static const auto result = []() -> bool {
if (FramelessConfig::instance()->isSet(Option::ForceNonNativeBackgroundBlur)) {
return false;
}
Expand Down
4 changes: 2 additions & 2 deletions src/core/utils_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -584,7 +584,7 @@ static void sendEvent(id obj, SEL sel, NSEvent *event)
const auto proxy = new NSWindowProxy(qwindow, nswindow);
g_macUtilsData()->hash.insert(windowId, proxy);
}
static const int hook = []() -> int {
static const auto hook = []() -> int {
FramelessHelper::Core::registerUninitializeHook([](){
const QMutexLocker locker(&g_macUtilsData()->mutex);
if (g_macUtilsData()->hash.isEmpty()) {
Expand Down Expand Up @@ -745,7 +745,7 @@ static void sendEvent(id obj, SEL sel, NSEvent *event)

bool Utils::isBlurBehindWindowSupported()
{
static const bool result = []() -> bool {
static const auto result = []() -> bool {
if (FramelessConfig::instance()->isSet(Option::ForceNonNativeBackgroundBlur)) {
return false;
}
Expand Down
178 changes: 158 additions & 20 deletions src/core/utils_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,11 @@ FRAMELESSHELPER_STRING_CONSTANT(AdjustWindowRectExForDpi)
FRAMELESSHELPER_STRING_CONSTANT(GetDpiMetrics)
FRAMELESSHELPER_STRING_CONSTANT(EnablePerMonitorDialogScaling)
FRAMELESSHELPER_STRING_CONSTANT(EnableChildWindowDpiMessage)
FRAMELESSHELPER_STRING_CONSTANT(GetForegroundWindow)
FRAMELESSHELPER_STRING_CONSTANT(SendMessageTimeoutW)
FRAMELESSHELPER_STRING_CONSTANT(AttachThreadInput)
FRAMELESSHELPER_STRING_CONSTANT(BringWindowToTop)
FRAMELESSHELPER_STRING_CONSTANT(SetActiveWindow)

struct Win32UtilsHelperData
{
Expand Down Expand Up @@ -871,7 +876,7 @@ struct SYSTEM_METRIC

[[nodiscard]] static inline bool doCompareWindowsVersion(const VersionNumber &targetOsVer)
{
static const std::optional<VersionNumber> currentOsVer = []() -> std::optional<VersionNumber> {
static const auto currentOsVer = []() -> std::optional<VersionNumber> {
if (API_NT_AVAILABLE(RtlGetVersion)) {
using RtlGetVersionPtr = _NTSTATUS(WINAPI *)(PRTL_OSVERSIONINFOW);
const auto pRtlGetVersion =
Expand Down Expand Up @@ -950,6 +955,69 @@ struct SYSTEM_METRIC
return __getSystemErrorMessage(function, dwError);
}

[[nodiscard]] static inline bool operator==(const RECT &lhs, const RECT &rhs) noexcept
{
return ((lhs.left == rhs.left) && (lhs.top == rhs.top)
&& (lhs.right == rhs.right) && (lhs.bottom == rhs.bottom));
}

[[nodiscard]] static inline std::optional<MONITORINFOEXW> getMonitorForWindow(const HWND hwnd)
{
Q_ASSERT(hwnd);
if (!hwnd) {
return std::nullopt;
}
const HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
if (!monitor) {
WARNING << Utils::getSystemErrorMessage(kMonitorFromWindow);
return std::nullopt;
}
MONITORINFOEXW monitorInfo;
SecureZeroMemory(&monitorInfo, sizeof(monitorInfo));
monitorInfo.cbSize = sizeof(monitorInfo);
if (GetMonitorInfoW(monitor, &monitorInfo) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kGetMonitorInfoW);
return std::nullopt;
}
return monitorInfo;
};

static inline void moveWindowToMonitor(const HWND hwnd, const MONITORINFOEXW &activeMonitor)
{
Q_ASSERT(hwnd);
if (!hwnd) {
return;
}
const std::optional<MONITORINFOEXW> currentMonitor = getMonitorForWindow(hwnd);
if (!currentMonitor.has_value()) {
WARNING << "Failed to retrieve the window's monitor.";
return;
}
const RECT currentMonitorRect = currentMonitor.value().rcMonitor;
const RECT activeMonitorRect = activeMonitor.rcMonitor;
// We are in the same monitor, nothing to adjust here.
if (currentMonitorRect == activeMonitorRect) {
return;
}
RECT currentWindowRect = {};
if (GetWindowRect(hwnd, &currentWindowRect) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kGetWindowRect);
return;
}
const int currentWindowWidth = qAbs(currentWindowRect.right - currentWindowRect.left);
const int currentWindowHeight = qAbs(currentWindowRect.bottom - currentWindowRect.top);
const int currentWindowOffsetX = (currentWindowRect.left - currentMonitorRect.left);
const int currentWindowOffsetY = (currentWindowRect.top - currentMonitorRect.top);
const int newWindowX = activeMonitorRect.left + currentWindowOffsetX;
const int newWindowY = activeMonitorRect.top + currentWindowOffsetY;
static constexpr const UINT flags =
(SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
if (SetWindowPos(hwnd, nullptr, newWindowX, newWindowY,
currentWindowWidth, currentWindowHeight, flags) == FALSE) {
WARNING << Utils::getSystemErrorMessage(kSetWindowPos);
}
}

[[nodiscard]] static inline int getSystemMetrics2(const WId windowId, const int index,
const bool horizontal, const bool scaled)
{
Expand Down Expand Up @@ -1365,29 +1433,18 @@ bool Utils::isFullScreen(const WId windowId)
return false;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
RECT wndRect = {};
if (GetWindowRect(hwnd, &wndRect) == FALSE) {
RECT windowRect = {};
if (GetWindowRect(hwnd, &windowRect) == FALSE) {
WARNING << getSystemErrorMessage(kGetWindowRect);
return false;
}
// According to Microsoft Docs, we should compare to the primary screen's geometry
// (if we can't determine the correct screen of our window).
const HMONITOR mon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
if (!mon) {
WARNING << getSystemErrorMessage(kMonitorFromWindow);
return false;
}
MONITORINFO mi;
SecureZeroMemory(&mi, sizeof(mi));
mi.cbSize = sizeof(mi);
if (GetMonitorInfoW(mon, &mi) == FALSE) {
WARNING << getSystemErrorMessage(kGetMonitorInfoW);
const std::optional<MONITORINFOEXW> mi = getMonitorForWindow(hwnd);
if (!mi.has_value()) {
WARNING << "Failed to retrieve the window's monitor.";
return false;
}
// Compare to the full area of the screen, not the work area.
const RECT scrRect = mi.rcMonitor;
return ((wndRect.left == scrRect.left) && (wndRect.top == scrRect.top)
&& (wndRect.right == scrRect.right) && (wndRect.bottom == scrRect.bottom));
return (windowRect == mi.value().rcMonitor);
}

bool Utils::isWindowNoState(const WId windowId)
Expand Down Expand Up @@ -1850,7 +1907,7 @@ void Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi

bool Utils::isWindowFrameBorderVisible()
{
static const bool result = []() -> bool {
static const auto result = []() -> bool {
const FramelessConfig * const config = FramelessConfig::instance();
if (config->isSet(Option::UseCrossPlatformQtImplementation)) {
return false;
Expand Down Expand Up @@ -2444,7 +2501,7 @@ WallpaperAspectStyle Utils::getWallpaperAspectStyle()

bool Utils::isBlurBehindWindowSupported()
{
static const bool result = []() -> bool {
static const auto result = []() -> bool {
if (FramelessConfig::instance()->isSet(Option::ForceNonNativeBackgroundBlur)) {
return false;
}
Expand Down Expand Up @@ -2787,4 +2844,85 @@ void Utils::setDarkModeAllowedForApp(const bool allow)
}
}

void Utils::bringWindowToFront(const WId windowId)
{
Q_ASSERT(windowId);
if (!windowId) {
return;
}
const auto hwnd = reinterpret_cast<HWND>(windowId);
const HWND oldForegroundWindow = GetForegroundWindow();
if (!oldForegroundWindow) {
WARNING << getSystemErrorMessage(kGetForegroundWindow);
return;
}
const std::optional<MONITORINFOEXW> activeMonitor = getMonitorForWindow(oldForegroundWindow);
if (!activeMonitor.has_value()) {
WARNING << "Failed to retrieve the window's monitor.";
return;
}
// We need to show the window first, otherwise we won't be able to bring it to front.
if (IsWindowVisible(hwnd) == FALSE) {
ShowWindow(hwnd, SW_SHOW);
}
if (IsMinimized(hwnd)) {
// Restore the window if it is minimized.
ShowWindow(hwnd, SW_RESTORE);
// Once we've been restored, throw us on the active monitor.
moveWindowToMonitor(hwnd, activeMonitor.value());
// When the window is restored, it will always become the foreground window.
// So return early here, we don't need the following code to bring it to front.
return;
}
// OK, our window is not minimized, so now we will try to bring it to front manually.
// First try to send a message to the current foreground window to check whether
// it is currently hanging or not.
static constexpr const UINT kTimeout = 1000;
if (SendMessageTimeoutW(oldForegroundWindow, WM_NULL, 0, 0,
SMTO_BLOCK | SMTO_ABORTIFHUNG | SMTO_NOTIMEOUTIFNOTHUNG, kTimeout, nullptr) == 0) {
if (GetLastError() == ERROR_TIMEOUT) {
WARNING << "The foreground window hangs, can't activate current window.";
} else {
WARNING << getSystemErrorMessage(kSendMessageTimeoutW);
}
return;
}
const DWORD windowThreadProcessId = GetWindowThreadProcessId(oldForegroundWindow, nullptr);
const DWORD currentThreadId = GetCurrentThreadId();
// We won't be able to change a window's Z order if it's not our own window,
// so we use this small technique to pretend the foreground window is ours.
if (AttachThreadInput(windowThreadProcessId, currentThreadId, TRUE) == FALSE) {
WARNING << getSystemErrorMessage(kAttachThreadInput);
return;
}
// And also don't forget to disconnect from it.
// Ideally we would want to use qScopeGuard to do this, but sadly it was introduced
// in Qt 5.12 and we still want to support some old Qt versions.
const struct __Cleanup {
const DWORD idAttach = 0;
const DWORD idAttachTo = 0;
__Cleanup(const DWORD attach, const DWORD attachTo)
: idAttach(attach), idAttachTo(attachTo) {}
~__Cleanup() {
if (AttachThreadInput(idAttach, idAttachTo, FALSE) == FALSE) {
WARNING << getSystemErrorMessage(kAttachThreadInput);
}
}
} __cleanup(windowThreadProcessId, currentThreadId);
Q_UNUSED(__cleanup);
// Make our window be the first one in the Z order.
if (BringWindowToTop(hwnd) == FALSE) {
WARNING << getSystemErrorMessage(kBringWindowToTop);
return;
}
// Activate the window too. This will force us to the virtual desktop this
// window is on, if it's on another virtual desktop.
if (SetActiveWindow(hwnd) == nullptr) {
WARNING << getSystemErrorMessage(kSetActiveWindow);
return;
}
// Throw us on the active monitor.
moveWindowToMonitor(hwnd, activeMonitor.value());
}

FRAMELESSHELPER_END_NAMESPACE
26 changes: 17 additions & 9 deletions src/quick/framelessquickhelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -391,18 +391,26 @@ void FramelessQuickHelperPrivate::bringWindowToFront()
if (!window) {
return;
}
if (window->visibility() == QQuickWindow::Hidden) {
window->show();
}
if (window->visibility() == QQuickWindow::Minimized) {
const auto bringWindowToFront_impl = [window]() -> void {
if (window->visibility() == QQuickWindow::Hidden) {
window->show();
}
if (window->visibility() == QQuickWindow::Minimized) {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
window->setWindowStates(window->windowStates() & ~Qt::WindowMinimized);
window->setWindowStates(window->windowStates() & ~Qt::WindowMinimized);
#else
window->showNormal();
window->showNormal();
#endif
}
window->raise();
window->requestActivate();
};
#ifdef Q_OS_WINDOWS
Q_UNUSED(bringWindowToFront_impl);
Utils::bringWindowToFront(window->winId());
#else
bringWindowToFront_impl();
#endif
}
window->raise();
window->requestActivate();
}

bool FramelessQuickHelperPrivate::isWindowFixedSize() const
Expand Down
24 changes: 16 additions & 8 deletions src/widgets/framelesswidgetshelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -780,14 +780,22 @@ void FramelessWidgetsHelperPrivate::bringWindowToFront()
if (!m_window) {
return;
}
if (m_window->isHidden()) {
m_window->show();
}
if (m_window->isMinimized()) {
m_window->setWindowState(m_window->windowState() & ~Qt::WindowMinimized);
}
m_window->raise();
m_window->activateWindow();
const auto bringWindowToFront_impl = [this]() -> void {
if (m_window->isHidden()) {
m_window->show();
}
if (m_window->isMinimized()) {
m_window->setWindowState(m_window->windowState() & ~Qt::WindowMinimized);
}
m_window->raise();
m_window->activateWindow();
};
#ifdef Q_OS_WINDOWS
Q_UNUSED(bringWindowToFront_impl);
Utils::bringWindowToFront(m_window->winId());
#else
bringWindowToFront_impl();
#endif
}

void FramelessWidgetsHelperPrivate::showSystemMenu(const QPoint &pos)
Expand Down

0 comments on commit 524f65c

Please sign in to comment.