minor general improvement
Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
parent
b6e86f90e6
commit
b5eebada2c
|
@ -72,3 +72,5 @@ Thumbs.db
|
|||
*.res
|
||||
.DS_Store
|
||||
.vscode/
|
||||
.vs/
|
||||
.cmake.conf
|
||||
|
|
|
@ -111,9 +111,16 @@ FRAMELESSHELPER_CORE_API void tryToBeCompatibleWithQtFramelessWindowHint(
|
|||
FRAMELESSHELPER_CORE_API void setAeroSnappingEnabled(const WId windowId, const bool enable);
|
||||
FRAMELESSHELPER_CORE_API void tryToEnableHighestDpiAwarenessLevel();
|
||||
FRAMELESSHELPER_CORE_API void updateGlobalWin32ControlsTheme(const WId windowId, const bool dark);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_windows();
|
||||
#endif // Q_OS_WINDOWS
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_linux();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getWmThemeColor();
|
||||
#endif // Q_OS_LINUX
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool shouldAppsUseDarkMode_macos();
|
||||
FRAMELESSHELPER_CORE_API void setSystemTitleBarVisible(const WId windowId, const bool visible);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QColor getControlsAccentColor();
|
||||
#endif // Q_OS_MACOS
|
||||
|
|
|
@ -102,7 +102,7 @@ private Q_SLOTS:
|
|||
void updateSystemMaximizeButton();
|
||||
|
||||
private:
|
||||
QWidget *q = nullptr;
|
||||
QPointer<QWidget> q = nullptr;
|
||||
bool m_initialized = false;
|
||||
QScopedPointer<QWidget> m_systemTitleBarWidget;
|
||||
QScopedPointer<QLabel> m_systemWindowTitleLabel;
|
||||
|
|
|
@ -55,7 +55,11 @@ if(WIN32)
|
|||
elseif(APPLE)
|
||||
list(APPEND SOURCES utils_mac.mm)
|
||||
elseif(UNIX)
|
||||
list(APPEND SOURCES utils_linux.cpp)
|
||||
list(APPEND SOURCES
|
||||
qtx11extras_p.h
|
||||
qtx11extras.cpp
|
||||
utils_linux.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
|
||||
|
|
|
@ -50,10 +50,15 @@ Q_GLOBAL_STATIC(FramelessWindowsManagerHelper, g_helper)
|
|||
|
||||
Q_GLOBAL_STATIC(FramelessWindowsManager, g_manager)
|
||||
|
||||
[[maybe_unused]] static constexpr const char QT_QPA_ENV_VAR[] = "QT_QPA_PLATFORM";
|
||||
[[maybe_unused]] static constexpr const char MAC_LAYER_ENV_VAR[] = "QT_MAC_WANTS_LAYER";
|
||||
#ifdef Q_OS_LINUX
|
||||
static constexpr const char QT_QPA_ENV_VAR[] = "QT_QPA_PLATFORM";
|
||||
FRAMELESSHELPER_BYTEARRAY_CONSTANT(xcb)
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
static constexpr const char MAC_LAYER_ENV_VAR[] = "QT_MAC_WANTS_LAYER";
|
||||
FRAMELESSHELPER_BYTEARRAY_CONSTANT2(ValueOne, "1")
|
||||
#endif
|
||||
|
||||
FramelessWindowsManagerPrivate::FramelessWindowsManagerPrivate(FramelessWindowsManager *q) : QObject(q)
|
||||
{
|
||||
|
@ -167,7 +172,7 @@ void FramelessWindowsManagerPrivate::notifySystemThemeHasChangedOrNot()
|
|||
const QColor currentAccentColor = Utils::getDwmColorizationColor();
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
const QColor currentAccentColor = {}; // ### TODO
|
||||
const QColor currentAccentColor = Utils::getWmThemeColor();
|
||||
#endif
|
||||
#ifdef Q_OS_MACOS
|
||||
const QColor currentAccentColor = Utils::getControlsAccentColor();
|
||||
|
@ -247,17 +252,17 @@ void FramelessHelper::Core::initialize(const Options options)
|
|||
}
|
||||
inited = true;
|
||||
#ifdef Q_OS_LINUX
|
||||
// ### FIXME: Crash on Wayland, so we force xcb here.
|
||||
// Remove this ugly hack when the crash is fixed!
|
||||
// Qt's Wayland experience is not good, so we force the X11 backend here.
|
||||
// TODO: Remove this hack once Qt's Wayland implementation is good enough.
|
||||
// We are setting the preferred QPA backend, so we have to set it early
|
||||
// enough, that is, before the construction of any Q(Gui)Application
|
||||
// instances.
|
||||
// instances. QCoreApplication won't instantiate the platform plugin.
|
||||
qputenv(QT_QPA_ENV_VAR, kxcb);
|
||||
#endif
|
||||
#ifdef Q_OS_MACOS
|
||||
if (qEnvironmentVariableIntValue(MAC_LAYER_ENV_VAR) != 1) {
|
||||
qputenv(MAC_LAYER_ENV_VAR, kValueOne);
|
||||
}
|
||||
// This has become the default setting since some unknown Qt version,
|
||||
// check whether we can remove this hack safely or not.
|
||||
qputenv(MAC_LAYER_ENV_VAR, kValueOne);
|
||||
#endif
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (!(options & Option::DontTouchProcessDpiAwarenessLevel)) {
|
||||
|
|
|
@ -0,0 +1,559 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2022 The Qt Company Ltd.
|
||||
** Copyright (C) 2022 Richard Moore <rich@kde.org>
|
||||
** Copyright (C) 2022 David Faure <david.faure@kdab.com>
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qtx11extras_p.h"
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtGui/qpa/qplatformnativeinterface.h>
|
||||
#include <QtGui/qpa/qplatformwindow.h>
|
||||
#include <QtGui/qpa/qplatformscreen_p.h>
|
||||
#include <QtGui/qpa/qplatformscreen.h>
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
[[nodiscard]] static inline QScreen *findScreenForVirtualDesktop(const int virtualDesktopNumber)
|
||||
{
|
||||
const QList<QScreen *> screens = QGuiApplication::screens();
|
||||
if (screens.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
for (auto &&screen : qAsConst(screens)) {
|
||||
const auto qxcbScreen = dynamic_cast<QNativeInterface::Private::QXcbScreen *>(screen->handle());
|
||||
if (qxcbScreen && (qxcbScreen->virtualDesktopNumber() == virtualDesktopNumber)) {
|
||||
return screen;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QX11Info
|
||||
\inmodule QtGui
|
||||
\since 6.2
|
||||
\internal
|
||||
|
||||
\brief Provides information about the X display configuration.
|
||||
|
||||
The class provides two APIs: a set of non-static functions that
|
||||
provide information about a specific widget or pixmap, and a set
|
||||
of static functions that provide the default information for the
|
||||
application.
|
||||
|
||||
\warning This class is only available on X11. For querying
|
||||
per-screen information in a portable way, use QDesktopWidget.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs an empty QX11Info object.
|
||||
*/
|
||||
QX11Info::QX11Info()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Destructor of QX11Info object.
|
||||
*/
|
||||
QX11Info::~QX11Info() = default;
|
||||
|
||||
/*!
|
||||
Returns true if the application is currently running on X11.
|
||||
|
||||
\since 6.2
|
||||
*/
|
||||
bool QX11Info::isPlatformX11()
|
||||
{
|
||||
return QGuiApplication::platformName() == QLatin1String("xcb");
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the horizontal resolution of the given \a screen in terms of the
|
||||
number of dots per inch.
|
||||
|
||||
The \a screen argument is an X screen number. Be aware that if
|
||||
the user's system uses Xinerama (as opposed to traditional X11
|
||||
multiscreen), there is only one X screen. Use QDesktopWidget to
|
||||
query for information about Xinerama screens.
|
||||
|
||||
\sa appDpiY()
|
||||
*/
|
||||
int QX11Info::appDpiX(const int screen)
|
||||
{
|
||||
if (screen == -1) {
|
||||
const QScreen *scr = QGuiApplication::primaryScreen();
|
||||
if (!scr)
|
||||
return 75;
|
||||
return qRound(scr->logicalDotsPerInchX());
|
||||
}
|
||||
|
||||
QScreen *scr = findScreenForVirtualDesktop(screen);
|
||||
if (!scr)
|
||||
return 0;
|
||||
|
||||
return scr->logicalDotsPerInchX();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the vertical resolution of the given \a screen in terms of the
|
||||
number of dots per inch.
|
||||
|
||||
The \a screen argument is an X screen number. Be aware that if
|
||||
the user's system uses Xinerama (as opposed to traditional X11
|
||||
multiscreen), there is only one X screen. Use QDesktopWidget to
|
||||
query for information about Xinerama screens.
|
||||
|
||||
\sa appDpiX()
|
||||
*/
|
||||
int QX11Info::appDpiY(const int screen)
|
||||
{
|
||||
if (screen == -1) {
|
||||
const QScreen *scr = QGuiApplication::primaryScreen();
|
||||
if (!scr)
|
||||
return 75;
|
||||
return qRound(scr->logicalDotsPerInchY());
|
||||
}
|
||||
|
||||
QScreen *scr = findScreenForVirtualDesktop(screen);
|
||||
if (!scr)
|
||||
return 0;
|
||||
|
||||
return scr->logicalDotsPerInchY();
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a handle for the applications root window on the given \a screen.
|
||||
|
||||
The \a screen argument is an X screen number. Be aware that if
|
||||
the user's system uses Xinerama (as opposed to traditional X11
|
||||
multiscreen), there is only one X screen. Use QDesktopWidget to
|
||||
query for information about Xinerama screens.
|
||||
*/
|
||||
quint32 QX11Info::appRootWindow(const int screen)
|
||||
{
|
||||
if (!qApp)
|
||||
return 0;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return 0;
|
||||
QScreen *scr = screen == -1 ? QGuiApplication::primaryScreen() : findScreenForVirtualDesktop(screen);
|
||||
if (!scr)
|
||||
return 0;
|
||||
return static_cast<xcb_window_t>(reinterpret_cast<quintptr>(native->nativeResourceForScreen(QByteArrayLiteral("rootwindow"), scr)));
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the number of the screen where the application is being
|
||||
displayed.
|
||||
|
||||
This method refers to screens in the original X11 meaning with a
|
||||
different DISPLAY environment variable per screen.
|
||||
This information is only useful if your application needs to know
|
||||
on which X screen it is running.
|
||||
|
||||
In a typical multi-head configuration, multiple physical monitors
|
||||
are combined in one X11 screen. This means this method returns the
|
||||
same number for each of the physical monitors. In such a setup you
|
||||
are interested in the monitor information as provided by the X11
|
||||
RandR extension. This is available through QDesktopWidget and QScreen.
|
||||
|
||||
\sa display()
|
||||
*/
|
||||
int QX11Info::appScreen()
|
||||
{
|
||||
if (!qApp)
|
||||
return 0;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return 0;
|
||||
return reinterpret_cast<qintptr>(native->nativeResourceForIntegration(QByteArrayLiteral("x11screen")));
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the X11 time.
|
||||
|
||||
\sa setAppTime(), appUserTime()
|
||||
*/
|
||||
quint32 QX11Info::appTime()
|
||||
{
|
||||
if (!qApp)
|
||||
return 0;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return 0;
|
||||
QScreen* screen = QGuiApplication::primaryScreen();
|
||||
return static_cast<xcb_timestamp_t>(reinterpret_cast<quintptr>(native->nativeResourceForScreen("apptime", screen)));
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the X11 user time.
|
||||
|
||||
\sa setAppUserTime(), appTime()
|
||||
*/
|
||||
quint32 QX11Info::appUserTime()
|
||||
{
|
||||
if (!qApp)
|
||||
return 0;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return 0;
|
||||
QScreen* screen = QGuiApplication::primaryScreen();
|
||||
return static_cast<xcb_timestamp_t>(reinterpret_cast<quintptr>(native->nativeResourceForScreen("appusertime", screen)));
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the X11 time to the value specified by \a time.
|
||||
|
||||
\sa appTime(), setAppUserTime()
|
||||
*/
|
||||
void QX11Info::setAppTime(const quint32 time)
|
||||
{
|
||||
if (!qApp)
|
||||
return;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return;
|
||||
using SetAppTimeFunc = void(*)(QScreen *, xcb_timestamp_t);
|
||||
QScreen* screen = QGuiApplication::primaryScreen();
|
||||
auto func = reinterpret_cast<SetAppTimeFunc>(reinterpret_cast<void *>(native->nativeResourceFunctionForScreen("setapptime")));
|
||||
if (func)
|
||||
func(screen, time);
|
||||
else
|
||||
qWarning("Internal error: QPA plugin doesn't implement setAppTime");
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the X11 user time as specified by \a time.
|
||||
|
||||
\sa appUserTime(), setAppTime()
|
||||
*/
|
||||
void QX11Info::setAppUserTime(const quint32 time)
|
||||
{
|
||||
if (!qApp)
|
||||
return;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return;
|
||||
using SetAppUserTimeFunc = void(*)(QScreen *, xcb_timestamp_t);
|
||||
QScreen* screen = QGuiApplication::primaryScreen();
|
||||
auto func = reinterpret_cast<SetAppUserTimeFunc>(reinterpret_cast<void *>(native->nativeResourceFunctionForScreen("setappusertime")));
|
||||
if (func)
|
||||
func(screen, time);
|
||||
else
|
||||
qWarning("Internal error: QPA plugin doesn't implement setAppUserTime");
|
||||
}
|
||||
|
||||
/*!
|
||||
Fetches the current X11 time stamp from the X Server.
|
||||
|
||||
This method creates a property notify event and blocks till it is
|
||||
received back from the X Server.
|
||||
*/
|
||||
quint32 QX11Info::getTimestamp()
|
||||
{
|
||||
if (!qApp)
|
||||
return 0;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return 0;
|
||||
QScreen* screen = QGuiApplication::primaryScreen();
|
||||
return static_cast<xcb_timestamp_t>(reinterpret_cast<quintptr>(native->nativeResourceForScreen("gettimestamp", screen)));
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the startup ID that will be used for the next window to be shown by this process.
|
||||
|
||||
After the next window is shown, the next startup ID will be empty.
|
||||
|
||||
http://standards.freedesktop.org/startup-notification-spec/startup-notification-latest.txt
|
||||
|
||||
\sa setNextStartupId()
|
||||
*/
|
||||
QByteArray QX11Info::nextStartupId()
|
||||
{
|
||||
if (!qApp)
|
||||
return QByteArray();
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return QByteArray();
|
||||
return static_cast<char *>(native->nativeResourceForIntegration("startupid"));
|
||||
}
|
||||
|
||||
/*!
|
||||
Sets the next startup ID to \a id.
|
||||
|
||||
This is the startup ID that will be used for the next window to be shown by this process.
|
||||
|
||||
The startup ID of the first window comes from the environment variable DESKTOP_STARTUP_ID.
|
||||
This method is useful for subsequent windows, when the request comes from another process
|
||||
(e.g. via DBus).
|
||||
|
||||
\sa nextStartupId()
|
||||
*/
|
||||
void QX11Info::setNextStartupId(const QByteArray &id)
|
||||
{
|
||||
if (!qApp)
|
||||
return;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return;
|
||||
using SetStartupIdFunc = void(*)(const char*);
|
||||
auto func = reinterpret_cast<SetStartupIdFunc>(reinterpret_cast<void *>(native->nativeResourceFunctionForIntegration("setstartupid")));
|
||||
if (func)
|
||||
func(id.constData());
|
||||
else
|
||||
qWarning("Internal error: QPA plugin doesn't implement setStartupId");
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the default display for the application.
|
||||
|
||||
\sa appScreen()
|
||||
*/
|
||||
Display *QX11Info::display()
|
||||
{
|
||||
if (!qApp)
|
||||
return nullptr;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return nullptr;
|
||||
|
||||
void *display = native->nativeResourceForIntegration(QByteArray("display"));
|
||||
return reinterpret_cast<Display *>(display);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the default XCB connection for the application.
|
||||
|
||||
\sa display()
|
||||
*/
|
||||
xcb_connection_t *QX11Info::connection()
|
||||
{
|
||||
if (!qApp)
|
||||
return nullptr;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return nullptr;
|
||||
|
||||
void *connection = native->nativeResourceForIntegration(QByteArray("connection"));
|
||||
return reinterpret_cast<xcb_connection_t *>(connection);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns true if there is a compositing manager running for the connection
|
||||
attached to \a screen.
|
||||
|
||||
If \a screen equals -1, the application's primary screen is used.
|
||||
*/
|
||||
bool QX11Info::isCompositingManagerRunning(const int screen)
|
||||
{
|
||||
if (!qApp)
|
||||
return false;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return false;
|
||||
|
||||
QScreen *scr = screen == -1 ? QGuiApplication::primaryScreen() : findScreenForVirtualDesktop(screen);
|
||||
if (!scr) {
|
||||
qWarning() << "isCompositingManagerRunning: Could not find screen number" << screen;
|
||||
return false;
|
||||
}
|
||||
|
||||
return native->nativeResourceForScreen(QByteArray("compositingEnabled"), scr);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a new peeker id or -1 if some interal error has occurred.
|
||||
Each peeker id is associated with an index in the buffered native
|
||||
event queue.
|
||||
|
||||
For more details see QX11Info::PeekOption and peekEventQueue().
|
||||
|
||||
\sa peekEventQueue(), removePeekerId()
|
||||
*/
|
||||
qint32 QX11Info::generatePeekerId()
|
||||
{
|
||||
if (!qApp)
|
||||
return -1;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return -1;
|
||||
|
||||
using GeneratePeekerIdFunc = qint32(*)(void);
|
||||
auto generatepeekerid = reinterpret_cast<GeneratePeekerIdFunc>(
|
||||
reinterpret_cast<void *>(native->nativeResourceFunctionForIntegration("generatepeekerid")));
|
||||
if (!generatepeekerid) {
|
||||
qWarning("Internal error: QPA plugin doesn't implement generatePeekerId");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return generatepeekerid();
|
||||
}
|
||||
|
||||
/*!
|
||||
Removes \a peekerId, which was earlier obtained via generatePeekerId().
|
||||
|
||||
Returns \c true on success or \c false if unknown peeker id was
|
||||
provided or some interal error has occurred.
|
||||
|
||||
\sa generatePeekerId()
|
||||
*/
|
||||
bool QX11Info::removePeekerId(const qint32 peekerId)
|
||||
{
|
||||
if (!qApp)
|
||||
return false;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return false;
|
||||
|
||||
using RemovePeekerIdFunc = bool(*)(qint32);
|
||||
auto removePeekerId = reinterpret_cast<RemovePeekerIdFunc>(
|
||||
reinterpret_cast<void *>(native->nativeResourceFunctionForIntegration("removepeekerid")));
|
||||
if (!removePeekerId) {
|
||||
qWarning("Internal error: QPA plugin doesn't implement removePeekerId");
|
||||
return false;
|
||||
}
|
||||
|
||||
return removePeekerId(peekerId);
|
||||
}
|
||||
|
||||
/*!
|
||||
\enum QX11Info::PeekOption
|
||||
\brief An enum to tune the behavior of QX11Info::peekEventQueue().
|
||||
|
||||
\value PeekDefault
|
||||
Peek from the beginning of the buffered native event queue. A peeker
|
||||
id is optional with PeekDefault. If a peeker id is provided to
|
||||
peekEventQueue() when using PeekDefault, then peeking starts from
|
||||
the beginning of the queue, not from the cached index; thus, this
|
||||
can be used to manually reset a cached index to peek from the start
|
||||
of the queue. When this operation completes, the associated index
|
||||
will be updated to the new position in the queue.
|
||||
|
||||
\value PeekFromCachedIndex
|
||||
QX11Info::peekEventQueue() can optimize the peeking algorithm by
|
||||
skipping events that it already has seen in earlier calls to
|
||||
peekEventQueue(). When control returns to the main event loop,
|
||||
which causes the buffered native event queue to be flushed to Qt's
|
||||
event queue, the cached indices are marked invalid and will be
|
||||
reset on the next access. The same is true if the program
|
||||
explicitly flushes the buffered native event queue by
|
||||
QCoreApplication::processEvents().
|
||||
*/
|
||||
|
||||
/*!
|
||||
\typedef QX11Info::PeekerCallback
|
||||
Typedef for a pointer to a function with the following signature:
|
||||
|
||||
\code
|
||||
bool (*PeekerCallback)(xcb_generic_event_t *event, void *peekerData);
|
||||
\endcode
|
||||
|
||||
The \a event is a native XCB event.
|
||||
The \a peekerData is a pointer to data, passed in via peekEventQueue().
|
||||
|
||||
Return \c true from this function to stop examining the buffered
|
||||
native event queue or \c false to continue.
|
||||
|
||||
\note A non-capturing lambda can serve as a PeekerCallback.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\brief Peek into the buffered XCB event queue.
|
||||
|
||||
You can call peekEventQueue() periodically, when your program is busy
|
||||
performing a long-running operation, to peek into the buffered native
|
||||
event queue. The more time the long-running operation blocks the
|
||||
program from returning control to the main event loop, the more
|
||||
events will accumulate in the buffered XCB event queue. Once control
|
||||
returns to the main event loop these events will be flushed to Qt's
|
||||
event queue, which is a separate event queue from the queue this
|
||||
function is peeking into.
|
||||
|
||||
\note It is usually better to run CPU-intensive operations in a
|
||||
non-GUI thread, instead of blocking the main event loop.
|
||||
|
||||
The buffered XCB event queue is populated from a non-GUI thread and
|
||||
therefore might be ahead of the current GUI state. To handle native
|
||||
events as they are processed by the GUI thread, see
|
||||
QAbstractNativeEventFilter::nativeEventFilter().
|
||||
|
||||
The \a peeker is a callback function as documented in PeekerCallback.
|
||||
The \a peekerData can be used to pass in arbitrary data to the \a
|
||||
peeker callback.
|
||||
The \a option is an enum that tunes the behavior of peekEventQueue().
|
||||
The \a peekerId is used to track an index in the queue, for more
|
||||
details see QX11Info::PeekOption. There can be several indices,
|
||||
each tracked individually by a peeker id obtained via generatePeekerId().
|
||||
|
||||
This function returns \c true when the peeker has stopped the event
|
||||
proccesing by returning \c true from the callback. If there were no
|
||||
events in the buffered native event queue to peek at or all the
|
||||
events have been processed by the peeker, this function returns \c
|
||||
false.
|
||||
|
||||
\sa generatePeekerId(), QAbstractNativeEventFilter::nativeEventFilter()
|
||||
*/
|
||||
bool QX11Info::peekEventQueue(PeekerCallback peeker, void *peekerData,
|
||||
const PeekOptions option, const qint32 peekerId)
|
||||
{
|
||||
if (!peeker || !qApp)
|
||||
return false;
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native)
|
||||
return false;
|
||||
|
||||
using PeekEventQueueFunc = bool(*)(PeekerCallback, void *, const PeekOptions, const qint32);
|
||||
auto peekeventqueue = reinterpret_cast<PeekEventQueueFunc>(
|
||||
reinterpret_cast<void *>(native->nativeResourceFunctionForIntegration("peekeventqueue")));
|
||||
if (!peekeventqueue) {
|
||||
qWarning("Internal error: QPA plugin doesn't implement peekEventQueue");
|
||||
return false;
|
||||
}
|
||||
|
||||
return peekeventqueue(peeker, peekerData, option, peekerId);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
|
|
@ -0,0 +1,122 @@
|
|||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2022 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of the QtGui module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU Lesser General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||
** packaging of this file. Please review the following information to
|
||||
** ensure the GNU Lesser General Public License version 3 requirements
|
||||
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 2.0 or (at your option) the GNU General
|
||||
** Public license version 3 or any later version approved by the KDE Free
|
||||
** Qt Foundation. The licenses are as published by the Free Software
|
||||
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists purely as an
|
||||
// implementation detail. This header file may change from version to
|
||||
// version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include "framelesshelpercore_global.h"
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
#include <QtGui/private/qtx11extras_p.h>
|
||||
#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
#include <QtCore/private/qglobal_p.h>
|
||||
#include <QtGui/qtguiglobal.h>
|
||||
|
||||
struct xcb_connection_t;
|
||||
struct xcb_generic_event_t;
|
||||
struct _XDisplay;
|
||||
|
||||
using Display = struct _XDisplay;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
class FRAMELESSHELPER_CORE_API QX11Info
|
||||
{
|
||||
Q_DISABLE_COPY_MOVE(QX11Info)
|
||||
|
||||
public:
|
||||
enum class PeekOption
|
||||
{
|
||||
Default = 0x0000,
|
||||
FromCachedIndex = 0x0001
|
||||
};
|
||||
Q_ENUM(PeekOption)
|
||||
Q_DECLARE_FLAGS(PeekOptions, PeekOption)
|
||||
Q_FLAG(PeekOptions)
|
||||
|
||||
[[nodiscard]] static bool isPlatformX11();
|
||||
|
||||
[[nodiscard]] static int appDpiX(const int screen = -1);
|
||||
[[nodiscard]] static int appDpiY(const int screen = -1);
|
||||
|
||||
[[nodiscard]] static quint32 appRootWindow(const int screen = -1);
|
||||
[[nodiscard]] static int appScreen();
|
||||
|
||||
[[nodiscard]] static quint32 appTime();
|
||||
[[nodiscard]] static quint32 appUserTime();
|
||||
|
||||
static void setAppTime(const quint32 time);
|
||||
static void setAppUserTime(const quint32 time);
|
||||
|
||||
[[nodiscard]] static quint32 getTimestamp();
|
||||
|
||||
[[nodiscard]] static QByteArray nextStartupId();
|
||||
static void setNextStartupId(const QByteArray &id);
|
||||
|
||||
[[nodiscard]] static Display *display();
|
||||
[[nodiscard]] static xcb_connection_t *connection();
|
||||
|
||||
[[nodiscard]] static bool isCompositingManagerRunning(const int screen = -1);
|
||||
|
||||
[[nodiscard]] static qint32 generatePeekerId();
|
||||
[[nodiscard]] static bool removePeekerId(const qint32 peekerId);
|
||||
|
||||
using PeekerCallback = bool(*)(xcb_generic_event_t *, void *);
|
||||
[[nodiscard]] static bool peekEventQueue(PeekerCallback peeker, void *peekerData = nullptr,
|
||||
const PeekOptions option = PeekOption::Default, const qint32 peekerId = -1);
|
||||
|
||||
private:
|
||||
explicit QX11Info();
|
||||
~QX11Info();
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(QX11Info::PeekOptions)
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
|
@ -57,16 +57,6 @@ FRAMELESSHELPER_STRING_CONSTANT(light)
|
|||
FRAMELESSHELPER_STRING_CONSTANT(dark)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(highcontrast)
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
[[nodiscard]] extern bool shouldAppsUseDarkMode_windows();
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
[[nodiscard]] extern bool shouldAppsUseDarkMode_linux();
|
||||
#endif
|
||||
#ifdef Q_OS_MACOS
|
||||
[[nodiscard]] extern bool shouldAppsUseDarkMode_macos();
|
||||
#endif
|
||||
|
||||
Qt::CursorShape Utils::calculateCursorShape(const QWindow *window, const QPoint &pos)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
|
@ -256,7 +246,7 @@ QColor Utils::calculateSystemButtonBackgroundColor(const SystemButtonType button
|
|||
return getDwmColorizationColor();
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
return {};
|
||||
return getWmThemeColor();
|
||||
#endif
|
||||
#ifdef Q_OS_MACOS
|
||||
return getControlsAccentColor();
|
||||
|
|
|
@ -23,14 +23,10 @@
|
|||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "qtx11extras_p.h"
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qregularexpression.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
# include <QtGui/private/qtx11extras_p.h>
|
||||
#else
|
||||
# include <QX11Extras/qx11info.h>
|
||||
#endif
|
||||
#include <gtk/gtk.h>
|
||||
#include <X11/Xlib.h>
|
||||
|
||||
|
@ -48,13 +44,13 @@ static constexpr const auto _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT = 6;
|
|||
static constexpr const auto _NET_WM_MOVERESIZE_SIZE_LEFT = 7;
|
||||
static constexpr const auto _NET_WM_MOVERESIZE_MOVE = 8;
|
||||
|
||||
static constexpr const char WM_MOVERESIZE_OPERATION_NAME[] = "_NET_WM_MOVERESIZE";
|
||||
|
||||
static constexpr const char GTK_THEME_NAME_ENV_VAR[] = "GTK_THEME";
|
||||
static constexpr const char GTK_THEME_NAME_PROP[] = "gtk-theme-name";
|
||||
static constexpr const char GTK_THEME_PREFER_DARK_PROP[] = "gtk-application-prefer-dark-theme";
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(GTK_THEME_DARK_REGEX, "[:-]dark")
|
||||
|
||||
static constexpr const char WM_MOVERESIZE_OPERATION_NAME[] = "_NET_WM_MOVERESIZE";
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] static inline T gtkSetting(const gchar *propertyName)
|
||||
{
|
||||
|
@ -116,50 +112,6 @@ template<typename T>
|
|||
return -1;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool shouldAppsUseDarkMode_linux()
|
||||
{
|
||||
/*
|
||||
https://docs.gtk.org/gtk3/running.html
|
||||
|
||||
It's possible to set a theme variant after the theme name when using GTK_THEME:
|
||||
|
||||
GTK_THEME=Adwaita:dark
|
||||
|
||||
Some themes also have "-dark" as part of their name.
|
||||
|
||||
We test this environment variable first because the documentation says
|
||||
it's mainly used for easy debugging, so it should be possible to use it
|
||||
to override any other settings.
|
||||
*/
|
||||
static const QRegularExpression darkRegex(kGTK_THEME_DARK_REGEX, QRegularExpression::CaseInsensitiveOption);
|
||||
const QString envThemeName = qEnvironmentVariable(GTK_THEME_NAME_ENV_VAR);
|
||||
if (!envThemeName.isEmpty()) {
|
||||
return darkRegex.match(envThemeName).hasMatch();
|
||||
}
|
||||
|
||||
/*
|
||||
https://docs.gtk.org/gtk3/property.Settings.gtk-application-prefer-dark-theme.html
|
||||
|
||||
This setting controls which theme is used when the theme specified by
|
||||
gtk-theme-name provides both light and dark variants. We can save a
|
||||
regex check by testing this property first.
|
||||
*/
|
||||
const auto preferDark = gtkSetting<bool>(GTK_THEME_PREFER_DARK_PROP);
|
||||
if (preferDark) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
https://docs.gtk.org/gtk3/property.Settings.gtk-theme-name.html
|
||||
*/
|
||||
const QString curThemeName = gtkSetting(GTK_THEME_NAME_PROP);
|
||||
if (!curThemeName.isEmpty()) {
|
||||
return darkRegex.match(curThemeName).hasMatch();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void doStartSystemMoveResize(const WId windowId, const QPoint &globalPos, const int edges)
|
||||
{
|
||||
Q_ASSERT(windowId);
|
||||
|
@ -238,6 +190,57 @@ void Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi
|
|||
|
||||
bool Utils::isTitleBarColorized()
|
||||
{
|
||||
// ### TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
QColor Utils::getWmThemeColor()
|
||||
{
|
||||
// ### TODO
|
||||
return {};
|
||||
}
|
||||
|
||||
bool Utils::shouldAppsUseDarkMode_linux()
|
||||
{
|
||||
/*
|
||||
https://docs.gtk.org/gtk3/running.html
|
||||
|
||||
It's possible to set a theme variant after the theme name when using GTK_THEME:
|
||||
|
||||
GTK_THEME=Adwaita:dark
|
||||
|
||||
Some themes also have "-dark" as part of their name.
|
||||
|
||||
We test this environment variable first because the documentation says
|
||||
it's mainly used for easy debugging, so it should be possible to use it
|
||||
to override any other settings.
|
||||
*/
|
||||
static const QRegularExpression darkRegex(kGTK_THEME_DARK_REGEX, QRegularExpression::CaseInsensitiveOption);
|
||||
const QString envThemeName = qEnvironmentVariable(GTK_THEME_NAME_ENV_VAR);
|
||||
if (!envThemeName.isEmpty()) {
|
||||
return darkRegex.match(envThemeName).hasMatch();
|
||||
}
|
||||
|
||||
/*
|
||||
https://docs.gtk.org/gtk3/property.Settings.gtk-application-prefer-dark-theme.html
|
||||
|
||||
This setting controls which theme is used when the theme specified by
|
||||
gtk-theme-name provides both light and dark variants. We can save a
|
||||
regex check by testing this property first.
|
||||
*/
|
||||
const auto preferDark = gtkSetting<bool>(GTK_THEME_PREFER_DARK_PROP);
|
||||
if (preferDark) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
https://docs.gtk.org/gtk3/property.Settings.gtk-theme-name.html
|
||||
*/
|
||||
const QString curThemeName = gtkSetting(GTK_THEME_NAME_PROP);
|
||||
if (!curThemeName.isEmpty()) {
|
||||
return darkRegex.match(curThemeName).hasMatch();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,26 +26,17 @@
|
|||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <QtGui/private/qcoregraphics_p.h>
|
||||
#include <objc/runtime.h>
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
[[nodiscard]] Q_GUI_EXPORT QColor qt_mac_toQColor(const NSColor *color);
|
||||
QT_END_NAMESPACE
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
using namespace Global;
|
||||
|
||||
[[nodiscard]] bool shouldAppsUseDarkMode_macos()
|
||||
{
|
||||
#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
|
||||
if (__builtin_available(macOS 10.14, *)) {
|
||||
const auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
|
||||
@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]];
|
||||
return [appearance isEqualToString:NSAppearanceNameDarkAqua];
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
class NSWindowProxy
|
||||
{
|
||||
Q_DISABLE_COPY_MOVE(NSWindowProxy)
|
||||
|
@ -228,4 +219,16 @@ bool Utils::isTitleBarColorized()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Utils::shouldAppsUseDarkMode_macos()
|
||||
{
|
||||
#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
|
||||
if (__builtin_available(macOS 10.14, *)) {
|
||||
const auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
|
||||
@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]];
|
||||
return [appearance isEqualToString:NSAppearanceNameDarkAqua];
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -212,34 +212,6 @@ FRAMELESSHELPER_STRING_CONSTANT(ReleaseCapture)
|
|||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool shouldAppsUseDarkMode_windows()
|
||||
{
|
||||
// The global dark mode was first introduced in Windows 10 1607.
|
||||
if (!Utils::isWin101607OrGreater()) {
|
||||
return false;
|
||||
}
|
||||
const auto resultFromRegistry = []() -> bool {
|
||||
const QWinRegistryKey registry(HKEY_CURRENT_USER, qPersonalizeRegistryKey);
|
||||
const auto result = registry.dwordValue(kAppsUseLightTheme);
|
||||
return (result.second && (result.first == 0));
|
||||
};
|
||||
static const auto pShouldAppsUseDarkMode =
|
||||
reinterpret_cast<BOOL(WINAPI *)(VOID)>(
|
||||
QSystemLibrary::resolve(kuxtheme, MAKEINTRESOURCEA(132)));
|
||||
if (pShouldAppsUseDarkMode && !Utils::isWin101903OrGreater()) {
|
||||
return (pShouldAppsUseDarkMode() != FALSE);
|
||||
}
|
||||
// Starting from Windows 10 1903, "ShouldAppsUseDarkMode()" always return "TRUE"
|
||||
// (actually, a random non-zero number at runtime), so we can't use it due to
|
||||
// this unreliability. In this case, we just simply read the user's setting from
|
||||
// the registry instead, it's not elegant but at least it works well.
|
||||
// However, reverse engineering of Win11's Task Manager reveals that Microsoft still
|
||||
// uses this function internally to determine the system theme, and the Task Manager
|
||||
// can correctly respond to the theme change message indeed. Is it fixed silently
|
||||
// in some unknown Windows versions? To be checked.
|
||||
return resultFromRegistry();
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline LRESULT CALLBACK SystemMenuHookWindowProc
|
||||
(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam)
|
||||
{
|
||||
|
@ -1284,4 +1256,32 @@ void Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark)
|
|||
pSetWindowTheme(hwnd, (dark ? kSystemDarkThemeResourceName : kSystemLightThemeResourceName), nullptr);
|
||||
}
|
||||
|
||||
bool Utils::shouldAppsUseDarkMode_windows()
|
||||
{
|
||||
// The global dark mode was first introduced in Windows 10 1607.
|
||||
if (!isWin101607OrGreater()) {
|
||||
return false;
|
||||
}
|
||||
const auto resultFromRegistry = []() -> bool {
|
||||
const QWinRegistryKey registry(HKEY_CURRENT_USER, qPersonalizeRegistryKey);
|
||||
const auto result = registry.dwordValue(kAppsUseLightTheme);
|
||||
return (result.second && (result.first == 0));
|
||||
};
|
||||
static const auto pShouldAppsUseDarkMode =
|
||||
reinterpret_cast<BOOL(WINAPI *)(VOID)>(
|
||||
QSystemLibrary::resolve(kuxtheme, MAKEINTRESOURCEA(132)));
|
||||
if (pShouldAppsUseDarkMode && !isWin101903OrGreater()) {
|
||||
return (pShouldAppsUseDarkMode() != FALSE);
|
||||
}
|
||||
// Starting from Windows 10 1903, "ShouldAppsUseDarkMode()" always return "TRUE"
|
||||
// (actually, a random non-zero number at runtime), so we can't use it due to
|
||||
// this unreliability. In this case, we just simply read the user's setting from
|
||||
// the registry instead, it's not elegant but at least it works well.
|
||||
// However, reverse engineering of Win11's Task Manager reveals that Microsoft still
|
||||
// uses this function internally to determine the system theme, and the Task Manager
|
||||
// can correctly respond to the theme change message indeed. Is it fixed silently
|
||||
// in some unknown Windows versions? To be checked.
|
||||
return resultFromRegistry();
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -71,7 +71,7 @@ target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
|||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_URL_CAST_FROM_STRING
|
||||
QT_NO_CAST_FROM_BYTEARRAY
|
||||
#QT_NO_KEYWORDS
|
||||
#QT_NO_KEYWORDS # Some private Qt Quick headers are not keyword-clean, so sad :(
|
||||
QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
|
||||
QT_NO_FOREACH
|
||||
QT_USE_QSTRINGBUILDER
|
||||
|
|
|
@ -82,7 +82,7 @@ QColor FramelessQuickUtils::systemAccentColor()
|
|||
return Utils::getDwmColorizationColor();
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
return {};
|
||||
return Utils::getWmThemeColor();
|
||||
#endif
|
||||
#ifdef Q_OS_MACOS
|
||||
return Utils::getControlsAccentColor();
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "framelesswidgetshelper.h"
|
||||
#include "standardsystembutton.h"
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <QtGui/qpainter.h>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QtWidgets/qboxlayout.h>
|
||||
|
@ -70,7 +71,7 @@ const FramelessWidgetsHelper *FramelessWidgetsHelper::get(const QWidget *pub)
|
|||
if (!pub) {
|
||||
return nullptr;
|
||||
}
|
||||
return qvariant_cast<const FramelessWidgetsHelper *>(pub->property(FRAMELESSHELPER_PROP_NAME));
|
||||
return qvariant_cast<FramelessWidgetsHelper *>(pub->property(FRAMELESSHELPER_PROP_NAME));
|
||||
}
|
||||
|
||||
bool FramelessWidgetsHelper::isNormal() const
|
||||
|
|
Loading…
Reference in New Issue