Implement homemade Mica material & other improvements
Signed-off-by: Yuhang Zhao <2546789017@qq.com>
|
@ -25,7 +25,7 @@
|
|||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
project(FramelessHelper
|
||||
VERSION 2.1.8.0
|
||||
VERSION 2.2.0.0
|
||||
DESCRIPTION "Cross-platform window customization framework for Qt Widgets and Qt Quick."
|
||||
HOMEPAGE_URL "https://github.com/wangwenx190/framelesshelper/"
|
||||
LANGUAGES CXX
|
||||
|
|
BIN
doc/mac_dark.png
Before Width: | Height: | Size: 515 KiB After Width: | Height: | Size: 686 KiB |
Before Width: | Height: | Size: 714 KiB After Width: | Height: | Size: 524 KiB |
BIN
doc/win_dark.png
Before Width: | Height: | Size: 352 KiB After Width: | Height: | Size: 122 KiB |
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 81 KiB |
|
@ -26,10 +26,8 @@ if(FRAMELESSHELPER_BUILD_WIDGETS AND TARGET Qt${QT_VERSION_MAJOR}::Widgets)
|
|||
add_subdirectory(widget)
|
||||
add_subdirectory(mainwindow)
|
||||
add_subdirectory(openglwidget)
|
||||
add_subdirectory(widget-blur)
|
||||
endif()
|
||||
|
||||
if(FRAMELESSHELPER_BUILD_QUICK AND TARGET Qt${QT_VERSION_MAJOR}::Quick AND ${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
||||
add_subdirectory(quick)
|
||||
add_subdirectory(quick-blur)
|
||||
endif()
|
||||
|
|
|
@ -36,27 +36,16 @@ endif()
|
|||
|
||||
add_executable(MainWindow ${SOURCES})
|
||||
|
||||
set_target_properties(MainWindow PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER org.wangwenx190.framelesshelper.demo
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION 1.0.0.0
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING 1.0
|
||||
)
|
||||
|
||||
target_link_libraries(MainWindow PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
FramelessHelper::Widgets
|
||||
)
|
||||
|
||||
target_compile_definitions(MainWindow PRIVATE
|
||||
QT_NO_CAST_FROM_ASCII
|
||||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_KEYWORDS
|
||||
QT_USE_QSTRINGBUILDER
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060500
|
||||
)
|
||||
|
||||
include(../deployqt.cmake)
|
||||
deploy_qt_libraries(MainWindow)
|
||||
include(../../src/core/cmakehelper.cmake)
|
||||
setup_gui_app(MainWindow)
|
||||
setup_compile_params(MainWindow)
|
||||
deploy_qt_runtime(MainWindow)
|
||||
|
|
|
@ -37,6 +37,7 @@ int main(int argc, char *argv[])
|
|||
QApplication application(argc, argv);
|
||||
|
||||
FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners);
|
||||
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
|
||||
|
||||
MainWindow mainWindow;
|
||||
mainWindow.show();
|
||||
|
|
|
@ -48,14 +48,6 @@ endif()
|
|||
|
||||
add_executable(OpenGLWidget ${SOURCES})
|
||||
|
||||
set_target_properties(OpenGLWidget PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER org.wangwenx190.framelesshelper.demo
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION 1.0.0.0
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING 1.0
|
||||
)
|
||||
|
||||
target_link_libraries(OpenGLWidget PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
Qt${QT_VERSION_MAJOR}::OpenGL
|
||||
|
@ -69,13 +61,10 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
|
|||
endif()
|
||||
|
||||
target_compile_definitions(OpenGLWidget PRIVATE
|
||||
QT_NO_CAST_FROM_ASCII
|
||||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_KEYWORDS
|
||||
QT_USE_QSTRINGBUILDER
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060500
|
||||
)
|
||||
|
||||
include(../deployqt.cmake)
|
||||
deploy_qt_libraries(OpenGLWidget)
|
||||
include(../../src/core/cmakehelper.cmake)
|
||||
setup_gui_app(OpenGLWidget)
|
||||
setup_compile_params(OpenGLWidget)
|
||||
deploy_qt_runtime(OpenGLWidget)
|
||||
|
|
|
@ -74,6 +74,7 @@ int main(int argc, char *argv[])
|
|||
QApplication application(argc, argv);
|
||||
|
||||
FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners);
|
||||
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
|
||||
|
||||
QSurfaceFormat fmt = {};
|
||||
fmt.setDepthBufferSize(24);
|
||||
|
|
|
@ -1,87 +0,0 @@
|
|||
#[[
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Qml Quick QuickControls2)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Qml Quick QuickControls2)
|
||||
|
||||
set(SOURCES
|
||||
main.cpp
|
||||
settings.h
|
||||
settings.cpp
|
||||
)
|
||||
|
||||
if(${QT_VERSION} VERSION_LESS 6.2)
|
||||
list(APPEND SOURCES qml.qrc)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
enable_language(RC)
|
||||
list(APPEND SOURCES ../example.rc ../example.manifest)
|
||||
endif()
|
||||
|
||||
add_executable(QuickBlur ${SOURCES})
|
||||
|
||||
if(${QT_VERSION} VERSION_GREATER_EQUAL 6.2)
|
||||
qt_add_qml_module(QuickBlur
|
||||
URI Demo
|
||||
VERSION 1.0
|
||||
IMPORT_PATH ${PROJECT_BINARY_DIR}/imports
|
||||
IMPORTS
|
||||
QtQml
|
||||
QtQuick
|
||||
QtQuick.Controls.Basic
|
||||
org.wangwenx190.FramelessHelper
|
||||
QML_FILES MainWindow.qml
|
||||
#ENABLE_TYPE_COMPILER # We can't use it for now due to it still can't compile singletons.
|
||||
# There's some hope to get it supported in Qt 6.5.
|
||||
)
|
||||
endif()
|
||||
|
||||
set_target_properties(QuickBlur PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER org.wangwenx190.framelesshelper.demo
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION 1.0.0.0
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING 1.0
|
||||
)
|
||||
|
||||
target_link_libraries(QuickBlur PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::QmlPrivate
|
||||
Qt${QT_VERSION_MAJOR}::QuickPrivate
|
||||
Qt${QT_VERSION_MAJOR}::QuickControls2Private
|
||||
FramelessHelper::Quick
|
||||
)
|
||||
|
||||
target_compile_definitions(QuickBlur PRIVATE
|
||||
QT_NO_CAST_FROM_ASCII
|
||||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_KEYWORDS
|
||||
QT_USE_QSTRINGBUILDER
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060500
|
||||
$<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>
|
||||
)
|
||||
|
||||
include(../deployqt.cmake)
|
||||
deploy_qt_libraries(QuickBlur)
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls.Basic
|
||||
import org.wangwenx190.FramelessHelper
|
||||
import Demo
|
||||
|
||||
FramelessWindow {
|
||||
id: window
|
||||
visible: false // Hide the window before we sets up it's correct size and position.
|
||||
width: 800
|
||||
height: 600
|
||||
title: qsTr("FramelessHelper demo application - Qt Quick (Blur behind window)")
|
||||
onClosing: Settings.saveGeometry(window)
|
||||
|
||||
FramelessHelper.onReady: {
|
||||
// Let FramelessHelper know what's our homemade title bar, otherwise
|
||||
// our window won't be draggable.
|
||||
FramelessHelper.titleBarItem = titleBar;
|
||||
// Make our own items visible to the hit test and on Windows, enable
|
||||
// the snap layout feature (available since Windows 11).
|
||||
FramelessHelper.setSystemButton(titleBar.minimizeButton, FramelessHelperConstants.Minimize);
|
||||
FramelessHelper.setSystemButton(titleBar.maximizeButton, FramelessHelperConstants.Maximize);
|
||||
FramelessHelper.setSystemButton(titleBar.closeButton, FramelessHelperConstants.Close);
|
||||
if (!Settings.restoreGeometry(window)) {
|
||||
FramelessHelper.moveWindowToDesktopCenter();
|
||||
}
|
||||
FramelessHelper.blurBehindWindowEnabled = true;
|
||||
// Finally, show the window after everything is setted.
|
||||
window.visible = true;
|
||||
}
|
||||
|
||||
Timer {
|
||||
interval: 500
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: timeLabel.text = Qt.formatTime(new Date(), "hh:mm:ss")
|
||||
}
|
||||
|
||||
Label {
|
||||
id: timeLabel
|
||||
anchors.centerIn: parent
|
||||
font {
|
||||
pointSize: 70
|
||||
bold: true
|
||||
}
|
||||
color: (FramelessUtils.systemTheme === FramelessHelperConstants.Dark) ? "white" : "black"
|
||||
}
|
||||
|
||||
StandardTitleBar {
|
||||
id: titleBar
|
||||
anchors {
|
||||
top: window.topBorderBottom // VERY IMPORTANT!
|
||||
left: parent.left
|
||||
right: parent.right
|
||||
}
|
||||
titleLabelAlignment: Qt.AlignCenter
|
||||
chromePalette {
|
||||
titleBarActiveBackgroundColor: "transparent"
|
||||
titleBarInactiveBackgroundColor: "transparent"
|
||||
titleBarActiveForegroundColor: "black"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef QMLTC_ENABLED
|
||||
# define QMLTC_ENABLED 0 // We disable it for now, because currently (6.4) it can't process singletons yet.
|
||||
// There's some hope to get it supported in Qt 6.5
|
||||
#endif
|
||||
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtQml/qqmlapplicationengine.h>
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
#include <QtQuickControls2/qquickstyle.h>
|
||||
#include <framelessquickmodule.h>
|
||||
#include <framelessconfig_p.h>
|
||||
#include "settings.h"
|
||||
#if QMLTC_ENABLED
|
||||
# include <mainwindow.h>
|
||||
#endif
|
||||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Not necessary, but better call this function, before the construction
|
||||
// of any Q(Core|Gui)Application instances.
|
||||
FramelessHelper::Quick::initialize();
|
||||
|
||||
QGuiApplication application(argc, argv);
|
||||
|
||||
FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners);
|
||||
|
||||
// Enable QtRHI debug output if not explicitly requested by the user.
|
||||
if (!qEnvironmentVariableIsSet("QSG_INFO")) {
|
||||
qputenv("QSG_INFO", FRAMELESSHELPER_BYTEARRAY_LITERAL("1"));
|
||||
}
|
||||
|
||||
// Allow testing other RHI backends through environment variable.
|
||||
if (!qEnvironmentVariableIsSet("QSG_RHI_BACKEND")) {
|
||||
// This line is not relevant to FramelessHelper, we change
|
||||
// the default RHI backend to "software" just because it's
|
||||
// stable enough and have exactly the same behavior on all
|
||||
// supported platforms. Other backends may behave differently
|
||||
// on different platforms and graphics cards, so I think they
|
||||
// are not suitable for our demonstration.
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
QQuickWindow::setGraphicsApi(QSGRendererInterface::Software);
|
||||
#elif (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||
QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software);
|
||||
#endif
|
||||
}
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
#if !QMLTC_ENABLED
|
||||
engine.addImportPath(FRAMELESSHELPER_STRING_LITERAL("../imports"));
|
||||
#endif
|
||||
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 2, 0)) && !QMLTC_ENABLED
|
||||
// Don't forget to register our own custom QML types!
|
||||
FramelessHelper::Quick::registerTypes(&engine);
|
||||
|
||||
qmlRegisterSingletonType<Settings>("Demo", 1, 0, "Settings",
|
||||
[](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject * {
|
||||
Q_UNUSED(engine);
|
||||
Q_UNUSED(scriptEngine);
|
||||
return new Settings;
|
||||
});
|
||||
#endif
|
||||
|
||||
#if !QMLTC_ENABLED
|
||||
// This line is not relevant to FramelessHelper, we change the default
|
||||
// Qt Quick Controls theme to "Basic" (Qt6) or "Default" (Qt5) just
|
||||
// because other themes will make our homemade system buttons look
|
||||
// not good. This line has nothing to do with FramelessHelper itself.
|
||||
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
QQuickStyle::setStyle(FRAMELESSHELPER_STRING_LITERAL("Basic"));
|
||||
# else
|
||||
QQuickStyle::setStyle(FRAMELESSHELPER_STRING_LITERAL("Default"));
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !QMLTC_ENABLED
|
||||
const QUrl mainUrl(FRAMELESSHELPER_STRING_LITERAL("qrc:///Demo/MainWindow.qml"));
|
||||
#endif
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 4, 0))
|
||||
QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed, &application,
|
||||
[](const QUrl &url){
|
||||
qCritical() << "The QML engine failed to create component:" << url;
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
#elif !QMLTC_ENABLED
|
||||
const QMetaObject::Connection connection = QObject::connect(
|
||||
&engine, &QQmlApplicationEngine::objectCreated, &application,
|
||||
[&mainUrl, &connection](QObject *object, const QUrl &url) {
|
||||
if (url != mainUrl) {
|
||||
return;
|
||||
}
|
||||
if (object) {
|
||||
QObject::disconnect(connection);
|
||||
} else {
|
||||
QCoreApplication::exit(-1);
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
#endif
|
||||
|
||||
#if !QMLTC_ENABLED
|
||||
engine.load(mainUrl);
|
||||
#endif
|
||||
|
||||
#if QMLTC_ENABLED
|
||||
QScopedPointer<MainWindow> mainWindow(new MainWindow(&engine));
|
||||
mainWindow->show();
|
||||
#endif
|
||||
|
||||
return QCoreApplication::exec();
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
<RCC>
|
||||
<qresource prefix="/Demo">
|
||||
<file>MainWindow.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
|
@ -1,28 +0,0 @@
|
|||
:: MIT License
|
||||
::
|
||||
:: Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
::
|
||||
:: Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
:: of this software and associated documentation files (the "Software"), to deal
|
||||
:: in the Software without restriction, including without limitation the rights
|
||||
:: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
:: copies of the Software, and to permit persons to whom the Software is
|
||||
:: furnished to do so, subject to the following conditions:
|
||||
::
|
||||
:: The above copyright notice and this permission notice shall be included in
|
||||
:: all copies or substantial portions of the Software.
|
||||
::
|
||||
:: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
:: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
:: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
:: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
:: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
:: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
:: SOFTWARE.
|
||||
|
||||
@echo off
|
||||
setlocal
|
||||
set QSG_RHI_BACKEND=d3d11
|
||||
"%~dp0QuickBlur.exe"
|
||||
endlocal
|
||||
exit /b 0
|
|
@ -1,28 +0,0 @@
|
|||
:: MIT License
|
||||
::
|
||||
:: Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
::
|
||||
:: Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
:: of this software and associated documentation files (the "Software"), to deal
|
||||
:: in the Software without restriction, including without limitation the rights
|
||||
:: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
:: copies of the Software, and to permit persons to whom the Software is
|
||||
:: furnished to do so, subject to the following conditions:
|
||||
::
|
||||
:: The above copyright notice and this permission notice shall be included in
|
||||
:: all copies or substantial portions of the Software.
|
||||
::
|
||||
:: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
:: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
:: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
:: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
:: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
:: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
:: SOFTWARE.
|
||||
|
||||
@echo off
|
||||
setlocal
|
||||
set QSG_RHI_BACKEND=opengl
|
||||
"%~dp0QuickBlur.exe"
|
||||
endlocal
|
||||
exit /b 0
|
|
@ -1,28 +0,0 @@
|
|||
:: MIT License
|
||||
::
|
||||
:: Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
::
|
||||
:: Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
:: of this software and associated documentation files (the "Software"), to deal
|
||||
:: in the Software without restriction, including without limitation the rights
|
||||
:: to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
:: copies of the Software, and to permit persons to whom the Software is
|
||||
:: furnished to do so, subject to the following conditions:
|
||||
::
|
||||
:: The above copyright notice and this permission notice shall be included in
|
||||
:: all copies or substantial portions of the Software.
|
||||
::
|
||||
:: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
:: IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
:: FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
:: AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
:: LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
:: OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
:: SOFTWARE.
|
||||
|
||||
@echo off
|
||||
setlocal
|
||||
set QSG_RHI_BACKEND=vulkan
|
||||
"%~dp0QuickBlur.exe"
|
||||
endlocal
|
||||
exit /b 0
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "settings.h"
|
||||
#include <QtCore/qsettings.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qfileinfo.h>
|
||||
#include <QtCore/qdir.h>
|
||||
#include <QtCore/qdatastream.h>
|
||||
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPath, "Window/Geometry")
|
||||
|
||||
Settings::Settings(QObject *parent) : QObject(parent)
|
||||
{
|
||||
const QFileInfo fileInfo(QCoreApplication::applicationFilePath());
|
||||
const QString iniFileName = fileInfo.completeBaseName() + FRAMELESSHELPER_STRING_LITERAL(".ini");
|
||||
const QString iniFilePath = fileInfo.canonicalPath() + QDir::separator() + iniFileName;
|
||||
m_settings.reset(new QSettings(iniFilePath, QSettings::IniFormat));
|
||||
}
|
||||
|
||||
Settings::~Settings() = default;
|
||||
|
||||
void Settings::saveGeometry(QWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
QByteArray data = {};
|
||||
QDataStream stream(&data, QDataStream::WriteOnly);
|
||||
stream.setVersion(QDataStream::Qt_5_6);
|
||||
stream << window->geometry();
|
||||
m_settings->setValue(kIniKeyPath, data);
|
||||
}
|
||||
|
||||
bool Settings::restoreGeometry(QWindow *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return false;
|
||||
}
|
||||
const QByteArray data = m_settings->value(kIniKeyPath).toByteArray();
|
||||
if (data.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
QRect geometry = {};
|
||||
QDataStream stream(data);
|
||||
stream.setVersion(QDataStream::Qt_5_6);
|
||||
stream >> geometry;
|
||||
if (!geometry.isValid()) {
|
||||
return false;
|
||||
}
|
||||
window->setGeometry(geometry);
|
||||
return true;
|
||||
}
|
|
@ -58,14 +58,6 @@ if(${QT_VERSION} VERSION_GREATER_EQUAL 6.2)
|
|||
)
|
||||
endif()
|
||||
|
||||
set_target_properties(Quick PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER org.wangwenx190.framelesshelper.demo
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION 1.0.0.0
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING 1.0
|
||||
)
|
||||
|
||||
target_link_libraries(Quick PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::QmlPrivate
|
||||
Qt${QT_VERSION_MAJOR}::QuickPrivate
|
||||
|
@ -74,14 +66,11 @@ target_link_libraries(Quick PRIVATE
|
|||
)
|
||||
|
||||
target_compile_definitions(Quick PRIVATE
|
||||
QT_NO_CAST_FROM_ASCII
|
||||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_KEYWORDS
|
||||
QT_USE_QSTRINGBUILDER
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060500
|
||||
$<$<OR:$<CONFIG:Debug>,$<CONFIG:RelWithDebInfo>>:QT_QML_DEBUG>
|
||||
)
|
||||
|
||||
include(../deployqt.cmake)
|
||||
deploy_qt_libraries(Quick)
|
||||
include(../../src/core/cmakehelper.cmake)
|
||||
setup_gui_app(Quick)
|
||||
setup_compile_params(Quick)
|
||||
deploy_qt_runtime(Quick)
|
||||
|
|
|
@ -33,8 +33,15 @@ FramelessWindow {
|
|||
width: 800
|
||||
height: 600
|
||||
title: qsTr("FramelessHelper demo application - Qt Quick")
|
||||
color: (FramelessUtils.systemTheme === FramelessHelperConstants.Dark)
|
||||
? FramelessUtils.defaultSystemDarkColor : FramelessUtils.defaultSystemLightColor
|
||||
color: {
|
||||
if (FramelessHelper.blurBehindWindowEnabled) {
|
||||
return Qt.color("transparent");
|
||||
}
|
||||
if (FramelessUtils.systemTheme === FramelessHelperConstants.Dark) {
|
||||
return FramelessUtils.defaultSystemDarkColor;
|
||||
}
|
||||
return FramelessUtils.defaultSystemLightColor;
|
||||
}
|
||||
onClosing: Settings.saveGeometry(window)
|
||||
|
||||
FramelessHelper.onReady: {
|
||||
|
@ -67,7 +74,7 @@ FramelessWindow {
|
|||
pointSize: 70
|
||||
bold: true
|
||||
}
|
||||
color: (FramelessUtils.systemTheme === FramelessHelperConstants.Dark) ? "white" : "black"
|
||||
color: (FramelessUtils.systemTheme === FramelessHelperConstants.Dark) ? Qt.color("white") : Qt.color("black")
|
||||
}
|
||||
|
||||
StandardTitleBar {
|
||||
|
|
|
@ -49,6 +49,7 @@ int main(int argc, char *argv[])
|
|||
QGuiApplication application(argc, argv);
|
||||
|
||||
FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners);
|
||||
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
|
||||
|
||||
// Enable QtRHI debug output if not explicitly requested by the user.
|
||||
if (!qEnvironmentVariableIsSet("QSG_INFO")) {
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
#[[
|
||||
MIT License
|
||||
|
||||
Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
]]
|
||||
|
||||
set(SOURCES
|
||||
widget.h
|
||||
widget.cpp
|
||||
main.cpp
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
enable_language(RC)
|
||||
list(APPEND SOURCES ../example.rc ../example.manifest)
|
||||
endif()
|
||||
|
||||
add_executable(WidgetBlur ${SOURCES})
|
||||
|
||||
set_target_properties(WidgetBlur PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER org.wangwenx190.framelesshelper.demo
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION 1.0.0.0
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING 1.0
|
||||
)
|
||||
|
||||
target_link_libraries(WidgetBlur PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
FramelessHelper::Widgets
|
||||
)
|
||||
|
||||
target_compile_definitions(WidgetBlur PRIVATE
|
||||
QT_NO_CAST_FROM_ASCII
|
||||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_KEYWORDS
|
||||
QT_USE_QSTRINGBUILDER
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060500
|
||||
)
|
||||
|
||||
include(../deployqt.cmake)
|
||||
deploy_qt_libraries(WidgetBlur)
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <QtWidgets/qapplication.h>
|
||||
#include <framelessconfig_p.h>
|
||||
#include "widget.h"
|
||||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
// Not necessary, but better call this function, before the construction
|
||||
// of any Q(Core|Gui)Application instances.
|
||||
FramelessHelper::Widgets::initialize();
|
||||
|
||||
QApplication application(argc, argv);
|
||||
|
||||
FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners);
|
||||
|
||||
Widget widget;
|
||||
widget.show();
|
||||
|
||||
return QCoreApplication::exec();
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "widget.h"
|
||||
#include <QtCore/qdatetime.h>
|
||||
#include <QtCore/qsettings.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#include <QtCore/qfileinfo.h>
|
||||
#include <QtCore/qdir.h>
|
||||
#include <QtWidgets/qlabel.h>
|
||||
#include <QtWidgets/qboxlayout.h>
|
||||
#include <FramelessManager>
|
||||
#include <Utils>
|
||||
#include <FramelessWidgetsHelper>
|
||||
#include <StandardTitleBar>
|
||||
#include <StandardSystemButton>
|
||||
#include <ChromePalette>
|
||||
|
||||
FRAMELESSHELPER_USE_NAMESPACE
|
||||
|
||||
using namespace Global;
|
||||
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(IniKeyPath, "Window/Geometry")
|
||||
|
||||
[[nodiscard]] static inline QSettings *appConfigFile()
|
||||
{
|
||||
const QFileInfo fileInfo(QCoreApplication::applicationFilePath());
|
||||
const QString iniFileName = fileInfo.completeBaseName() + FRAMELESSHELPER_STRING_LITERAL(".ini");
|
||||
const QString iniFilePath = fileInfo.canonicalPath() + QDir::separator() + iniFileName;
|
||||
const auto settings = new QSettings(iniFilePath, QSettings::IniFormat);
|
||||
return settings;
|
||||
}
|
||||
|
||||
Widget::Widget(QWidget *parent) : FramelessWidget(parent)
|
||||
{
|
||||
initialize();
|
||||
startTimer(500);
|
||||
connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, this, &Widget::updateStyleSheet);
|
||||
}
|
||||
|
||||
Widget::~Widget() = default;
|
||||
|
||||
void Widget::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
FramelessWidget::timerEvent(event);
|
||||
if (m_clockLabel) {
|
||||
m_clockLabel->setText(QTime::currentTime().toString(FRAMELESSHELPER_STRING_LITERAL("hh:mm:ss")));
|
||||
}
|
||||
}
|
||||
|
||||
void Widget::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
const QScopedPointer<QSettings> settings(appConfigFile());
|
||||
settings->setValue(kIniKeyPath, saveGeometry());
|
||||
FramelessWidget::closeEvent(event);
|
||||
}
|
||||
|
||||
void Widget::initialize()
|
||||
{
|
||||
setWindowTitle(tr("FramelessHelper demo application - Qt Widgets (Blur behind window)"));
|
||||
resize(800, 600);
|
||||
m_titleBar.reset(new StandardTitleBar(this));
|
||||
m_titleBar->setTitleLabelAlignment(Qt::AlignCenter);
|
||||
ChromePalette *pal = m_titleBar->chromePalette();
|
||||
pal->setTitleBarActiveBackgroundColor(kDefaultTransparentColor);
|
||||
pal->setTitleBarInactiveBackgroundColor(kDefaultTransparentColor);
|
||||
pal->setTitleBarActiveForegroundColor(kDefaultBlackColor);
|
||||
m_clockLabel.reset(new QLabel(this));
|
||||
m_clockLabel->setFrameShape(QFrame::NoFrame);
|
||||
QFont clockFont = font();
|
||||
clockFont.setBold(true);
|
||||
clockFont.setPointSize(70);
|
||||
m_clockLabel->setFont(clockFont);
|
||||
const auto contentLayout = new QHBoxLayout;
|
||||
contentLayout->setContentsMargins(0, 0, 0, 0);
|
||||
contentLayout->setSpacing(0);
|
||||
contentLayout->addStretch();
|
||||
contentLayout->addWidget(m_clockLabel.data());
|
||||
contentLayout->addStretch();
|
||||
const auto mainLayout = new QVBoxLayout(this);
|
||||
mainLayout->setSpacing(0);
|
||||
mainLayout->setContentsMargins(0, 0, 0, 0);
|
||||
mainLayout->addWidget(m_titleBar.data());
|
||||
mainLayout->addLayout(contentLayout);
|
||||
setLayout(mainLayout);
|
||||
updateStyleSheet();
|
||||
|
||||
FramelessWidgetsHelper *helper = FramelessWidgetsHelper::get(this);
|
||||
helper->setTitleBarWidget(m_titleBar.data());
|
||||
helper->setSystemButton(m_titleBar->minimizeButton(), SystemButtonType::Minimize);
|
||||
helper->setSystemButton(m_titleBar->maximizeButton(), SystemButtonType::Maximize);
|
||||
helper->setSystemButton(m_titleBar->closeButton(), SystemButtonType::Close);
|
||||
connect(helper, &FramelessWidgetsHelper::ready, this, [this, helper](){
|
||||
const QScopedPointer<QSettings> settings(appConfigFile());
|
||||
const QByteArray data = settings->value(kIniKeyPath).toByteArray();
|
||||
if (data.isEmpty()) {
|
||||
helper->moveWindowToDesktopCenter();
|
||||
} else {
|
||||
restoreGeometry(data);
|
||||
}
|
||||
helper->setBlurBehindWindowEnabled(true);
|
||||
});
|
||||
}
|
||||
|
||||
void Widget::updateStyleSheet()
|
||||
{
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
const QColor clockLabelTextColor = (dark ? kDefaultWhiteColor : kDefaultBlackColor);
|
||||
m_clockLabel->setStyleSheet(FRAMELESSHELPER_STRING_LITERAL("color: %1;").arg(clockLabelTextColor.name()));
|
||||
update();
|
||||
}
|
|
@ -35,27 +35,16 @@ endif()
|
|||
|
||||
add_executable(Widget ${SOURCES})
|
||||
|
||||
set_target_properties(Widget PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER org.wangwenx190.framelesshelper.demo
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION 1.0.0.0
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING 1.0
|
||||
)
|
||||
|
||||
target_link_libraries(Widget PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Widgets
|
||||
FramelessHelper::Widgets
|
||||
)
|
||||
|
||||
target_compile_definitions(Widget PRIVATE
|
||||
QT_NO_CAST_FROM_ASCII
|
||||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_KEYWORDS
|
||||
QT_USE_QSTRINGBUILDER
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060500
|
||||
)
|
||||
|
||||
include(../deployqt.cmake)
|
||||
deploy_qt_libraries(Widget)
|
||||
include(../../src/core/cmakehelper.cmake)
|
||||
setup_gui_app(Widget)
|
||||
setup_compile_params(Widget)
|
||||
deploy_qt_runtime(Widget)
|
||||
|
|
|
@ -37,6 +37,7 @@ int main(int argc, char *argv[])
|
|||
QApplication application(argc, argv);
|
||||
|
||||
FramelessConfig::instance()->set(Global::Option::WindowUseRoundCorners);
|
||||
FramelessConfig::instance()->set(Global::Option::EnableBlurBehindWindow);
|
||||
|
||||
Widget widget;
|
||||
widget.show();
|
||||
|
|
|
@ -120,8 +120,12 @@ void Widget::updateStyleSheet()
|
|||
{
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
const QColor clockLabelTextColor = (dark ? kDefaultWhiteColor : kDefaultBlackColor);
|
||||
const QColor widgetBackgroundColor = (dark ? kDefaultSystemDarkColor : kDefaultSystemLightColor);
|
||||
m_clockLabel->setStyleSheet(FRAMELESSHELPER_STRING_LITERAL("color: %1;").arg(clockLabelTextColor.name()));
|
||||
setStyleSheet(FRAMELESSHELPER_STRING_LITERAL("background-color: %1;").arg(widgetBackgroundColor.name()));
|
||||
if (FramelessWidgetsHelper::get(this)->isBlurBehindWindowEnabled()) {
|
||||
setStyleSheet(FRAMELESSHELPER_STRING_LITERAL("background-color: transparent"));
|
||||
} else {
|
||||
const QColor windowBackgroundColor = (dark ? kDefaultSystemDarkColor : kDefaultSystemLightColor);
|
||||
setStyleSheet(FRAMELESSHELPER_STRING_LITERAL("background-color: %1").arg(windowBackgroundColor.name()));
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#include <micamaterial.h>
|
|
@ -26,9 +26,12 @@
|
|||
|
||||
#include "framelesshelpercore_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcChromePalette)
|
||||
|
||||
class ChromePalettePrivate;
|
||||
|
||||
class FRAMELESSHELPER_CORE_API ChromePalette : public QObject
|
||||
|
|
|
@ -26,9 +26,12 @@
|
|||
|
||||
#include "framelesshelpercore_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcFramelessHelperQt)
|
||||
|
||||
class FRAMELESSHELPER_CORE_API FramelessHelperQt : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
|
@ -26,9 +26,12 @@
|
|||
|
||||
#include "framelesshelpercore_global.h"
|
||||
#include <QtCore/qabstractnativeeventfilter.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcFramelessHelperWin)
|
||||
|
||||
class FRAMELESSHELPER_CORE_API FramelessHelperWin : public QAbstractNativeEventFilter
|
||||
{
|
||||
Q_DISABLE_COPY_MOVE(FramelessHelperWin)
|
||||
|
|
|
@ -385,3 +385,4 @@ EXTERN_C_END
|
|||
[[maybe_unused]] static constexpr const wchar_t kDwmColorKeyName[] = L"ColorPrevalence";
|
||||
[[maybe_unused]] static constexpr const wchar_t kSystemDarkThemeResourceName[] = L"DarkMode_Explorer";
|
||||
[[maybe_unused]] static constexpr const wchar_t kSystemLightThemeResourceName[] = L"Explorer";
|
||||
[[maybe_unused]] static constexpr const wchar_t kDesktopRegistryKey[] = LR"(Control Panel\Desktop)";
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <QtCore/qpoint.h>
|
||||
#include <QtCore/qsize.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtGui/qcolor.h>
|
||||
#include <QtGui/qwindowdefs.h>
|
||||
#include <functional>
|
||||
|
@ -185,6 +186,8 @@ QT_END_NAMESPACE
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcCoreGlobal)
|
||||
|
||||
#include <framelesshelper.version>
|
||||
|
||||
[[maybe_unused]] static constexpr const int FRAMELESSHELPER_VERSION =
|
||||
|
@ -228,7 +231,8 @@ enum class Option
|
|||
DisableWindowsSnapLayout = 3,
|
||||
WindowUseRoundCorners = 4,
|
||||
CenterWindowBeforeShow = 5,
|
||||
EnableBlurBehindWindow = 6
|
||||
EnableBlurBehindWindow = 6,
|
||||
ForceNonNativeBackgroundBlur = 7
|
||||
};
|
||||
Q_ENUM_NS(Option)
|
||||
|
||||
|
@ -333,6 +337,17 @@ enum class BlurMode
|
|||
};
|
||||
Q_ENUM_NS(BlurMode)
|
||||
|
||||
enum class WallpaperAspectStyle
|
||||
{
|
||||
Fill = 0, // Keep aspect ratio to fill, expand/crop if necessary.
|
||||
Fit = 1, // Keep aspect ratio to fill, but don't expand/crop.
|
||||
Stretch = 2, // Ignore aspect ratio to fill.
|
||||
Tile = 3,
|
||||
Center = 4,
|
||||
Span = 5 // ???
|
||||
};
|
||||
Q_ENUM_NS(WallpaperAspectStyle)
|
||||
|
||||
struct VersionNumber
|
||||
{
|
||||
int major = 0;
|
||||
|
|
|
@ -26,9 +26,12 @@
|
|||
|
||||
#include "framelesshelpercore_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcFramelessManager)
|
||||
|
||||
class FramelessManagerPrivate;
|
||||
|
||||
class FRAMELESSHELPER_CORE_API FramelessManager : public QObject
|
||||
|
@ -38,6 +41,8 @@ class FRAMELESSHELPER_CORE_API FramelessManager : public QObject
|
|||
Q_DISABLE_COPY_MOVE(FramelessManager)
|
||||
Q_PROPERTY(Global::SystemTheme systemTheme READ systemTheme NOTIFY systemThemeChanged FINAL)
|
||||
Q_PROPERTY(QColor systemAccentColor READ systemAccentColor NOTIFY systemThemeChanged FINAL)
|
||||
Q_PROPERTY(QString wallpaper READ wallpaper NOTIFY wallpaperChanged FINAL)
|
||||
Q_PROPERTY(Global::WallpaperAspectStyle wallpaperAspectStyle READ wallpaperAspectStyle NOTIFY wallpaperChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit FramelessManager(QObject *parent = nullptr);
|
||||
|
@ -47,12 +52,15 @@ public:
|
|||
|
||||
Q_NODISCARD Global::SystemTheme systemTheme() const;
|
||||
Q_NODISCARD QColor systemAccentColor() const;
|
||||
Q_NODISCARD QString wallpaper() const;
|
||||
Q_NODISCARD Global::WallpaperAspectStyle wallpaperAspectStyle() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
void addWindow(const Global::SystemParameters ¶ms);
|
||||
|
||||
Q_SIGNALS:
|
||||
void systemThemeChanged();
|
||||
void wallpaperChanged();
|
||||
|
||||
private:
|
||||
QScopedPointer<FramelessManagerPrivate> d_ptr;
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framelesshelpercore_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcMicaMaterial)
|
||||
|
||||
class MicaMaterialPrivate;
|
||||
|
||||
class FRAMELESSHELPER_CORE_API MicaMaterial : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(MicaMaterial)
|
||||
Q_DECLARE_PRIVATE(MicaMaterial)
|
||||
|
||||
Q_PROPERTY(QColor tintColor READ tintColor WRITE setTintColor NOTIFY tintColorChanged FINAL)
|
||||
Q_PROPERTY(qreal tintOpacity READ tintOpacity WRITE setTintOpacity NOTIFY tintOpacityChanged FINAL)
|
||||
Q_PROPERTY(qreal noiseOpacity READ noiseOpacity WRITE setNoiseOpacity NOTIFY noiseOpacityChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit MicaMaterial(QObject *parent = nullptr);
|
||||
~MicaMaterial() override;
|
||||
|
||||
Q_NODISCARD QColor tintColor() const;
|
||||
void setTintColor(const QColor &value);
|
||||
|
||||
Q_NODISCARD qreal tintOpacity() const;
|
||||
void setTintOpacity(const qreal value);
|
||||
|
||||
Q_NODISCARD qreal noiseOpacity() const;
|
||||
void setNoiseOpacity(const qreal value);
|
||||
|
||||
public Q_SLOTS:
|
||||
void paint(QPainter *painter, const QSize &size, const QPoint &pos) const;
|
||||
Q_NODISCARD static MicaMaterial *attach(QObject *target);
|
||||
|
||||
Q_SIGNALS:
|
||||
void tintColorChanged();
|
||||
void tintOpacityChanged();
|
||||
void noiseOpacityChanged();
|
||||
void shouldRedraw();
|
||||
|
||||
private:
|
||||
QScopedPointer<MicaMaterialPrivate> d_ptr;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(MicaMaterial))
|
|
@ -27,6 +27,7 @@
|
|||
#include "framelesshelpercore_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qvariant.h>
|
||||
#include <optional>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -49,12 +50,16 @@ public:
|
|||
static void setLoadFromEnvironmentVariablesDisabled(const bool on = true);
|
||||
static void setLoadFromConfigurationFileDisabled(const bool on = true);
|
||||
|
||||
Q_NODISCARD QVariant setInternal(const QString &key, const QVariant &value);
|
||||
Q_NODISCARD QVariant getInternal(const QString &key) const;
|
||||
Q_NODISCARD std::optional<QVariant> setInternal(const QString &key, const QVariant &value);
|
||||
Q_NODISCARD std::optional<QVariant> getInternal(const QString &key) const;
|
||||
template<typename T>
|
||||
Q_NODISCARD T getInternal(const QString &key) const
|
||||
Q_NODISCARD std::optional<T> getInternal(const QString &key) const
|
||||
{
|
||||
return qvariant_cast<T>(getInternal(key));
|
||||
const std::optional<QVariant> var = getInternal(key);
|
||||
if (var.has_value()) {
|
||||
return qvariant_cast<T>(var.value());
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -25,12 +25,12 @@
|
|||
#pragma once
|
||||
|
||||
#include "framelesshelpercore_global.h"
|
||||
#include "framelessmanager.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qpointer.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
class FramelessManager;
|
||||
|
||||
class FRAMELESSHELPER_CORE_API FramelessManagerPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@ -49,20 +49,26 @@ public:
|
|||
|
||||
Q_NODISCARD Global::SystemTheme systemTheme() const;
|
||||
Q_NODISCARD QColor systemAccentColor() const;
|
||||
Q_NODISCARD QString wallpaper() const;
|
||||
Q_NODISCARD Global::WallpaperAspectStyle wallpaperAspectStyle() const;
|
||||
|
||||
static void addWindow(const Global::SystemParameters ¶ms);
|
||||
|
||||
Q_INVOKABLE void notifySystemThemeHasChangedOrNot();
|
||||
Q_INVOKABLE void notifyWallpaperHasChangedOrNot();
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
FramelessManager *q_ptr = nullptr;
|
||||
QPointer<FramelessManager> q_ptr = nullptr;
|
||||
Global::SystemTheme m_systemTheme = Global::SystemTheme::Unknown;
|
||||
QColor m_accentColor = {};
|
||||
#ifdef Q_OS_WINDOWS
|
||||
Global::DwmColorizationArea m_colorizationArea = Global::DwmColorizationArea::None_;
|
||||
#endif
|
||||
QString m_wallpaper = {};
|
||||
Global::WallpaperAspectStyle m_wallpaperAspectStyle = Global::WallpaperAspectStyle::Fill;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -24,38 +24,45 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "framelesshelpercore_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <framelesshelpercore_global.h>
|
||||
#if __has_include(<QtQml/qqmlregistration.h>)
|
||||
# include <QtQml/qqmlregistration.h>
|
||||
#else
|
||||
# include <QtQml/qqml.h>
|
||||
#endif
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtGui/qbrush.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QSettings;
|
||||
QT_END_NAMESPACE
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
class Settings : public QObject
|
||||
class MicaMaterial;
|
||||
|
||||
class FRAMELESSHELPER_CORE_API MicaMaterialPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
#ifdef QML_ELEMENT
|
||||
QML_ELEMENT
|
||||
#endif
|
||||
#ifdef QML_SINGLETON
|
||||
QML_SINGLETON
|
||||
#endif
|
||||
Q_DISABLE_COPY_MOVE(Settings)
|
||||
Q_DISABLE_COPY_MOVE(MicaMaterialPrivate)
|
||||
Q_DECLARE_PUBLIC(MicaMaterial)
|
||||
|
||||
public:
|
||||
explicit Settings(QObject *parent = nullptr);
|
||||
~Settings() override;
|
||||
explicit MicaMaterialPrivate(MicaMaterial *q);
|
||||
~MicaMaterialPrivate() override;
|
||||
|
||||
Q_NODISCARD static MicaMaterialPrivate *get(MicaMaterial *q);
|
||||
Q_NODISCARD static const MicaMaterialPrivate *get(const MicaMaterial *q);
|
||||
|
||||
public Q_SLOTS:
|
||||
void saveGeometry(QWindow *window);
|
||||
Q_NODISCARD bool restoreGeometry(QWindow *window);
|
||||
void maybeGenerateBlurredWallpaper(const bool force = false);
|
||||
void updateMaterialBrush();
|
||||
void paint(QPainter *painter, const QSize &size, const QPoint &pos) const;
|
||||
Q_NODISCARD static MicaMaterial *attach(QObject *target);
|
||||
|
||||
private:
|
||||
QScopedPointer<QSettings> m_settings;
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
QPointer<MicaMaterial> q_ptr = nullptr;
|
||||
QColor tintColor = {};
|
||||
qreal tintOpacity = 0.0;
|
||||
qreal noiseOpacity = 0.0;
|
||||
QBrush micaBrush = {};
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(MicaMaterialPrivate))
|
|
@ -26,9 +26,19 @@
|
|||
|
||||
#include "framelesshelpercore_global.h"
|
||||
#include <QtGui/qwindowdefs.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcUtilsCommon)
|
||||
#ifdef Q_OS_WINDOWS
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcUtilsWin)
|
||||
#elif defined(Q_OS_LINUX)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcUtilsLinux)
|
||||
#elif defined(Q_OS_MACOS)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcUtilsMac)
|
||||
#endif
|
||||
|
||||
namespace Utils
|
||||
{
|
||||
|
||||
|
@ -55,6 +65,9 @@ FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(
|
|||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isTitleBarColorized();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool
|
||||
setBlurBehindWindowEnabled(const WId windowId, const Global::BlurMode mode, const QColor &color);
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QString getWallpaperFilePath();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API Global::WallpaperAspectStyle getWallpaperAspectStyle();
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isBlurBehindWindowSupported();
|
||||
|
||||
#ifdef Q_OS_WINDOWS
|
||||
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWindowsVersionOrGreater(const Global::WindowsVersion version);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
#include <quickmicamaterial.h>
|
|
@ -25,6 +25,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <framelesshelpercore_global.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#if __has_include(<QtQml/qqmlregistration.h>)
|
||||
# include <QtQml/qqmlregistration.h>
|
||||
#else
|
||||
|
@ -74,6 +75,8 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQuickGlobal)
|
||||
|
||||
[[maybe_unused]] static constexpr const char FRAMELESSHELPER_QUICK_URI[] = "org.wangwenx190.FramelessHelper";
|
||||
|
||||
struct FRAMELESSHELPER_QUICK_API QuickGlobal
|
||||
|
|
|
@ -26,9 +26,12 @@
|
|||
|
||||
#include "framelesshelperquick_global.h"
|
||||
#include <QtQuick/qquickitem.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcFramelessQuickHelper)
|
||||
|
||||
class FramelessQuickHelperPrivate;
|
||||
|
||||
class FRAMELESSHELPER_QUICK_API FramelessQuickHelper : public QQuickItem
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "framelesshelperquick_global.h"
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QQmlEngine;
|
||||
|
@ -32,6 +33,8 @@ QT_END_NAMESPACE
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQuickModule)
|
||||
|
||||
namespace FramelessHelper::Quick
|
||||
{
|
||||
FRAMELESSHELPER_QUICK_API void registerTypes(QQmlEngine *engine);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "framelesshelperquick_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtGui/qcolor.h>
|
||||
#include <QtQml/qqml.h>
|
||||
|
||||
|
@ -35,6 +36,8 @@ QT_END_NAMESPACE
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcFramelessQuickUtils)
|
||||
|
||||
class FRAMELESSHELPER_QUICK_API FramelessQuickUtils : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
|
@ -75,7 +75,7 @@ private Q_SLOTS:
|
|||
void updateTopBorderHeight();
|
||||
|
||||
private:
|
||||
FramelessQuickWindow *q_ptr = nullptr;
|
||||
QPointer<FramelessQuickWindow> q_ptr = nullptr;
|
||||
QScopedPointer<QQuickRectangle> m_topBorderRectangle;
|
||||
QScopedPointer<QQuickAnchors> m_topBorderAnchors;
|
||||
QQuickWindow::Visibility m_savedVisibility = QQuickWindow::Windowed;
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "framelesshelperquick_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qpointer.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
class QuickMicaMaterial;
|
||||
class WallpaperImageNode;
|
||||
|
||||
class FRAMELESSHELPER_QUICK_API QuickMicaMaterialPrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(QuickMicaMaterialPrivate)
|
||||
Q_DECLARE_PUBLIC(QuickMicaMaterial)
|
||||
|
||||
public:
|
||||
explicit QuickMicaMaterialPrivate(QuickMicaMaterial *q);
|
||||
~QuickMicaMaterialPrivate() override;
|
||||
|
||||
Q_NODISCARD static QuickMicaMaterialPrivate *get(QuickMicaMaterial *q);
|
||||
Q_NODISCARD static const QuickMicaMaterialPrivate *get(const QuickMicaMaterial *q);
|
||||
|
||||
public Q_SLOTS:
|
||||
void rebindWindow();
|
||||
void forceRegenerateWallpaperImageCache();
|
||||
void appendNode(WallpaperImageNode *node);
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
QPointer<QuickMicaMaterial> q_ptr = nullptr;
|
||||
QMetaObject::Connection m_rootWindowXChangedConnection = {};
|
||||
QMetaObject::Connection m_rootWindowYChangedConnection = {};
|
||||
QList<QPointer<WallpaperImageNode>> m_nodes = {};
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(QuickMicaMaterialPrivate))
|
|
@ -25,11 +25,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "framelesshelperquick_global.h"
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtQml/qqml.h>
|
||||
#include <chromepalette.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQuickChromePalette)
|
||||
|
||||
class FRAMELESSHELPER_QUICK_API QuickChromePalette : public ChromePalette
|
||||
{
|
||||
Q_OBJECT
|
||||
|
|
|
@ -24,36 +24,38 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <FramelessWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QLabel;
|
||||
QT_END_NAMESPACE
|
||||
#include "framelesshelperquick_global.h"
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtQuick/qquickitem.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
class StandardTitleBar;
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
class Widget : public FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessWidget)
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcQuickMicaMaterial)
|
||||
|
||||
class QuickMicaMaterialPrivate;
|
||||
|
||||
class FRAMELESSHELPER_QUICK_API QuickMicaMaterial : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(Widget)
|
||||
#ifdef QML_NAMED_ELEMENT
|
||||
QML_NAMED_ELEMENT(MicaMaterial)
|
||||
#endif
|
||||
Q_DISABLE_COPY_MOVE(QuickMicaMaterial)
|
||||
Q_DECLARE_PRIVATE(QuickMicaMaterial)
|
||||
|
||||
public:
|
||||
explicit Widget(QWidget *parent = nullptr);
|
||||
~Widget() override;
|
||||
explicit QuickMicaMaterial(QQuickItem *parent = nullptr);
|
||||
~QuickMicaMaterial() override;
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void itemChange(const ItemChange change, const ItemChangeData &value) override;
|
||||
[[nodiscard]] QSGNode *updatePaintNode(QSGNode *old, UpdatePaintNodeData *data) override;
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
private Q_SLOTS:
|
||||
void updateStyleSheet();
|
||||
|
||||
private:
|
||||
QScopedPointer<QLabel> m_clockLabel;
|
||||
QScopedPointer<FRAMELESSHELPER_PREPEND_NAMESPACE(StandardTitleBar)> m_titleBar;
|
||||
QScopedPointer<QuickMicaMaterialPrivate> d_ptr;
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(QuickMicaMaterial))
|
||||
QML_DECLARE_TYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(QuickMicaMaterial))
|
|
@ -25,6 +25,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <framelesshelpercore_global.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
#ifndef FRAMELESSHELPER_WIDGETS_API
|
||||
# ifdef FRAMELESSHELPER_WIDGETS_STATIC
|
||||
|
@ -40,6 +41,8 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcWidgetsGlobal)
|
||||
|
||||
namespace FramelessHelper::Widgets
|
||||
{
|
||||
FRAMELESSHELPER_WIDGETS_API void initialize();
|
||||
|
|
|
@ -25,10 +25,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "framelesshelperwidgets_global.h"
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtWidgets/qmainwindow.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcFramelessMainWindow)
|
||||
|
||||
class FramelessMainWindowPrivate;
|
||||
|
||||
class FRAMELESSHELPER_WIDGETS_API FramelessMainWindow : public QMainWindow
|
||||
|
|
|
@ -25,10 +25,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "framelesshelperwidgets_global.h"
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtWidgets/qwidget.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcFramelessWidget)
|
||||
|
||||
class FramelessWidgetPrivate;
|
||||
|
||||
class FRAMELESSHELPER_WIDGETS_API FramelessWidget : public QWidget
|
||||
|
|
|
@ -26,9 +26,12 @@
|
|||
|
||||
#include "framelesshelperwidgets_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcFramelessWidgetsHelper)
|
||||
|
||||
class FramelessWidgetsHelperPrivate;
|
||||
|
||||
class FRAMELESSHELPER_WIDGETS_API FramelessWidgetsHelper : public QObject
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "framelesshelperwidgets_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qpointer.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -51,11 +52,13 @@ public:
|
|||
void toggleMaximized();
|
||||
void toggleFullScreen();
|
||||
|
||||
Q_NODISCARD WidgetsSharedHelper *widgetsSharedHelper() const;
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
FramelessMainWindow *q_ptr = nullptr;
|
||||
QPointer<FramelessMainWindow> q_ptr = nullptr;
|
||||
Qt::WindowState m_savedWindowState = Qt::WindowNoState;
|
||||
QScopedPointer<WidgetsSharedHelper> m_helper;
|
||||
};
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "framelesshelperwidgets_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qpointer.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -51,11 +52,13 @@ public:
|
|||
void toggleMaximized();
|
||||
void toggleFullScreen();
|
||||
|
||||
Q_NODISCARD WidgetsSharedHelper *widgetsSharedHelper() const;
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
FramelessWidget *q_ptr = nullptr;
|
||||
QPointer<FramelessWidget> q_ptr = nullptr;
|
||||
Qt::WindowState m_savedWindowState = Qt::WindowNoState;
|
||||
QScopedPointer<WidgetsSharedHelper> m_helper;
|
||||
};
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "framelesshelperwidgets_global.h"
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qpointer.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QPaintEvent;
|
||||
|
@ -34,10 +35,13 @@ QT_END_NAMESPACE
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
class MicaMaterial;
|
||||
|
||||
class FRAMELESSHELPER_WIDGETS_API WidgetsSharedHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(WidgetsSharedHelper)
|
||||
Q_PROPERTY(bool micaEnabled READ isMicaEnabled WRITE setMicaEnabled NOTIFY micaEnabledChanged FINAL)
|
||||
|
||||
public:
|
||||
explicit WidgetsSharedHelper(QObject *parent = nullptr);
|
||||
|
@ -45,19 +49,32 @@ public:
|
|||
|
||||
void setup(QWidget *widget);
|
||||
|
||||
Q_NODISCARD bool isMicaEnabled() const;
|
||||
void setMicaEnabled(const bool value);
|
||||
|
||||
protected:
|
||||
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void updateContentsMargins();
|
||||
void handleScreenChanged(QScreen *screen);
|
||||
|
||||
private:
|
||||
void changeEventHandler(QEvent *event);
|
||||
void paintEventHandler(QPaintEvent *event);
|
||||
Q_NODISCARD bool shouldDrawFrameBorder() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void micaEnabledChanged();
|
||||
|
||||
private:
|
||||
QPointer<QWidget> m_targetWidget = nullptr;
|
||||
bool m_micaEnabled = false;
|
||||
QPointer<MicaMaterial> m_micaMaterial;
|
||||
QMetaObject::Connection m_micaRedrawConnection = {};
|
||||
QPointer<QScreen> m_screen = nullptr;
|
||||
qreal m_screenDpr = 0.0;
|
||||
QMetaObject::Connection m_screenDpiChangeConnection = {};
|
||||
};
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -25,10 +25,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "framelesshelperwidgets_global.h"
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <QtWidgets/qabstractbutton.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcStandardSystemButton)
|
||||
|
||||
class StandardSystemButtonPrivate;
|
||||
|
||||
class FRAMELESSHELPER_WIDGETS_API StandardSystemButton : public QAbstractButton
|
||||
|
|
|
@ -25,11 +25,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "framelesshelperwidgets_global.h"
|
||||
#include <QtCore/qloggingcategory.h>
|
||||
#include <chromepalette.h>
|
||||
#include <QtWidgets/qwidget.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(lcStandardTitleBar)
|
||||
|
||||
class StandardTitleBarPrivate;
|
||||
class StandardSystemButton;
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ set(PUBLIC_HEADERS
|
|||
${INCLUDE_PREFIX}/framelessmanager.h
|
||||
${INCLUDE_PREFIX}/utils.h
|
||||
${INCLUDE_PREFIX}/chromepalette.h
|
||||
${INCLUDE_PREFIX}/micamaterial.h
|
||||
)
|
||||
|
||||
set(PUBLIC_HEADERS_ALIAS
|
||||
|
@ -52,6 +53,7 @@ set(PUBLIC_HEADERS_ALIAS
|
|||
${INCLUDE_PREFIX}/FramelessManager
|
||||
${INCLUDE_PREFIX}/Utils
|
||||
${INCLUDE_PREFIX}/ChromePalette
|
||||
${INCLUDE_PREFIX}/MicaMaterial
|
||||
)
|
||||
|
||||
set(PRIVATE_HEADERS
|
||||
|
@ -59,6 +61,7 @@ set(PRIVATE_HEADERS
|
|||
${INCLUDE_PREFIX}/private/framelessconfig_p.h
|
||||
${INCLUDE_PREFIX}/private/sysapiloader_p.h
|
||||
${INCLUDE_PREFIX}/private/chromepalette_p.h
|
||||
${INCLUDE_PREFIX}/private/micamaterial_p.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
|
@ -70,6 +73,7 @@ set(SOURCES
|
|||
sysapiloader.cpp
|
||||
chromepalette.cpp
|
||||
global.cpp
|
||||
micamaterial.cpp
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
|
@ -118,38 +122,10 @@ if(FRAMELESSHELPER_BUILD_STATIC)
|
|||
endif()
|
||||
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
QT_NO_CAST_FROM_ASCII
|
||||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_URL_CAST_FROM_STRING
|
||||
QT_NO_CAST_FROM_BYTEARRAY
|
||||
QT_NO_KEYWORDS
|
||||
QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
|
||||
QT_NO_FOREACH
|
||||
QT_USE_QSTRINGBUILDER
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060500
|
||||
FRAMELESSHELPER_CORE_LIBRARY
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
set(_WIN32_WINNT_WIN10 0x0A00)
|
||||
set(NTDDI_WIN10_CO 0x0A00000B)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
_CRT_NON_CONFORMING_SWPRINTFS _CRT_SECURE_NO_WARNINGS
|
||||
_ENABLE_EXTENDED_ALIGNED_STORAGE NOMINMAX UNICODE
|
||||
_UNICODE WIN32_LEAN_AND_MEAN WINRT_LEAN_AND_MEAN
|
||||
WINVER=${_WIN32_WINNT_WIN10} _WIN32_WINNT=${_WIN32_WINNT_WIN10}
|
||||
_WIN32_IE=${_WIN32_WINNT_WIN10} NTDDI_VERSION=${NTDDI_WIN10_CO}
|
||||
)
|
||||
target_compile_options(${SUB_PROJ_NAME} PRIVATE
|
||||
/utf-8 /W3 /WX # Cannot use /W4 here, Qt's own headers are not warning-clean.
|
||||
)
|
||||
else()
|
||||
target_compile_options(${SUB_PROJ_NAME} PRIVATE
|
||||
-Wall -Wextra -Werror
|
||||
)
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
"-framework Foundation"
|
||||
|
@ -182,25 +158,6 @@ target_include_directories(${SUB_PROJ_NAME} PUBLIC
|
|||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}/private>"
|
||||
)
|
||||
|
||||
install(TARGETS ${SUB_PROJ_NAME}
|
||||
EXPORT ${SUB_PROJ_NAME}Targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}
|
||||
)
|
||||
|
||||
export(EXPORT ${SUB_PROJ_NAME}Targets
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/${SUB_PROJ_NAME}Targets.cmake"
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
)
|
||||
|
||||
install(FILES ${PUBLIC_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH})
|
||||
install(FILES ${PUBLIC_HEADERS_ALIAS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH})
|
||||
install(FILES ${PRIVATE_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}/private)
|
||||
|
||||
install(EXPORT ${SUB_PROJ_NAME}Targets
|
||||
FILE ${SUB_PROJ_NAME}Targets.cmake
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
include(cmakehelper.cmake)
|
||||
setup_compile_params(${SUB_PROJ_NAME})
|
||||
setup_package_export(${SUB_PROJ_NAME} ${SUB_PROJ_PATH} "${PUBLIC_HEADERS}" "${PUBLIC_HEADERS_ALIAS}" "${PRIVATE_HEADERS}")
|
||||
|
|
|
@ -29,6 +29,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcChromePalette, "wangwenx190.framelesshelper.core.chromepalette")
|
||||
#define INFO qCInfo(lcChromePalette)
|
||||
#define DEBUG qCDebug(lcChromePalette)
|
||||
#define WARNING qCWarning(lcChromePalette)
|
||||
#define CRITICAL qCCritical(lcChromePalette)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
ChromePalettePrivate::ChromePalettePrivate(ChromePalette *q) : QObject(q)
|
||||
|
|
|
@ -22,7 +22,74 @@
|
|||
SOFTWARE.
|
||||
]]
|
||||
|
||||
function(deploy_qt_libraries arg_target)
|
||||
function(setup_compile_params arg_target)
|
||||
target_compile_definitions(${arg_target} PRIVATE
|
||||
QT_NO_CAST_FROM_ASCII
|
||||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_URL_CAST_FROM_STRING
|
||||
QT_NO_CAST_FROM_BYTEARRAY
|
||||
#QT_NO_KEYWORDS # QtQuick headers still use traditional Qt keywords.
|
||||
QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
|
||||
QT_NO_FOREACH
|
||||
QT_USE_QSTRINGBUILDER
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060500
|
||||
)
|
||||
if(MSVC)
|
||||
set(_WIN32_WINNT_WIN10 0x0A00)
|
||||
set(NTDDI_WIN10_CO 0x0A00000B)
|
||||
target_compile_definitions(${arg_target} PRIVATE
|
||||
_CRT_NON_CONFORMING_SWPRINTFS _CRT_SECURE_NO_WARNINGS
|
||||
_ENABLE_EXTENDED_ALIGNED_STORAGE NOMINMAX UNICODE
|
||||
_UNICODE WIN32_LEAN_AND_MEAN WINRT_LEAN_AND_MEAN
|
||||
WINVER=${_WIN32_WINNT_WIN10} _WIN32_WINNT=${_WIN32_WINNT_WIN10}
|
||||
_WIN32_IE=${_WIN32_WINNT_WIN10} NTDDI_VERSION=${NTDDI_WIN10_CO}
|
||||
)
|
||||
target_compile_options(${arg_target} PRIVATE
|
||||
/utf-8 /W3 /WX # Cannot use /W4 here, Qt's own headers are not warning-clean.
|
||||
)
|
||||
target_link_options(${arg_target} PRIVATE /WX)
|
||||
else()
|
||||
target_compile_options(${arg_target} PRIVATE
|
||||
-Wall -Wextra -Werror
|
||||
)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(setup_gui_app arg_target)
|
||||
set_target_properties(${arg_target} PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER org.wangwenx190.${PROJECT_NAME}.app
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION 1.0.0.0
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING 1.0
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(setup_package_export arg_target arg_path arg_public arg_alias arg_private)
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS ${arg_target}
|
||||
EXPORT ${arg_target}Targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${arg_path}
|
||||
)
|
||||
export(EXPORT ${arg_target}Targets
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/${arg_target}Targets.cmake"
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
)
|
||||
install(FILES ${arg_public} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${arg_path})
|
||||
install(FILES ${arg_alias} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${arg_path})
|
||||
install(FILES ${arg_private} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${arg_path}/private)
|
||||
install(EXPORT ${arg_target}Targets
|
||||
FILE ${arg_target}Targets.cmake
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
endfunction()
|
||||
|
||||
function(deploy_qt_runtime arg_target)
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)
|
||||
if(NOT DEFINED QT_QMAKE_EXECUTABLE)
|
|
@ -30,6 +30,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFramelessConfig, "wangwenx190.framelesshelper.core.framelessconfig")
|
||||
#define INFO qCInfo(lcFramelessConfig)
|
||||
#define DEBUG qCDebug(lcFramelessConfig)
|
||||
#define WARNING qCWarning(lcFramelessConfig)
|
||||
#define CRITICAL qCCritical(lcFramelessConfig)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(ConfigFileName, ".framelesshelper.ini")
|
||||
|
@ -52,7 +58,9 @@ static const struct
|
|||
{FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_CENTER_WINDOW_BEFORE_SHOW"),
|
||||
FRAMELESSHELPER_BYTEARRAY_LITERAL("Options/CenterWindowBeforeShow")},
|
||||
{FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_ENABLE_BLUR_BEHIND_WINDOW"),
|
||||
FRAMELESSHELPER_BYTEARRAY_LITERAL("Options/EnableBlurBehindWindow")}
|
||||
FRAMELESSHELPER_BYTEARRAY_LITERAL("Options/EnableBlurBehindWindow")},
|
||||
{FRAMELESSHELPER_BYTEARRAY_LITERAL("FRAMELESSHELPER_FORCE_NON_NATIVE_BACKGROUND_BLUR"),
|
||||
FRAMELESSHELPER_BYTEARRAY_LITERAL("Options/ForceNonNativeBackgroundBlur")}
|
||||
};
|
||||
|
||||
static constexpr const auto OptionCount = std::size(OptionsTable);
|
||||
|
@ -131,14 +139,14 @@ void FramelessConfig::setLoadFromConfigurationFileDisabled(const bool on)
|
|||
g_data()->disableCfgFile = on;
|
||||
}
|
||||
|
||||
QVariant FramelessConfig::setInternal(const QString &key, const QVariant &value)
|
||||
std::optional<QVariant> FramelessConfig::setInternal(const QString &key, const QVariant &value)
|
||||
{
|
||||
Q_ASSERT(!key.isEmpty());
|
||||
Q_ASSERT(value.isValid());
|
||||
if (key.isEmpty() || !value.isValid()) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
QVariant previous = {};
|
||||
std::optional<QVariant> previous = std::nullopt;
|
||||
QMutexLocker locker(&g_data()->mutex);
|
||||
if (g_data()->internals.contains(key)) {
|
||||
previous = g_data()->internals.value(key);
|
||||
|
@ -148,14 +156,17 @@ QVariant FramelessConfig::setInternal(const QString &key, const QVariant &value)
|
|||
return previous;
|
||||
}
|
||||
|
||||
QVariant FramelessConfig::getInternal(const QString &key) const
|
||||
std::optional<QVariant> FramelessConfig::getInternal(const QString &key) const
|
||||
{
|
||||
Q_ASSERT(!key.isEmpty());
|
||||
if (key.isEmpty()) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
QMutexLocker locker(&g_data()->mutex);
|
||||
return (g_data()->internals.contains(key) ? g_data()->internals.value(key) : QVariant{});
|
||||
if (g_data()->internals.contains(key)) {
|
||||
return g_data()->internals.value(key);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -33,6 +33,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFramelessHelperQt, "wangwenx190.framelesshelper.core.impl.qt")
|
||||
#define INFO qCInfo(lcFramelessHelperQt)
|
||||
#define DEBUG qCDebug(lcFramelessHelperQt)
|
||||
#define WARNING qCWarning(lcFramelessHelperQt)
|
||||
#define CRITICAL qCCritical(lcFramelessHelperQt)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
struct QtHelperData
|
||||
|
@ -104,9 +110,12 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
|||
// First detect whether we got a theme change event or not, if so,
|
||||
// inform the user the system theme has changed.
|
||||
if (Utils::isThemeChangeEvent(event)) {
|
||||
FramelessManager *manager = FramelessManager::instance();
|
||||
FramelessManagerPrivate *managerPriv = FramelessManagerPrivate::get(manager);
|
||||
managerPriv->notifySystemThemeHasChangedOrNot();
|
||||
// Sometimes the FramelessManager instance may be destroyed already.
|
||||
if (FramelessManager * const manager = FramelessManager::instance()) {
|
||||
if (FramelessManagerPrivate * const managerPriv = FramelessManagerPrivate::get(manager)) {
|
||||
managerPriv->notifySystemThemeHasChangedOrNot();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// We are only interested in events that are dispatched to top level windows.
|
||||
|
|
|
@ -38,27 +38,15 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFramelessHelperWin, "wangwenx190.framelesshelper.core.impl.win")
|
||||
#define INFO qCInfo(lcFramelessHelperWin)
|
||||
#define DEBUG qCDebug(lcFramelessHelperWin)
|
||||
#define WARNING qCWarning(lcFramelessHelperWin)
|
||||
#define CRITICAL qCCritical(lcFramelessHelperWin)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
struct Win32HelperData
|
||||
{
|
||||
SystemParameters params = {};
|
||||
bool trackingMouse = false;
|
||||
WId fallbackTitleBarWindowId = 0;
|
||||
};
|
||||
|
||||
struct Win32Helper
|
||||
{
|
||||
QMutex mutex;
|
||||
QScopedPointer<FramelessHelperWin> nativeEventFilter;
|
||||
QHash<WId, Win32HelperData> data = {};
|
||||
QHash<WId, WId> fallbackTitleBarToParentWindowMapping = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
||||
|
||||
static constexpr const wchar_t FALLBACK_TITLEBAR_CLASS_NAME[] = L"FALLBACK_TITLEBAR_WINDOW_CLASS\0";
|
||||
|
||||
static constexpr const wchar_t kFallbackTitleBarWindowClass[] = L"FALLBACK_TITLEBAR_WINDOW_CLASS\0";
|
||||
FRAMELESSHELPER_BYTEARRAY_CONSTANT2(Win32MessageTypeName, "windows_generic_MSG")
|
||||
FRAMELESSHELPER_STRING_CONSTANT(MonitorFromWindow)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(GetMonitorInfoW)
|
||||
|
@ -84,6 +72,23 @@ FRAMELESSHELPER_STRING_CONSTANT(SetWindowPos)
|
|||
FRAMELESSHELPER_STRING_CONSTANT(TrackMouseEvent)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
||||
|
||||
struct Win32HelperData
|
||||
{
|
||||
SystemParameters params = {};
|
||||
bool trackingMouse = false;
|
||||
WId fallbackTitleBarWindowId = 0;
|
||||
};
|
||||
|
||||
struct Win32Helper
|
||||
{
|
||||
QMutex mutex;
|
||||
QScopedPointer<FramelessHelperWin> nativeEventFilter;
|
||||
QHash<WId, Win32HelperData> data = {};
|
||||
QHash<WId, WId> fallbackTitleBarToParentWindowMapping = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(Win32Helper, g_win32Helper)
|
||||
|
||||
[[nodiscard]] static inline LRESULT CALLBACK FallbackTitleBarWindowProc
|
||||
(const HWND hWnd, const UINT uMsg, const WPARAM wParam, const LPARAM lParam)
|
||||
{
|
||||
|
@ -109,27 +114,6 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
|||
// Hit-testing event should not be considered as a mouse event.
|
||||
const bool isMouseEvent = (((uMsg >= WM_MOUSEFIRST) && (uMsg <= WM_MOUSELAST)) ||
|
||||
((uMsg >= WM_NCMOUSEMOVE) && (uMsg <= WM_NCXBUTTONDBLCLK)));
|
||||
#if 0 // Need extra safe guard, otherwise will crash, but since it's not used, just comment them out.
|
||||
// We only use this fallback title bar window to activate the snap layout feature, if the parent
|
||||
// window is not resizable, the snap layout feature should also be disabled at the same time,
|
||||
// hence forward everything to the parent window, we don't need to handle anything here.
|
||||
if (data.params.isWindowFixedSize()) {
|
||||
// Let the mouse event pass through our fallback title bar window to the root window
|
||||
// under it, to ensure our homemade title bar keep functional.
|
||||
if (uMsg == WM_NCHITTEST) {
|
||||
return HTTRANSPARENT;
|
||||
}
|
||||
// Forward all mouse events to the parent window to let the controls inside
|
||||
// our homemade title bar still continue to work normally. But ignore these
|
||||
// events in this fallback title bar window due to there are no controls in it.
|
||||
if (isMouseEvent) {
|
||||
SendMessageW(parentWindowHandle, uMsg, wParam, lParam);
|
||||
return 0;
|
||||
}
|
||||
// For all other events just use the default handling.
|
||||
return DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
}
|
||||
#endif
|
||||
const auto releaseButtons = [&data](const std::optional<SystemButtonType> exclude) -> void {
|
||||
static constexpr const auto defaultButtonState = ButtonState::Unspecified;
|
||||
if (!exclude.has_value() || (exclude.value() != SystemButtonType::WindowIcon)) {
|
||||
|
@ -170,7 +154,7 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
|||
const POINT nativeGlobalPos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
||||
POINT nativeLocalPos = nativeGlobalPos;
|
||||
if (ScreenToClient(hWnd, &nativeLocalPos) == FALSE) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kScreenToClient);
|
||||
WARNING << Utils::getSystemErrorMessage(kScreenToClient);
|
||||
break;
|
||||
}
|
||||
const qreal devicePixelRatio = data.params.getWindowDevicePixelRatio();
|
||||
|
@ -253,7 +237,7 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
|||
tme.hwndTrack = hWnd;
|
||||
tme.dwHoverTime = HOVER_DEFAULT; // We don't _really_ care about this.
|
||||
if (TrackMouseEvent(&tme) == FALSE) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kTrackMouseEvent);
|
||||
WARNING << Utils::getSystemErrorMessage(kTrackMouseEvent);
|
||||
break;
|
||||
}
|
||||
QMutexLocker locker(&g_win32Helper()->mutex);
|
||||
|
@ -368,7 +352,7 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
|||
const auto parentWindowHandle = reinterpret_cast<HWND>(parentWindowId);
|
||||
RECT parentWindowClientRect = {};
|
||||
if (GetClientRect(parentWindowHandle, &parentWindowClientRect) == FALSE) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kGetClientRect);
|
||||
WARNING << Utils::getSystemErrorMessage(kGetClientRect);
|
||||
return false;
|
||||
}
|
||||
const int titleBarHeight = Utils::getTitleBarHeight(parentWindowId, true);
|
||||
|
@ -385,7 +369,7 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
|||
// into all the magic behind it.
|
||||
if (SetWindowPos(fallbackTitleBarWindowHandle, HWND_TOP, 0, 0,
|
||||
parentWindowClientRect.right, titleBarHeight, flags) == FALSE) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kSetWindowPos);
|
||||
WARNING << Utils::getSystemErrorMessage(kSetWindowPos);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -399,14 +383,14 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
|||
}
|
||||
static const bool isWin10OrGreater = Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1507);
|
||||
if (!isWin10OrGreater) {
|
||||
qWarning() << "The fallback title bar window is only supported on Windows 10 and onwards.";
|
||||
WARNING << "The fallback title bar window is only supported on Windows 10 and onwards.";
|
||||
return false;
|
||||
}
|
||||
const auto parentWindowHandle = reinterpret_cast<HWND>(parentWindowId);
|
||||
const auto instance = static_cast<HINSTANCE>(GetModuleHandleW(nullptr));
|
||||
Q_ASSERT(instance);
|
||||
if (!instance) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kGetModuleHandleW);
|
||||
WARNING << Utils::getSystemErrorMessage(kGetModuleHandleW);
|
||||
return false;
|
||||
}
|
||||
static const ATOM fallbackTitleBarWindowClass = [instance]() -> ATOM {
|
||||
|
@ -414,7 +398,7 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
|||
SecureZeroMemory(&wcex, sizeof(wcex));
|
||||
wcex.cbSize = sizeof(wcex);
|
||||
wcex.style = (CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS);
|
||||
wcex.lpszClassName = FALLBACK_TITLEBAR_CLASS_NAME;
|
||||
wcex.lpszClassName = kFallbackTitleBarWindowClass;
|
||||
wcex.hbrBackground = static_cast<HBRUSH>(GetStockObject(BLACK_BRUSH));
|
||||
wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW);
|
||||
wcex.lpfnWndProc = FallbackTitleBarWindowProc;
|
||||
|
@ -423,24 +407,24 @@ FRAMELESSHELPER_STRING_CONSTANT(FindWindowW)
|
|||
}();
|
||||
Q_ASSERT(fallbackTitleBarWindowClass);
|
||||
if (!fallbackTitleBarWindowClass) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kRegisterClassExW);
|
||||
WARNING << Utils::getSystemErrorMessage(kRegisterClassExW);
|
||||
return false;
|
||||
}
|
||||
const HWND fallbackTitleBarWindowHandle = CreateWindowExW((WS_EX_LAYERED | WS_EX_NOREDIRECTIONBITMAP),
|
||||
FALLBACK_TITLEBAR_CLASS_NAME, nullptr, WS_CHILD, 0, 0, 0, 0,
|
||||
kFallbackTitleBarWindowClass, nullptr, WS_CHILD, 0, 0, 0, 0,
|
||||
parentWindowHandle, nullptr, instance, nullptr);
|
||||
Q_ASSERT(fallbackTitleBarWindowHandle);
|
||||
if (!fallbackTitleBarWindowHandle) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kCreateWindowExW);
|
||||
WARNING << Utils::getSystemErrorMessage(kCreateWindowExW);
|
||||
return false;
|
||||
}
|
||||
if (SetLayeredWindowAttributes(fallbackTitleBarWindowHandle, 0, 255, LWA_ALPHA) == FALSE) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kSetLayeredWindowAttributes);
|
||||
WARNING << Utils::getSystemErrorMessage(kSetLayeredWindowAttributes);
|
||||
return false;
|
||||
}
|
||||
const auto fallbackTitleBarWindowId = reinterpret_cast<WId>(fallbackTitleBarWindowHandle);
|
||||
if (!resizeFallbackTitleBarWindow(parentWindowId, fallbackTitleBarWindowId, hide)) {
|
||||
qWarning() << "Failed to re-position the fallback title bar window.";
|
||||
WARNING << "Failed to re-position the fallback title bar window.";
|
||||
return false;
|
||||
}
|
||||
QMutexLocker locker(&g_win32Helper()->mutex);
|
||||
|
@ -479,9 +463,7 @@ void FramelessHelperWin::addWindow(const SystemParameters ¶ms)
|
|||
static const bool isWin10RS1OrGreater = Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1607);
|
||||
if (isWin10RS1OrGreater) {
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 4, 0))
|
||||
Utils::updateWindowFrameBorderColor(windowId, dark);
|
||||
#endif
|
||||
static const bool isWin10RS5OrGreater = Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1809);
|
||||
if (isWin10RS5OrGreater) {
|
||||
static const bool isQtQuickApplication = (params.getCurrentApplicationType() == ApplicationType::Quick);
|
||||
|
@ -497,7 +479,7 @@ void FramelessHelperWin::addWindow(const SystemParameters ¶ms)
|
|||
// introduced in Windows 11, so it's not necessary to create it on systems below Win11.
|
||||
if (!config->isSet(Option::DisableWindowsSnapLayout)) {
|
||||
if (!createFallbackTitleBarWindow(windowId, data.params.isWindowFixedSize())) {
|
||||
qWarning() << "Failed to create the fallback title bar window.";
|
||||
WARNING << "Failed to create the fallback title bar window.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -684,11 +666,11 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
monitorInfo.cbSize = sizeof(monitorInfo);
|
||||
const HMONITOR monitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (!monitor) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kMonitorFromWindow);
|
||||
WARNING << Utils::getSystemErrorMessage(kMonitorFromWindow);
|
||||
break;
|
||||
}
|
||||
if (GetMonitorInfoW(monitor, &monitorInfo) == FALSE) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kGetMonitorInfoW);
|
||||
WARNING << Utils::getSystemErrorMessage(kGetMonitorInfoW);
|
||||
break;
|
||||
}
|
||||
// This helper can be used to determine if there's a
|
||||
|
@ -716,12 +698,12 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
if (_abd.hWnd) {
|
||||
const HMONITOR windowMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
|
||||
if (!windowMonitor) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kMonitorFromWindow);
|
||||
WARNING << Utils::getSystemErrorMessage(kMonitorFromWindow);
|
||||
break;
|
||||
}
|
||||
const HMONITOR taskbarMonitor = MonitorFromWindow(_abd.hWnd, MONITOR_DEFAULTTOPRIMARY);
|
||||
if (!taskbarMonitor) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kMonitorFromWindow);
|
||||
WARNING << Utils::getSystemErrorMessage(kMonitorFromWindow);
|
||||
break;
|
||||
}
|
||||
if (taskbarMonitor == windowMonitor) {
|
||||
|
@ -729,7 +711,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
edge = _abd.uEdge;
|
||||
}
|
||||
} else {
|
||||
qWarning() << Utils::getSystemErrorMessage(kFindWindowW);
|
||||
WARNING << Utils::getSystemErrorMessage(kFindWindowW);
|
||||
break;
|
||||
}
|
||||
top = (edge == ABE_TOP);
|
||||
|
@ -857,7 +839,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
const POINT nativeGlobalPos = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
||||
POINT nativeLocalPos = nativeGlobalPos;
|
||||
if (ScreenToClient(hWnd, &nativeLocalPos) == FALSE) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kScreenToClient);
|
||||
WARNING << Utils::getSystemErrorMessage(kScreenToClient);
|
||||
break;
|
||||
}
|
||||
const qreal dpr = data.params.getWindowDevicePixelRatio();
|
||||
|
@ -914,7 +896,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
if (!isFixedSize) {
|
||||
RECT clientRect = {0, 0, 0, 0};
|
||||
if (GetClientRect(hWnd, &clientRect) == FALSE) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kGetClientRect);
|
||||
WARNING << Utils::getSystemErrorMessage(kGetClientRect);
|
||||
break;
|
||||
}
|
||||
const LONG width = clientRect.right;
|
||||
|
@ -1033,7 +1015,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
SetLastError(ERROR_SUCCESS);
|
||||
const auto oldStyle = static_cast<DWORD>(GetWindowLongPtrW(hWnd, GWL_STYLE));
|
||||
if (oldStyle == 0) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kGetWindowLongPtrW);
|
||||
WARNING << Utils::getSystemErrorMessage(kGetWindowLongPtrW);
|
||||
break;
|
||||
}
|
||||
// Prevent Windows from drawing the default title bar by temporarily
|
||||
|
@ -1041,14 +1023,14 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
const DWORD newStyle = (oldStyle & ~WS_VISIBLE);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetWindowLongPtrW(hWnd, GWL_STYLE, static_cast<LONG_PTR>(newStyle)) == 0) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
WARNING << Utils::getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
break;
|
||||
}
|
||||
Utils::triggerFrameChange(windowId);
|
||||
const LRESULT ret = DefWindowProcW(hWnd, uMsg, wParam, lParam);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetWindowLongPtrW(hWnd, GWL_STYLE, static_cast<LONG_PTR>(oldStyle)) == 0) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
WARNING << Utils::getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
break;
|
||||
}
|
||||
Utils::triggerFrameChange(windowId);
|
||||
|
@ -1059,21 +1041,22 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
break;
|
||||
}
|
||||
}
|
||||
static const bool isWin10OrGreater = Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1507);
|
||||
if (isWin10OrGreater && data.fallbackTitleBarWindowId) {
|
||||
static const bool isWin11OrGreater = Utils::isWindowsVersionOrGreater(WindowsVersion::_11_21H2);
|
||||
if (isWin11OrGreater && data.fallbackTitleBarWindowId) {
|
||||
switch (uMsg) {
|
||||
case WM_SIZE: // Sent to a window after its size has changed.
|
||||
case WM_DISPLAYCHANGE: // Sent to a window when the display resolution has changed.
|
||||
{
|
||||
const bool isFixedSize = data.params.isWindowFixedSize();
|
||||
if (!resizeFallbackTitleBarWindow(windowId, data.fallbackTitleBarWindowId, isFixedSize)) {
|
||||
qWarning() << "Failed to re-position the fallback title bar window.";
|
||||
WARNING << "Failed to re-position the fallback title bar window.";
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
const bool wallpaperChanged = ((uMsg == WM_SETTINGCHANGE) && (wParam == SPI_SETDESKWALLPAPER));
|
||||
bool systemThemeChanged = ((uMsg == WM_THEMECHANGED) || (uMsg == WM_SYSCOLORCHANGE)
|
||||
|| (uMsg == WM_DWMCOLORIZATIONCOLORCHANGED));
|
||||
static const bool isWin10RS1OrGreater = Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1607);
|
||||
|
@ -1083,9 +1066,7 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
&& (std::wcscmp(reinterpret_cast<LPCWSTR>(lParam), kThemeSettingChangeEventName) == 0)) {
|
||||
systemThemeChanged = true;
|
||||
const bool dark = Utils::shouldAppsUseDarkMode();
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(6, 4, 0))
|
||||
Utils::updateWindowFrameBorderColor(windowId, dark);
|
||||
#endif
|
||||
static const bool isWin10RS5OrGreater = Utils::isWindowsVersionOrGreater(WindowsVersion::_10_1809);
|
||||
if (isWin10RS5OrGreater) {
|
||||
static const bool isQtQuickApplication = (data.params.getCurrentApplicationType() == ApplicationType::Quick);
|
||||
|
@ -1097,12 +1078,17 @@ bool FramelessHelperWin::nativeEventFilter(const QByteArray &eventType, void *me
|
|||
}
|
||||
}
|
||||
}
|
||||
if (systemThemeChanged) {
|
||||
// In some rare cases the FramelessManager instance may be destroyed already.
|
||||
FramelessManager *manager = FramelessManager::instance();
|
||||
if (manager) {
|
||||
FramelessManagerPrivate *managerPriv = FramelessManagerPrivate::get(manager);
|
||||
managerPriv->notifySystemThemeHasChangedOrNot();
|
||||
if (systemThemeChanged || wallpaperChanged) {
|
||||
// Sometimes the FramelessManager instance may be destroyed already.
|
||||
if (FramelessManager * const manager = FramelessManager::instance()) {
|
||||
if (FramelessManagerPrivate * const managerPriv = FramelessManagerPrivate::get(manager)) {
|
||||
if (systemThemeChanged) {
|
||||
managerPriv->notifySystemThemeHasChangedOrNot();
|
||||
}
|
||||
if (wallpaperChanged) {
|
||||
managerPriv->notifyWallpaperHasChangedOrNot();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<RCC>
|
||||
<qresource prefix="/org.wangwenx190.FramelessHelper">
|
||||
<file>resources/fonts/Micon.ttf</file>
|
||||
<file>resources/images/noise.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
@ -22,7 +22,6 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "framelessmanager.h"
|
||||
#include "framelessmanager_p.h"
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
|
@ -47,6 +46,12 @@ static inline void initResource()
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFramelessManager, "wangwenx190.framelesshelper.core.framelessmanager")
|
||||
#define INFO qCInfo(lcFramelessManager)
|
||||
#define DEBUG qCDebug(lcFramelessManager)
|
||||
#define WARNING qCWarning(lcFramelessManager)
|
||||
#define CRITICAL qCCritical(lcFramelessManager)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
struct FramelessManagerHelper
|
||||
|
@ -63,7 +68,11 @@ FRAMELESSHELPER_STRING_CONSTANT2(IconFontFilePath, ":/org.wangwenx190.FramelessH
|
|||
FRAMELESSHELPER_STRING_CONSTANT2(IconFontFamilyName_win11, "Segoe Fluent Icons")
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(IconFontFamilyName_win10, "Segoe MDL2 Assets")
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(IconFontFamilyName_common, "micon_nb")
|
||||
static constexpr const int kIconFontPointSize = 8;
|
||||
#ifdef Q_OS_MACOS
|
||||
static constexpr const int kIconFontPointSize = 10;
|
||||
#else
|
||||
static constexpr const int kIconFontPointSize = 8;
|
||||
#endif
|
||||
|
||||
[[nodiscard]] static inline QString iconFontFamilyName()
|
||||
{
|
||||
|
@ -121,11 +130,12 @@ void FramelessManagerPrivate::initializeIconFont()
|
|||
}
|
||||
inited = true;
|
||||
initResource();
|
||||
// We always register this font because it's our only fallback.
|
||||
const int id = QFontDatabase::addApplicationFont(kIconFontFilePath);
|
||||
if (id < 0) {
|
||||
qWarning() << "Failed to load icon font:" << kIconFontFilePath;
|
||||
WARNING << "Failed to load icon font:" << kIconFontFilePath;
|
||||
} else {
|
||||
qDebug() << "Successfully registered icon font:" << QFontDatabase::applicationFontFamilies(id);
|
||||
DEBUG << "Successfully registered icon font:" << QFontDatabase::applicationFontFamilies(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -142,14 +152,28 @@ QFont FramelessManagerPrivate::getIconFont()
|
|||
|
||||
SystemTheme FramelessManagerPrivate::systemTheme() const
|
||||
{
|
||||
QMutexLocker locker(&g_helper()->mutex);
|
||||
return m_systemTheme;
|
||||
}
|
||||
|
||||
QColor FramelessManagerPrivate::systemAccentColor() const
|
||||
{
|
||||
QMutexLocker locker(&g_helper()->mutex);
|
||||
return m_accentColor;
|
||||
}
|
||||
|
||||
QString FramelessManagerPrivate::wallpaper() const
|
||||
{
|
||||
QMutexLocker locker(&g_helper()->mutex);
|
||||
return m_wallpaper;
|
||||
}
|
||||
|
||||
WallpaperAspectStyle FramelessManagerPrivate::wallpaperAspectStyle() const
|
||||
{
|
||||
QMutexLocker locker(&g_helper()->mutex);
|
||||
return m_wallpaperAspectStyle;
|
||||
}
|
||||
|
||||
void FramelessManagerPrivate::addWindow(const SystemParameters ¶ms)
|
||||
{
|
||||
Q_ASSERT(params.isValid());
|
||||
|
@ -203,11 +227,11 @@ void FramelessManagerPrivate::addWindow(const SystemParameters ¶ms)
|
|||
|
||||
void FramelessManagerPrivate::notifySystemThemeHasChangedOrNot()
|
||||
{
|
||||
Q_Q(FramelessManager);
|
||||
QMutexLocker locker(&g_helper()->mutex);
|
||||
const SystemTheme currentSystemTheme = Utils::getSystemTheme();
|
||||
#ifdef Q_OS_WINDOWS
|
||||
const DwmColorizationArea currentColorizationArea = Utils::getDwmColorizationArea();
|
||||
const QColor currentAccentColor = Utils::getDwmColorizationColor();
|
||||
const QColor currentAccentColor = Utils::getDwmAccentColor();
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
const QColor currentAccentColor = Utils::getWmThemeColor();
|
||||
|
@ -231,16 +255,40 @@ void FramelessManagerPrivate::notifySystemThemeHasChangedOrNot()
|
|||
}
|
||||
#endif
|
||||
if (notify) {
|
||||
Q_Q(FramelessManager);
|
||||
Q_EMIT q->systemThemeChanged();
|
||||
DEBUG << "Detected system theme changed.";
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessManagerPrivate::notifyWallpaperHasChangedOrNot()
|
||||
{
|
||||
QMutexLocker locker(&g_helper()->mutex);
|
||||
const QString currentWallpaper = Utils::getWallpaperFilePath();
|
||||
const WallpaperAspectStyle currentWallpaperAspectStyle = Utils::getWallpaperAspectStyle();
|
||||
bool notify = false;
|
||||
if (m_wallpaper != currentWallpaper) {
|
||||
m_wallpaper = currentWallpaper;
|
||||
notify = true;
|
||||
}
|
||||
if (m_wallpaperAspectStyle != currentWallpaperAspectStyle) {
|
||||
m_wallpaperAspectStyle = currentWallpaperAspectStyle;
|
||||
notify = true;
|
||||
}
|
||||
if (notify) {
|
||||
Q_Q(FramelessManager);
|
||||
Q_EMIT q->wallpaperChanged();
|
||||
DEBUG << "Detected wallpaper changed.";
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessManagerPrivate::initialize()
|
||||
{
|
||||
QMutexLocker locker(&g_helper()->mutex);
|
||||
m_systemTheme = Utils::getSystemTheme();
|
||||
#ifdef Q_OS_WINDOWS
|
||||
m_colorizationArea = Utils::getDwmColorizationArea();
|
||||
m_accentColor = Utils::getDwmColorizationColor();
|
||||
m_accentColor = Utils::getDwmAccentColor();
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
m_accentColor = Utils::getWmThemeColor();
|
||||
|
@ -248,6 +296,8 @@ void FramelessManagerPrivate::initialize()
|
|||
#ifdef Q_OS_MACOS
|
||||
m_accentColor = Utils::getControlsAccentColor();
|
||||
#endif
|
||||
m_wallpaper = Utils::getWallpaperFilePath();
|
||||
m_wallpaperAspectStyle = Utils::getWallpaperAspectStyle();
|
||||
}
|
||||
|
||||
FramelessManager::FramelessManager(QObject *parent) :
|
||||
|
@ -274,6 +324,18 @@ QColor FramelessManager::systemAccentColor() const
|
|||
return d->systemAccentColor();
|
||||
}
|
||||
|
||||
QString FramelessManager::wallpaper() const
|
||||
{
|
||||
Q_D(const FramelessManager);
|
||||
return d->wallpaper();
|
||||
}
|
||||
|
||||
WallpaperAspectStyle FramelessManager::wallpaperAspectStyle() const
|
||||
{
|
||||
Q_D(const FramelessManager);
|
||||
return d->wallpaperAspectStyle();
|
||||
}
|
||||
|
||||
void FramelessManager::addWindow(const SystemParameters ¶ms)
|
||||
{
|
||||
Q_D(FramelessManager);
|
||||
|
|
|
@ -30,10 +30,12 @@
|
|||
#endif
|
||||
#include "framelesshelper_qt.h"
|
||||
#include "chromepalette.h"
|
||||
#include "micamaterial.h"
|
||||
#include "sysapiloader_p.h"
|
||||
#include "framelessmanager_p.h"
|
||||
#include "framelessconfig_p.h"
|
||||
#include "chromepalette_p.h"
|
||||
#include "micamaterial_p.h"
|
||||
#include <QtGui/qguiapplication.h>
|
||||
|
||||
#ifndef COMPILER_STRING
|
||||
|
@ -72,6 +74,12 @@ FRAMELESSHELPER_BYTEARRAY_CONSTANT2(ValueOne, "1")
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcCoreGlobal, "wangwenx190.framelesshelper.core.global")
|
||||
#define INFO qCInfo(lcCoreGlobal)
|
||||
#define DEBUG qCDebug(lcCoreGlobal)
|
||||
#define WARNING qCWarning(lcCoreGlobal)
|
||||
#define CRITICAL qCCritical(lcCoreGlobal)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
namespace FramelessHelper::Core
|
||||
|
@ -141,6 +149,7 @@ void initialize()
|
|||
qRegisterMetaType<WindowsVersion>();
|
||||
qRegisterMetaType<ApplicationType>();
|
||||
qRegisterMetaType<BlurMode>();
|
||||
qRegisterMetaType<WallpaperAspectStyle>();
|
||||
qRegisterMetaType<VersionNumber>();
|
||||
qRegisterMetaType<SystemParameters>();
|
||||
qRegisterMetaType<VersionInfo>();
|
||||
|
@ -155,6 +164,8 @@ void initialize()
|
|||
qRegisterMetaType<FramelessManagerPrivate>();
|
||||
qRegisterMetaType<FramelessConfig>();
|
||||
qRegisterMetaType<ChromePalettePrivate>();
|
||||
qRegisterMetaType<MicaMaterial>();
|
||||
qRegisterMetaType<MicaMaterialPrivate>();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,684 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "micamaterial.h"
|
||||
#include "micamaterial_p.h"
|
||||
#include "framelessmanager.h"
|
||||
#include "utils.h"
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qsysinfo.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtGui/qpixmap.h>
|
||||
#include <QtGui/qimage.h>
|
||||
#include <QtGui/qpainter.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtGui/private/qguiapplication_p.h>
|
||||
#include <QtGui/private/qmemrotate_p.h>
|
||||
|
||||
// The "Q_INIT_RESOURCE()" macro can't be used within a namespace,
|
||||
// so we wrap it into a separate function outside of the namespace and
|
||||
// then call it instead inside the namespace, that's also the recommended
|
||||
// workaround provided by Qt's official documentation.
|
||||
static inline void initResource()
|
||||
{
|
||||
Q_INIT_RESOURCE(framelesshelpercore);
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcMicaMaterial, "wangwenx190.framelesshelper.core.micamaterial")
|
||||
#define INFO qCInfo(lcMicaMaterial)
|
||||
#define DEBUG qCDebug(lcMicaMaterial)
|
||||
#define WARNING qCWarning(lcMicaMaterial)
|
||||
#define CRITICAL qCCritical(lcMicaMaterial)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
static constexpr const qreal kDefaultTintOpacity = 0.7;
|
||||
static constexpr const qreal kDefaultNoiseOpacity = 0.04;
|
||||
static constexpr const qreal kDefaultBlurRadius = 128.0;
|
||||
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(NoiseImageFilePath, ":/org.wangwenx190.FramelessHelper/resources/images/noise.png")
|
||||
|
||||
struct MicaMaterialData
|
||||
{
|
||||
QMutex mutex;
|
||||
QPixmap blurredWallpaper = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(MicaMaterialData, g_micaMaterialData)
|
||||
|
||||
template<const int shift>
|
||||
[[nodiscard]] static inline int qt_static_shift(const int value)
|
||||
{
|
||||
if (shift == 0) {
|
||||
return value;
|
||||
}
|
||||
if (shift > 0) {
|
||||
return (value << (quint32(shift) & 0x1f));
|
||||
}
|
||||
return (value >> (quint32(-shift) & 0x1f));
|
||||
}
|
||||
|
||||
template<const int aprec, const int zprec>
|
||||
static inline void qt_blurinner(uchar *bptr, int &zR, int &zG, int &zB, int &zA, const int alpha)
|
||||
{
|
||||
const auto pixel = reinterpret_cast<QRgb *>(bptr);
|
||||
|
||||
#define Z_MASK (0xff << zprec)
|
||||
const int A_zprec = (qt_static_shift<zprec - 24>(*pixel) & Z_MASK);
|
||||
const int R_zprec = (qt_static_shift<zprec - 16>(*pixel) & Z_MASK);
|
||||
const int G_zprec = (qt_static_shift<zprec - 8>(*pixel) & Z_MASK);
|
||||
const int B_zprec = (qt_static_shift<zprec>(*pixel) & Z_MASK);
|
||||
#undef Z_MASK
|
||||
|
||||
const int zR_zprec = (zR >> aprec);
|
||||
const int zG_zprec = (zG >> aprec);
|
||||
const int zB_zprec = (zB >> aprec);
|
||||
const int zA_zprec = (zA >> aprec);
|
||||
|
||||
zR += (alpha * (R_zprec - zR_zprec));
|
||||
zG += (alpha * (G_zprec - zG_zprec));
|
||||
zB += (alpha * (B_zprec - zB_zprec));
|
||||
zA += (alpha * (A_zprec - zA_zprec));
|
||||
|
||||
#define ZA_MASK (0xff << (zprec + aprec))
|
||||
*pixel = (qt_static_shift<24 - zprec - aprec>(zA & ZA_MASK)
|
||||
| qt_static_shift<16 - zprec - aprec>(zR & ZA_MASK)
|
||||
| qt_static_shift<8 - zprec - aprec>(zG & ZA_MASK)
|
||||
| qt_static_shift<-zprec - aprec>(zB & ZA_MASK));
|
||||
#undef ZA_MASK
|
||||
}
|
||||
|
||||
static constexpr const int alphaIndex = ((QSysInfo::ByteOrder == QSysInfo::BigEndian) ? 0 : 3);
|
||||
|
||||
template<const int aprec, const int zprec>
|
||||
static inline void qt_blurinner_alphaOnly(uchar *bptr, int &z, const int alpha)
|
||||
{
|
||||
const int A_zprec = (int(*(bptr)) << zprec);
|
||||
const int z_zprec = (z >> aprec);
|
||||
z += (alpha * (A_zprec - z_zprec));
|
||||
*(bptr) = (z >> (zprec + aprec));
|
||||
}
|
||||
|
||||
template<const int aprec, const int zprec, const bool alphaOnly>
|
||||
static inline void qt_blurrow(QImage &im, const int line, const int alpha)
|
||||
{
|
||||
uchar *bptr = im.scanLine(line);
|
||||
|
||||
int zR = 0, zG = 0, zB = 0, zA = 0;
|
||||
|
||||
if (alphaOnly && (im.format() != QImage::Format_Indexed8)) {
|
||||
bptr += alphaIndex;
|
||||
}
|
||||
|
||||
const int stride = (im.depth() >> 3);
|
||||
const int im_width = im.width();
|
||||
for (int index = 0; index != im_width; ++index) {
|
||||
if (alphaOnly) {
|
||||
qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
|
||||
} else {
|
||||
qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
|
||||
}
|
||||
bptr += stride;
|
||||
}
|
||||
|
||||
bptr -= stride;
|
||||
|
||||
for (int index = (im_width - 2); index >= 0; --index) {
|
||||
bptr -= stride;
|
||||
if (alphaOnly) {
|
||||
qt_blurinner_alphaOnly<aprec, zprec>(bptr, zA, alpha);
|
||||
} else {
|
||||
qt_blurinner<aprec, zprec>(bptr, zR, zG, zB, zA, alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* expblur(QImage &img, int radius)
|
||||
*
|
||||
* Based on exponential blur algorithm by Jani Huhtanen
|
||||
*
|
||||
* In-place blur of image 'img' with kernel
|
||||
* of approximate radius 'radius'.
|
||||
*
|
||||
* Blurs with two sided exponential impulse
|
||||
* response.
|
||||
*
|
||||
* aprec = precision of alpha parameter
|
||||
* in fixed-point format 0.aprec
|
||||
*
|
||||
* zprec = precision of state parameters
|
||||
* zR,zG,zB and zA in fp format 8.zprec
|
||||
*/
|
||||
template<const int aprec, const int zprec, const bool alphaOnly>
|
||||
static inline void expblur(QImage &img, qreal radius, const bool improvedQuality = false, const int transposed = 0)
|
||||
{
|
||||
Q_ASSERT((img.format() == QImage::Format_ARGB32_Premultiplied)
|
||||
|| (img.format() == QImage::Format_RGB32)
|
||||
|| (img.format() == QImage::Format_Indexed8)
|
||||
|| (img.format() == QImage::Format_Grayscale8));
|
||||
if ((img.format() != QImage::Format_ARGB32_Premultiplied)
|
||||
&& (img.format() != QImage::Format_RGB32)
|
||||
&& (img.format() != QImage::Format_Indexed8)
|
||||
&& (img.format() != QImage::Format_Grayscale8)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// halve the radius if we're using two passes
|
||||
if (improvedQuality) {
|
||||
radius *= 0.5;
|
||||
}
|
||||
|
||||
// choose the alpha such that pixels at radius distance from a fully
|
||||
// saturated pixel will have an alpha component of no greater than
|
||||
// the cutOffIntensity
|
||||
static constexpr const qreal cutOffIntensity = 2.0;
|
||||
const int alpha = ((radius <= qreal(1e-5)) ? ((1 << aprec) - 1) :
|
||||
qRound((1 << aprec) * (1 - qPow(cutOffIntensity / qreal(255), qreal(1) / radius))));
|
||||
|
||||
int img_height = img.height();
|
||||
for (int row = 0; row != img_height; ++row) {
|
||||
for (int i = 0; i <= int(improvedQuality); ++i) {
|
||||
qt_blurrow<aprec, zprec, alphaOnly>(img, row, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
QImage temp(img.height(), img.width(), img.format());
|
||||
temp.setDevicePixelRatio(img.devicePixelRatio());
|
||||
|
||||
if (transposed >= 0) {
|
||||
if (img.depth() == 8) {
|
||||
qt_memrotate270(reinterpret_cast<const quint8 *>(img.bits()),
|
||||
img.width(), img.height(), img.bytesPerLine(),
|
||||
reinterpret_cast<quint8 *>(temp.bits()),
|
||||
temp.bytesPerLine());
|
||||
} else {
|
||||
qt_memrotate270(reinterpret_cast<const quint32 *>(img.bits()),
|
||||
img.width(), img.height(), img.bytesPerLine(),
|
||||
reinterpret_cast<quint32 *>(temp.bits()),
|
||||
temp.bytesPerLine());
|
||||
}
|
||||
} else {
|
||||
if (img.depth() == 8) {
|
||||
qt_memrotate90(reinterpret_cast<const quint8 *>(img.bits()),
|
||||
img.width(), img.height(), img.bytesPerLine(),
|
||||
reinterpret_cast<quint8 *>(temp.bits()),
|
||||
temp.bytesPerLine());
|
||||
} else {
|
||||
qt_memrotate90(reinterpret_cast<const quint32 *>(img.bits()),
|
||||
img.width(), img.height(), img.bytesPerLine(),
|
||||
reinterpret_cast<quint32 *>(temp.bits()),
|
||||
temp.bytesPerLine());
|
||||
}
|
||||
}
|
||||
|
||||
img_height = temp.height();
|
||||
for (int row = 0; row != img_height; ++row) {
|
||||
for (int i = 0; i <= int(improvedQuality); ++i) {
|
||||
qt_blurrow<aprec, zprec, alphaOnly>(temp, row, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
if (transposed == 0) {
|
||||
if (img.depth() == 8) {
|
||||
qt_memrotate90(reinterpret_cast<const quint8 *>(temp.bits()),
|
||||
temp.width(), temp.height(), temp.bytesPerLine(),
|
||||
reinterpret_cast<quint8 *>(img.bits()),
|
||||
img.bytesPerLine());
|
||||
} else {
|
||||
qt_memrotate90(reinterpret_cast<const quint32 *>(temp.bits()),
|
||||
temp.width(), temp.height(), temp.bytesPerLine(),
|
||||
reinterpret_cast<quint32 *>(img.bits()),
|
||||
img.bytesPerLine());
|
||||
}
|
||||
} else {
|
||||
img = temp;
|
||||
}
|
||||
}
|
||||
|
||||
#define AVG(a,b) ( ((((a)^(b)) & 0xfefefefeUL) >> 1) + ((a)&(b)) )
|
||||
#define AVG16(a,b) ( ((((a)^(b)) & 0xf7deUL) >> 1) + ((a)&(b)) )
|
||||
|
||||
[[nodiscard]] static inline QImage qt_halfScaled(const QImage &source)
|
||||
{
|
||||
if ((source.width() < 2) || (source.height() < 2)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
QImage srcImage = source;
|
||||
|
||||
if ((source.format() == QImage::Format_Indexed8)
|
||||
|| (source.format() == QImage::Format_Grayscale8)) {
|
||||
// assumes grayscale
|
||||
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
|
||||
dest.setDevicePixelRatio(source.devicePixelRatio());
|
||||
|
||||
auto src = reinterpret_cast<const uchar *>(const_cast<const QImage &>(srcImage).bits());
|
||||
const qsizetype sx = srcImage.bytesPerLine();
|
||||
const qsizetype sx2 = (sx << 1);
|
||||
|
||||
auto dst = reinterpret_cast<uchar *>(dest.bits());
|
||||
const qsizetype dx = dest.bytesPerLine();
|
||||
const int ww = dest.width();
|
||||
const int hh = dest.height();
|
||||
|
||||
for (int y = hh; y; --y, dst += dx, src += sx2) {
|
||||
const uchar *p1 = src;
|
||||
const uchar *p2 = (src + sx);
|
||||
uchar *q = dst;
|
||||
for (int x = ww; x; --x, ++q, p1 += 2, p2 += 2) {
|
||||
*q = (((int(p1[0]) + int(p1[1]) + int(p2[0]) + int(p2[1])) + 2) >> 2);
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
if (source.format() == QImage::Format_ARGB8565_Premultiplied) {
|
||||
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
|
||||
dest.setDevicePixelRatio(source.devicePixelRatio());
|
||||
|
||||
auto src = reinterpret_cast<const uchar *>(const_cast<const QImage &>(srcImage).bits());
|
||||
const qsizetype sx = srcImage.bytesPerLine();
|
||||
const qsizetype sx2 = (sx << 1);
|
||||
|
||||
auto dst = reinterpret_cast<uchar *>(dest.bits());
|
||||
const qsizetype dx = dest.bytesPerLine();
|
||||
const int ww = dest.width();
|
||||
const int hh = dest.height();
|
||||
|
||||
for (int y = hh; y; --y, dst += dx, src += sx2) {
|
||||
const uchar *p1 = src;
|
||||
const uchar *p2 = (src + sx);
|
||||
uchar *q = dst;
|
||||
for (int x = ww; x; --x, q += 3, p1 += 6, p2 += 6) {
|
||||
// alpha
|
||||
q[0] = AVG(AVG(p1[0], p1[3]), AVG(p2[0], p2[3]));
|
||||
// rgb
|
||||
const quint16 p16_1 = ((p1[2] << 8) | p1[1]);
|
||||
const quint16 p16_2 = ((p1[5] << 8) | p1[4]);
|
||||
const quint16 p16_3 = ((p2[2] << 8) | p2[1]);
|
||||
const quint16 p16_4 = ((p2[5] << 8) | p2[4]);
|
||||
const quint16 result = AVG16(AVG16(p16_1, p16_2), AVG16(p16_3, p16_4));
|
||||
q[1] = (result & 0xff);
|
||||
q[2] = (result >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
if ((source.format() != QImage::Format_ARGB32_Premultiplied)
|
||||
&& (source.format() != QImage::Format_RGB32)) {
|
||||
srcImage = source.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
|
||||
QImage dest(source.width() / 2, source.height() / 2, srcImage.format());
|
||||
dest.setDevicePixelRatio(source.devicePixelRatio());
|
||||
|
||||
auto src = reinterpret_cast<const quint32 *>(const_cast<const QImage &>(srcImage).bits());
|
||||
const qsizetype sx = (srcImage.bytesPerLine() >> 2);
|
||||
const qsizetype sx2 = (sx << 1);
|
||||
|
||||
auto dst = reinterpret_cast<quint32 *>(dest.bits());
|
||||
const qsizetype dx = (dest.bytesPerLine() >> 2);
|
||||
const int ww = dest.width();
|
||||
const int hh = dest.height();
|
||||
|
||||
for (int y = hh; y; --y, dst += dx, src += sx2) {
|
||||
const quint32 *p1 = src;
|
||||
const quint32 *p2 = (src + sx);
|
||||
quint32 *q = dst;
|
||||
for (int x = ww; x; --x, q++, p1 += 2, p2 += 2) {
|
||||
*q = AVG(AVG(p1[0], p1[1]), AVG(p2[0], p2[1]));
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static inline void qt_blurImage(QPainter *p, QImage &blurImage,
|
||||
qreal radius, const bool quality, const bool alphaOnly, const int transposed = 0)
|
||||
{
|
||||
if ((blurImage.format() != QImage::Format_ARGB32_Premultiplied)
|
||||
&& (blurImage.format() != QImage::Format_RGB32)) {
|
||||
blurImage = blurImage.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
|
||||
qreal scale = 1.0;
|
||||
if ((radius >= 4) && (blurImage.width() >= 2) && (blurImage.height() >= 2)) {
|
||||
blurImage = qt_halfScaled(blurImage);
|
||||
scale = 2.0;
|
||||
radius *= 0.5;
|
||||
}
|
||||
|
||||
if (alphaOnly) {
|
||||
expblur<12, 10, true>(blurImage, radius, quality, transposed);
|
||||
} else {
|
||||
expblur<12, 10, false>(blurImage, radius, quality, transposed);
|
||||
}
|
||||
|
||||
if (p) {
|
||||
p->scale(scale, scale);
|
||||
p->setRenderHints(QPainter::Antialiasing |
|
||||
QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 2, 0))
|
||||
const QSize imageSize = blurImage.deviceIndependentSize().toSize();
|
||||
#else
|
||||
const QSize imageSize = QSizeF(QSizeF(blurImage.size()) / blurImage.devicePixelRatio()).toSize();
|
||||
#endif
|
||||
p->drawImage(QRect(QPoint(0, 0), imageSize), blurImage);
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] static inline void qt_blurImage(QImage &blurImage,
|
||||
const qreal radius, const bool quality, const int transposed = 0)
|
||||
{
|
||||
if ((blurImage.format() == QImage::Format_Indexed8)
|
||||
|| (blurImage.format() == QImage::Format_Grayscale8)) {
|
||||
expblur<12, 10, true>(blurImage, radius, quality, transposed);
|
||||
} else {
|
||||
expblur<12, 10, false>(blurImage, radius, quality, transposed);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Transforms an \a alignment of Qt::AlignLeft or Qt::AlignRight
|
||||
without Qt::AlignAbsolute into Qt::AlignLeft or Qt::AlignRight with
|
||||
Qt::AlignAbsolute according to the layout \a direction. The other
|
||||
alignment flags are left untouched.
|
||||
|
||||
If no horizontal alignment was specified, the function returns the
|
||||
default alignment for the given layout \a direction.
|
||||
|
||||
\sa QWidget::layoutDirection
|
||||
*/
|
||||
[[nodiscard]] static inline Qt::Alignment visualAlignment
|
||||
(const Qt::LayoutDirection direction, const Qt::Alignment alignment)
|
||||
{
|
||||
return QGuiApplicationPrivate::visualAlignment(direction, alignment);
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns a new rectangle of the specified \a size that is aligned to the given
|
||||
\a rectangle according to the specified \a alignment and \a direction.
|
||||
*/
|
||||
[[nodiscard]] static inline QRect alignedRect(const Qt::LayoutDirection direction,
|
||||
Qt::Alignment alignment, const QSize &size, const QRect &rectangle)
|
||||
{
|
||||
alignment = visualAlignment(direction, alignment);
|
||||
int x = rectangle.x();
|
||||
int y = rectangle.y();
|
||||
int w = size.width();
|
||||
int h = size.height();
|
||||
if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter) {
|
||||
y += ((rectangle.size().height() / 2) - (h / 2));
|
||||
} else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom) {
|
||||
y += (rectangle.size().height() - h);
|
||||
}
|
||||
if ((alignment & Qt::AlignRight) == Qt::AlignRight) {
|
||||
x += (rectangle.size().width() - w);
|
||||
} else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter) {
|
||||
x += ((rectangle.size().width() / 2) - (w / 2));
|
||||
}
|
||||
return {x, y, w, h};
|
||||
}
|
||||
|
||||
MicaMaterialPrivate::MicaMaterialPrivate(MicaMaterial *q) : QObject(q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
if (!q) {
|
||||
return;
|
||||
}
|
||||
q_ptr = q;
|
||||
initialize();
|
||||
}
|
||||
|
||||
MicaMaterialPrivate::~MicaMaterialPrivate() = default;
|
||||
|
||||
MicaMaterialPrivate *MicaMaterialPrivate::get(MicaMaterial *q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
if (!q) {
|
||||
return nullptr;
|
||||
}
|
||||
return q->d_func();
|
||||
}
|
||||
|
||||
const MicaMaterialPrivate *MicaMaterialPrivate::get(const MicaMaterial *q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
if (!q) {
|
||||
return nullptr;
|
||||
}
|
||||
return q->d_func();
|
||||
}
|
||||
|
||||
void MicaMaterialPrivate::maybeGenerateBlurredWallpaper(const bool force)
|
||||
{
|
||||
g_micaMaterialData()->mutex.lock();
|
||||
if (!g_micaMaterialData()->blurredWallpaper.isNull() && !force) {
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
return;
|
||||
}
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
const QSize size = QGuiApplication::primaryScreen()->virtualSize();
|
||||
g_micaMaterialData()->mutex.lock();
|
||||
g_micaMaterialData()->blurredWallpaper = QPixmap(size);
|
||||
g_micaMaterialData()->blurredWallpaper.fill(kDefaultTransparentColor);
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
const QString wallpaperFilePath = Utils::getWallpaperFilePath();
|
||||
if (wallpaperFilePath.isEmpty()) {
|
||||
WARNING << "Failed to retrieve the wallpaper file path.";
|
||||
return;
|
||||
}
|
||||
QImage image(wallpaperFilePath);
|
||||
if (image.isNull()) {
|
||||
WARNING << "QImage doesn't support this kind of file:" << wallpaperFilePath;
|
||||
return;
|
||||
}
|
||||
WallpaperAspectStyle aspectStyle = Utils::getWallpaperAspectStyle();
|
||||
QImage buffer(size, QImage::Format_ARGB32_Premultiplied);
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (aspectStyle == WallpaperAspectStyle::Center) {
|
||||
buffer.fill(kDefaultBlackColor);
|
||||
}
|
||||
#endif
|
||||
if ((aspectStyle == WallpaperAspectStyle::Stretch)
|
||||
|| (aspectStyle == WallpaperAspectStyle::Fit)
|
||||
|| (aspectStyle == WallpaperAspectStyle::Fill)) {
|
||||
Qt::AspectRatioMode mode = Qt::KeepAspectRatioByExpanding;
|
||||
if (aspectStyle == WallpaperAspectStyle::Stretch) {
|
||||
mode = Qt::IgnoreAspectRatio;
|
||||
} else if (aspectStyle == WallpaperAspectStyle::Fit) {
|
||||
mode = Qt::KeepAspectRatio;
|
||||
}
|
||||
QSize newSize = image.size();
|
||||
newSize.scale(size, mode);
|
||||
image = image.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
static constexpr const QPoint desktopOriginPoint = {0, 0};
|
||||
const QRect desktopRect = {desktopOriginPoint, size};
|
||||
if (aspectStyle == WallpaperAspectStyle::Tile) {
|
||||
QPainter bufferPainter(&buffer);
|
||||
const QBrush brush(image);
|
||||
bufferPainter.fillRect(desktopRect, brush);
|
||||
} else {
|
||||
QPainter bufferPainter(&buffer);
|
||||
const QRect rect = alignedRect(Qt::LeftToRight, Qt::AlignCenter, image.size(), desktopRect);
|
||||
bufferPainter.drawImage(rect.topLeft(), image);
|
||||
}
|
||||
g_micaMaterialData()->mutex.lock();
|
||||
QPainter painter(&g_micaMaterialData()->blurredWallpaper);
|
||||
#if 1
|
||||
qt_blurImage(&painter, buffer, kDefaultBlurRadius, true, false);
|
||||
#else
|
||||
painter.drawImage(desktopOriginPoint, buffer);
|
||||
#endif
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
Q_Q(MicaMaterial);
|
||||
Q_EMIT q->shouldRedraw();
|
||||
}
|
||||
|
||||
void MicaMaterialPrivate::updateMaterialBrush()
|
||||
{
|
||||
initResource();
|
||||
static const QImage noiseTexture = QImage(kNoiseImageFilePath);
|
||||
QImage micaTexture = QImage(QSize(64, 64), QImage::Format_ARGB32_Premultiplied);
|
||||
QColor fillColor = (Utils::shouldAppsUseDarkMode() ? kDefaultSystemDarkColor : kDefaultSystemLightColor);
|
||||
fillColor.setAlphaF(0.9f);
|
||||
micaTexture.fill(fillColor);
|
||||
QPainter painter(&micaTexture);
|
||||
painter.setOpacity(tintOpacity);
|
||||
const QRect rect = {QPoint(0, 0), micaTexture.size()};
|
||||
painter.fillRect(rect, tintColor);
|
||||
painter.setOpacity(noiseOpacity);
|
||||
painter.fillRect(rect, QBrush(noiseTexture));
|
||||
micaBrush = QBrush(micaTexture);
|
||||
Q_Q(MicaMaterial);
|
||||
Q_EMIT q->shouldRedraw();
|
||||
}
|
||||
|
||||
void MicaMaterialPrivate::paint(QPainter *painter, const QSize &size, const QPoint &pos) const
|
||||
{
|
||||
Q_ASSERT(painter);
|
||||
if (!painter) {
|
||||
return;
|
||||
}
|
||||
static constexpr const QPoint originPoint = {0, 0};
|
||||
painter->save();
|
||||
g_micaMaterialData()->mutex.lock();
|
||||
painter->drawPixmap(originPoint, g_micaMaterialData()->blurredWallpaper, QRect(pos, size));
|
||||
g_micaMaterialData()->mutex.unlock();
|
||||
painter->setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||
painter->setOpacity(1.0);
|
||||
painter->fillRect(QRect(originPoint, size), micaBrush);
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
MicaMaterial *MicaMaterialPrivate::attach(QObject *target)
|
||||
{
|
||||
Q_ASSERT(target);
|
||||
if (!target) {
|
||||
return nullptr;
|
||||
}
|
||||
if (const auto instance = target->findChild<MicaMaterial *>()) {
|
||||
return instance;
|
||||
}
|
||||
const auto instance = new MicaMaterial(target);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void MicaMaterialPrivate::initialize()
|
||||
{
|
||||
tintColor = kDefaultTransparentColor;
|
||||
tintOpacity = kDefaultTintOpacity;
|
||||
noiseOpacity = kDefaultNoiseOpacity;
|
||||
|
||||
connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged,
|
||||
this, &MicaMaterialPrivate::updateMaterialBrush);
|
||||
connect(FramelessManager::instance(), &FramelessManager::wallpaperChanged,
|
||||
this, [this](){
|
||||
maybeGenerateBlurredWallpaper(true);
|
||||
});
|
||||
|
||||
maybeGenerateBlurredWallpaper();
|
||||
updateMaterialBrush();
|
||||
}
|
||||
|
||||
MicaMaterial::MicaMaterial(QObject *parent)
|
||||
: QObject(parent), d_ptr(new MicaMaterialPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
MicaMaterial::~MicaMaterial() = default;
|
||||
|
||||
QColor MicaMaterial::tintColor() const
|
||||
{
|
||||
Q_D(const MicaMaterial);
|
||||
return d->tintColor;
|
||||
}
|
||||
|
||||
void MicaMaterial::setTintColor(const QColor &value)
|
||||
{
|
||||
Q_ASSERT(value.isValid());
|
||||
if (!value.isValid()) {
|
||||
return;
|
||||
}
|
||||
Q_D(MicaMaterial);
|
||||
if (d->tintColor == value) {
|
||||
return;
|
||||
}
|
||||
d->tintColor = value;
|
||||
d->updateMaterialBrush();
|
||||
Q_EMIT tintColorChanged();
|
||||
}
|
||||
|
||||
qreal MicaMaterial::tintOpacity() const
|
||||
{
|
||||
Q_D(const MicaMaterial);
|
||||
return d->tintOpacity;
|
||||
}
|
||||
|
||||
void MicaMaterial::setTintOpacity(const qreal value)
|
||||
{
|
||||
Q_D(MicaMaterial);
|
||||
if (qFuzzyCompare(d->tintOpacity, value)) {
|
||||
return;
|
||||
}
|
||||
d->tintOpacity = value;
|
||||
d->updateMaterialBrush();
|
||||
Q_EMIT tintOpacityChanged();
|
||||
}
|
||||
|
||||
qreal MicaMaterial::noiseOpacity() const
|
||||
{
|
||||
Q_D(const MicaMaterial);
|
||||
return d->noiseOpacity;
|
||||
}
|
||||
|
||||
void MicaMaterial::setNoiseOpacity(const qreal value)
|
||||
{
|
||||
Q_D(MicaMaterial);
|
||||
if (qFuzzyCompare(d->noiseOpacity, value)) {
|
||||
return;
|
||||
}
|
||||
d->noiseOpacity = value;
|
||||
d->updateMaterialBrush();
|
||||
Q_EMIT noiseOpacityChanged();
|
||||
}
|
||||
|
||||
void MicaMaterial::paint(QPainter *painter, const QSize &size, const QPoint &pos) const
|
||||
{
|
||||
Q_D(const MicaMaterial);
|
||||
d->paint(painter, size, pos);
|
||||
}
|
||||
|
||||
MicaMaterial *MicaMaterial::attach(QObject *target)
|
||||
{
|
||||
return MicaMaterialPrivate::attach(target);
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
|
@ -0,0 +1 @@
|
|||
#include "../../include/FramelessHelper/Core/micamaterial.h"
|
|
@ -0,0 +1 @@
|
|||
#include "../../include/FramelessHelper/Core/private/micamaterial_p.h"
|
After Width: | Height: | Size: 266 KiB |
|
@ -32,6 +32,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcSysApiLoader, "wangwenx190.framelesshelper.core.sysapiloader")
|
||||
#define INFO qCInfo(lcSysApiLoader)
|
||||
#define DEBUG qCDebug(lcSysApiLoader)
|
||||
#define WARNING qCWarning(lcSysApiLoader)
|
||||
#define CRITICAL qCCritical(lcSysApiLoader)
|
||||
|
||||
Q_GLOBAL_STATIC(SysApiLoader, g_sysApiLoader)
|
||||
|
||||
SysApiLoader::SysApiLoader(QObject *parent) : QObject(parent)
|
||||
|
@ -83,11 +89,11 @@ bool SysApiLoader::isAvailable(const QString &library, const QString &function)
|
|||
const QFunctionPointer symbol = SysApiLoader::resolve(library, function);
|
||||
if (symbol) {
|
||||
m_functionCache.insert(function, symbol);
|
||||
qDebug() << "Successfully loaded" << function << "from" << library;
|
||||
DEBUG << "Successfully loaded" << function << "from" << library;
|
||||
return true;
|
||||
}
|
||||
m_functionCache.insert(function, std::nullopt);
|
||||
qWarning() << "Failed to load" << function << "from" << library;
|
||||
WARNING << "Failed to load" << function << "from" << library;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcUtilsCommon, "wangwenx190.framelesshelper.core.utils.common")
|
||||
#define INFO qCInfo(lcUtilsCommon)
|
||||
#define DEBUG qCDebug(lcUtilsCommon)
|
||||
#define WARNING qCWarning(lcUtilsCommon)
|
||||
#define CRITICAL qCCritical(lcUtilsCommon)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
struct FONT_ICON
|
||||
|
@ -125,7 +131,7 @@ QString Utils::getSystemButtonIconCode(const SystemButtonType button)
|
|||
{
|
||||
const auto index = static_cast<int>(button);
|
||||
if (!g_fontIconsTable.contains(index)) {
|
||||
qWarning() << "FIXME: Add FONT_ICON value for button" << button;
|
||||
WARNING << "FIXME: Add FONT_ICON value for button" << button;
|
||||
return {};
|
||||
}
|
||||
const FONT_ICON icon = g_fontIconsTable.value(index);
|
||||
|
@ -211,6 +217,10 @@ bool Utils::isThemeChangeEvent(const QEvent * const event)
|
|||
if (!event) {
|
||||
return false;
|
||||
}
|
||||
// QGuiApplication will only deliver theme change events to top level QWindow(QQuickWindow)s,
|
||||
// QWidgets won't get such notifications, no matter whether it's top level widget or not.
|
||||
// QEvent::ThemeChange: Send by the Windows QPA.
|
||||
// QEvent::ApplicationPaletteChange: All other platforms (Linux & macOS).
|
||||
const QEvent::Type type = event->type();
|
||||
return ((type == QEvent::ThemeChange) || (type == QEvent::ApplicationPaletteChange));
|
||||
}
|
||||
|
@ -229,7 +239,7 @@ QColor Utils::calculateSystemButtonBackgroundColor(const SystemButtonType button
|
|||
}
|
||||
if (isTitleColor) {
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return getDwmColorizationColor();
|
||||
return getDwmAccentColor();
|
||||
#endif
|
||||
#ifdef Q_OS_LINUX
|
||||
return getWmThemeColor();
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "framelessconfig_p.h"
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qregularexpression.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
|
@ -41,6 +42,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcUtilsLinux, "wangwenx190.framelesshelper.core.utils.linux")
|
||||
#define INFO qCInfo(lcUtilsLinux)
|
||||
#define DEBUG qCDebug(lcUtilsLinux)
|
||||
#define WARNING qCWarning(lcUtilsLinux)
|
||||
#define CRITICAL qCCritical(lcUtilsLinux)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
using Display = struct _XDisplay;
|
||||
|
@ -478,4 +485,36 @@ bool Utils::shouldAppsUseDarkMode_linux()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode, const QColor &color)
|
||||
{
|
||||
Q_UNUSED(windowId);
|
||||
Q_UNUSED(mode);
|
||||
Q_UNUSED(color);
|
||||
return false;
|
||||
}
|
||||
|
||||
QString Utils::getWallpaperFilePath()
|
||||
{
|
||||
// ### TODO
|
||||
return {};
|
||||
}
|
||||
|
||||
WallpaperAspectStyle Utils::getWallpaperAspectStyle()
|
||||
{
|
||||
// ### TODO
|
||||
return WallpaperAspectStyle::Fill;
|
||||
}
|
||||
|
||||
bool Utils::isBlurBehindWindowSupported()
|
||||
{
|
||||
static const bool result = []() -> bool {
|
||||
if (FramelessConfig::instance()->isSet(Option::ForceNonNativeBackgroundBlur)) {
|
||||
return false;
|
||||
}
|
||||
// Currently not supported due to the desktop environments vary too much.
|
||||
return false;
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -24,10 +24,16 @@
|
|||
|
||||
#include "utils.h"
|
||||
#include "framelessmanager.h"
|
||||
#include "framelessconfig_p.h"
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
# include <QtCore/qoperatingsystemversion.h>
|
||||
#else
|
||||
# include <QtCore/qsysinfo.h>
|
||||
#endif
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <objc/runtime.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
|
@ -38,6 +44,12 @@ QT_END_NAMESPACE
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcUtilsMac, "wangwenx190.framelesshelper.core.utils.mac")
|
||||
#define INFO qCInfo(lcUtilsMac)
|
||||
#define DEBUG qCDebug(lcUtilsMac)
|
||||
#define WARNING qCWarning(lcUtilsMac)
|
||||
#define CRITICAL qCCritical(lcUtilsMac)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
class NSWindowProxy : public QObject
|
||||
|
@ -508,7 +520,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
if ((mode == BlurMode::Disable) || (mode == BlurMode::Default)) {
|
||||
return mode;
|
||||
}
|
||||
qWarning() << "The BlurMode::Windows_* enum values are not supported on macOS.";
|
||||
WARNING << "The BlurMode::Windows_* enum values are not supported on macOS.";
|
||||
return BlurMode::Default;
|
||||
}();
|
||||
NSWindowProxy * const proxy = ensureWindowProxy(windowId);
|
||||
|
@ -516,6 +528,56 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
return true;
|
||||
}
|
||||
|
||||
QString Utils::getWallpaperFilePath()
|
||||
{
|
||||
#if 0
|
||||
const NSWorkspace * const sharedWorkspace = [NSWorkspace sharedWorkspace];
|
||||
if (!sharedWorkspace) {
|
||||
WARNING << "Failed to retrieve the shared workspace.";
|
||||
return {};
|
||||
}
|
||||
NSScreen * const mainScreen = [NSScreen mainScreen];
|
||||
if (!mainScreen) {
|
||||
WARNING << "Failed to retrieve the main screen.";
|
||||
return {};
|
||||
}
|
||||
const NSURL * const url = [sharedWorkspace desktopImageURLForScreen:mainScreen];
|
||||
if (!url) {
|
||||
WARNING << "Failed to retrieve the desktop image URL.";
|
||||
return {};
|
||||
}
|
||||
const QUrl path = QUrl::fromNSURL(url);
|
||||
if (!path.isValid()) {
|
||||
WARNING << "The converted QUrl is not valid.";
|
||||
return {};
|
||||
}
|
||||
return path.toLocalFile();
|
||||
#else
|
||||
// ### TODO
|
||||
return {};
|
||||
#endif
|
||||
}
|
||||
|
||||
WallpaperAspectStyle Utils::getWallpaperAspectStyle()
|
||||
{
|
||||
return WallpaperAspectStyle::Stretch;
|
||||
}
|
||||
|
||||
bool Utils::isBlurBehindWindowSupported()
|
||||
{
|
||||
static const bool result = []() -> bool {
|
||||
if (FramelessConfig::instance()->isSet(Option::ForceNonNativeBackgroundBlur)) {
|
||||
return false;
|
||||
}
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 9, 0))
|
||||
return (QOperatingSystemVersion::current() >= QOperatingSystemVersion::OSXYosemite);
|
||||
#else
|
||||
return (QSysInfo::macVersion() >= QSysInfo::MV_YOSEMITE);
|
||||
#endif
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
#include "utils_mac.moc"
|
||||
|
|
|
@ -44,29 +44,19 @@ Q_DECLARE_METATYPE(QMargins)
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcUtilsWin, "wangwenx190.framelesshelper.core.utils.win")
|
||||
#define INFO qCInfo(lcUtilsWin)
|
||||
#define DEBUG qCDebug(lcUtilsWin)
|
||||
#define WARNING qCWarning(lcUtilsWin)
|
||||
#define CRITICAL qCCritical(lcUtilsWin)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
struct Win32UtilsHelperData
|
||||
{
|
||||
WNDPROC originalWindowProc = nullptr;
|
||||
IsWindowFixedSizeCallback isWindowFixedSize = nullptr;
|
||||
IsInsideTitleBarDraggableAreaCallback isInTitleBarArea = nullptr;
|
||||
GetWindowDevicePixelRatioCallback getDevicePixelRatio = nullptr;
|
||||
};
|
||||
|
||||
struct Win32UtilsHelper
|
||||
{
|
||||
QMutex mutex;
|
||||
QHash<WId, Win32UtilsHelperData> data = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(Win32UtilsHelper, g_utilsHelper)
|
||||
|
||||
static constexpr const wchar_t kDummyWindowClassName[] = L"FRAMELESSHELPER_DUMMY_WINDOW_CLASS";
|
||||
static const QString qDwmColorKeyName = QString::fromWCharArray(kDwmColorKeyName);
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(SuccessMessageText, "The operation completed successfully.")
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(FormatMessageEmptyResult, "\"FormatMessageW()\" returned empty string.")
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(ErrorMessageTemplate, "Function \"%1()\" failed with error code %2: %3.")
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(EmptyMessageText, "FormatMessageW() returned empty string.")
|
||||
FRAMELESSHELPER_STRING_CONSTANT2(ErrorMessageTemplate, "Function %1() failed with error code %2: %3.")
|
||||
FRAMELESSHELPER_STRING_CONSTANT(Composition)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(ColorizationColor)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(AppsUseLightTheme)
|
||||
|
@ -140,6 +130,24 @@ FRAMELESSHELPER_STRING_CONSTANT(RegisterClassExW)
|
|||
FRAMELESSHELPER_STRING_CONSTANT(CreateWindowExW)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(AccentColor)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(GetScaleFactorForMonitor)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(WallpaperStyle)
|
||||
FRAMELESSHELPER_STRING_CONSTANT(TileWallpaper)
|
||||
|
||||
struct Win32UtilsHelperData
|
||||
{
|
||||
WNDPROC originalWindowProc = nullptr;
|
||||
IsWindowFixedSizeCallback isWindowFixedSize = nullptr;
|
||||
IsInsideTitleBarDraggableAreaCallback isInTitleBarArea = nullptr;
|
||||
GetWindowDevicePixelRatioCallback getDevicePixelRatio = nullptr;
|
||||
};
|
||||
|
||||
struct Win32UtilsHelper
|
||||
{
|
||||
QMutex mutex;
|
||||
QHash<WId, Win32UtilsHelperData> data = {};
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(Win32UtilsHelper, g_utilsHelper)
|
||||
|
||||
struct SYSTEM_METRIC
|
||||
{
|
||||
|
@ -241,12 +249,18 @@ private:
|
|||
return key;
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline QString desktopRegistryKey()
|
||||
{
|
||||
static const QString key = (hkcuRegistryKey() + u'\\' + QString::fromWCharArray(kDesktopRegistryKey));
|
||||
return key;
|
||||
}
|
||||
|
||||
[[nodiscard]] static inline HWND ensureDummyWindow()
|
||||
{
|
||||
static const HWND hwnd = []() -> HWND {
|
||||
const HMODULE instance = GetModuleHandleW(nullptr);
|
||||
if (!instance) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kGetModuleHandleW);
|
||||
WARNING << Utils::getSystemErrorMessage(kGetModuleHandleW);
|
||||
return nullptr;
|
||||
}
|
||||
WNDCLASSEXW wcex;
|
||||
|
@ -257,13 +271,13 @@ private:
|
|||
wcex.lpszClassName = kDummyWindowClassName;
|
||||
const ATOM atom = RegisterClassExW(&wcex);
|
||||
if (!atom) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kRegisterClassExW);
|
||||
WARNING << Utils::getSystemErrorMessage(kRegisterClassExW);
|
||||
return nullptr;
|
||||
}
|
||||
const HWND window = CreateWindowExW(0, kDummyWindowClassName, nullptr,
|
||||
WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, nullptr, nullptr, instance, nullptr);
|
||||
if (!window) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kCreateWindowExW);
|
||||
WARNING << Utils::getSystemErrorMessage(kCreateWindowExW);
|
||||
return nullptr;
|
||||
}
|
||||
return window;
|
||||
|
@ -325,7 +339,7 @@ private:
|
|||
LPWSTR buf = nullptr;
|
||||
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
nullptr, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&buf), 0, nullptr) == 0) {
|
||||
return kFormatMessageEmptyResult;
|
||||
return kEmptyMessageText;
|
||||
}
|
||||
const QString errorText = QString::fromWCharArray(buf).trimmed();
|
||||
LocalFree(buf);
|
||||
|
@ -366,7 +380,7 @@ private:
|
|||
return 0;
|
||||
}
|
||||
if (!g_systemMetricsTable.contains(index)) {
|
||||
qWarning() << "FIXME: Add SYSTEM_METRIC value for index" << index;
|
||||
WARNING << "FIXME: Add SYSTEM_METRIC value for index" << index;
|
||||
return 0;
|
||||
}
|
||||
const SYSTEM_METRIC systemMetric = g_systemMetricsTable.value(index);
|
||||
|
@ -393,7 +407,7 @@ private:
|
|||
DPI_CASE(432)
|
||||
DPI_CASE(480)
|
||||
default:
|
||||
qWarning() << "Unsupported DPI value:" << dpi;
|
||||
WARNING << "Unsupported DPI value:" << dpi;
|
||||
return 0;
|
||||
}
|
||||
#undef DPI_CASE
|
||||
|
@ -447,7 +461,7 @@ private:
|
|||
const auto getNativeGlobalPosFromKeyboard = [hWnd, windowId]() -> QPoint {
|
||||
RECT windowPos = {};
|
||||
if (GetWindowRect(hWnd, &windowPos) == FALSE) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kGetWindowRect);
|
||||
WARNING << Utils::getSystemErrorMessage(kGetWindowRect);
|
||||
return {};
|
||||
}
|
||||
const bool maxOrFull = (IsMaximized(hWnd) || Utils::isFullScreen(windowId));
|
||||
|
@ -485,7 +499,7 @@ private:
|
|||
if (data.isInTitleBarArea(qtScenePos)) {
|
||||
POINT pos = {nativeLocalPos.x(), nativeLocalPos.y()};
|
||||
if (ClientToScreen(hWnd, &pos) == FALSE) {
|
||||
qWarning() << Utils::getSystemErrorMessage(kClientToScreen);
|
||||
WARNING << Utils::getSystemErrorMessage(kClientToScreen);
|
||||
break;
|
||||
}
|
||||
shouldShowSystemMenu = true;
|
||||
|
@ -561,7 +575,7 @@ bool Utils::isDwmCompositionEnabled()
|
|||
BOOL enabled = FALSE;
|
||||
const HRESULT hr = API_CALL_FUNCTION(DwmIsCompositionEnabled, &enabled);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(kDwmIsCompositionEnabled, hr);
|
||||
WARNING << __getSystemErrorMessage(kDwmIsCompositionEnabled, hr);
|
||||
return resultFromRegistry();
|
||||
}
|
||||
return (enabled != FALSE);
|
||||
|
@ -576,7 +590,7 @@ void Utils::triggerFrameChange(const WId windowId)
|
|||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
static constexpr const UINT flags = (SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOOWNERZORDER);
|
||||
if (SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, flags) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kSetWindowPos);
|
||||
WARNING << getSystemErrorMessage(kSetWindowPos);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -604,7 +618,7 @@ void Utils::updateWindowFrameMargins(const WId windowId, const bool reset)
|
|||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
const HRESULT hr = API_CALL_FUNCTION(DwmExtendFrameIntoClientArea, hwnd, &margins);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(kDwmExtendFrameIntoClientArea, hr);
|
||||
WARNING << __getSystemErrorMessage(kDwmExtendFrameIntoClientArea, hr);
|
||||
return;
|
||||
}
|
||||
triggerFrameChange(windowId);
|
||||
|
@ -636,14 +650,14 @@ void Utils::updateInternalWindowFrameMargins(QWindow *window, const bool enable)
|
|||
if (QPlatformWindow *platformWindow = window->handle()) {
|
||||
QGuiApplication::platformNativeInterface()->setWindowProperty(platformWindow, kWindowsCustomMargins, marginsVar);
|
||||
} else {
|
||||
qWarning() << "Failed to retrieve the platform window.";
|
||||
WARNING << "Failed to retrieve the platform window.";
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (const auto platformWindow = dynamic_cast<QNativeInterface::Private::QWindowsWindow *>(window->handle())) {
|
||||
platformWindow->setCustomMargins(margins);
|
||||
} else {
|
||||
qWarning() << "Failed to retrieve the platform window.";
|
||||
WARNING << "Failed to retrieve the platform window.";
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
@ -678,7 +692,7 @@ QColor Utils::getDwmColorizationColor()
|
|||
BOOL opaque = FALSE;
|
||||
const HRESULT hr = API_CALL_FUNCTION(DwmGetColorizationColor, &color, &opaque);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(kDwmGetColorizationColor, hr);
|
||||
WARNING << __getSystemErrorMessage(kDwmGetColorizationColor, hr);
|
||||
return resultFromRegistry();
|
||||
}
|
||||
return QColor::fromRgba(color);
|
||||
|
@ -762,7 +776,7 @@ void Utils::showSystemMenu(const WId windowId, const QPoint &pos, const bool sel
|
|||
|
||||
// Send the command that the user choses to the corresponding window.
|
||||
if (PostMessageW(hWnd, WM_SYSCOMMAND, result, 0) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kPostMessageW);
|
||||
WARNING << getSystemErrorMessage(kPostMessageW);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -775,21 +789,21 @@ bool Utils::isFullScreen(const WId windowId)
|
|||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
RECT wndRect = {};
|
||||
if (GetWindowRect(hwnd, &wndRect) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kGetWindowRect);
|
||||
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) {
|
||||
qWarning() << getSystemErrorMessage(kMonitorFromWindow);
|
||||
WARNING << getSystemErrorMessage(kMonitorFromWindow);
|
||||
return false;
|
||||
}
|
||||
MONITORINFO mi;
|
||||
SecureZeroMemory(&mi, sizeof(mi));
|
||||
mi.cbSize = sizeof(mi);
|
||||
if (GetMonitorInfoW(mon, &mi) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kGetMonitorInfoW);
|
||||
WARNING << getSystemErrorMessage(kGetMonitorInfoW);
|
||||
return false;
|
||||
}
|
||||
// Compare to the full area of the screen, not the work area.
|
||||
|
@ -809,7 +823,7 @@ bool Utils::isWindowNoState(const WId windowId)
|
|||
SecureZeroMemory(&wp, sizeof(wp));
|
||||
wp.length = sizeof(wp); // This line is important! Don't miss it!
|
||||
if (GetWindowPlacement(hwnd, &wp) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kGetWindowPlacement);
|
||||
WARNING << getSystemErrorMessage(kGetWindowPlacement);
|
||||
return false;
|
||||
}
|
||||
return ((wp.showCmd == SW_NORMAL) || (wp.showCmd == SW_RESTORE));
|
||||
|
@ -836,22 +850,22 @@ void Utils::syncWmPaintWithDwm()
|
|||
// Dirty hack to workaround the resize flicker caused by DWM.
|
||||
LARGE_INTEGER freq = {};
|
||||
if (QueryPerformanceFrequency(&freq) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kQueryPerformanceFrequency);
|
||||
WARNING << getSystemErrorMessage(kQueryPerformanceFrequency);
|
||||
return;
|
||||
}
|
||||
TIMECAPS tc = {};
|
||||
if (API_CALL_FUNCTION(timeGetDevCaps, &tc, sizeof(tc)) != MMSYSERR_NOERROR) {
|
||||
qWarning() << "timeGetDevCaps() failed.";
|
||||
WARNING << "timeGetDevCaps() failed.";
|
||||
return;
|
||||
}
|
||||
const UINT ms_granularity = tc.wPeriodMin;
|
||||
if (API_CALL_FUNCTION(timeBeginPeriod, ms_granularity) != TIMERR_NOERROR) {
|
||||
qWarning() << "timeBeginPeriod() failed.";
|
||||
WARNING << "timeBeginPeriod() failed.";
|
||||
return;
|
||||
}
|
||||
LARGE_INTEGER now0 = {};
|
||||
if (QueryPerformanceCounter(&now0) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kQueryPerformanceCounter);
|
||||
WARNING << getSystemErrorMessage(kQueryPerformanceCounter);
|
||||
return;
|
||||
}
|
||||
// ask DWM where the vertical blank falls
|
||||
|
@ -860,12 +874,12 @@ void Utils::syncWmPaintWithDwm()
|
|||
dti.cbSize = sizeof(dti);
|
||||
const HRESULT hr = API_CALL_FUNCTION(DwmGetCompositionTimingInfo, nullptr, &dti);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << getSystemErrorMessage(kDwmGetCompositionTimingInfo);
|
||||
WARNING << getSystemErrorMessage(kDwmGetCompositionTimingInfo);
|
||||
return;
|
||||
}
|
||||
LARGE_INTEGER now1 = {};
|
||||
if (QueryPerformanceCounter(&now1) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kQueryPerformanceCounter);
|
||||
WARNING << getSystemErrorMessage(kQueryPerformanceCounter);
|
||||
return;
|
||||
}
|
||||
// - DWM told us about SOME vertical blank
|
||||
|
@ -887,7 +901,7 @@ void Utils::syncWmPaintWithDwm()
|
|||
const qreal m_ms = (1000.0 * qreal(m) / qreal(freq.QuadPart));
|
||||
Sleep(static_cast<DWORD>(qRound(m_ms)));
|
||||
if (API_CALL_FUNCTION(timeEndPeriod, ms_granularity) != TIMERR_NOERROR) {
|
||||
qWarning() << "timeEndPeriod() failed.";
|
||||
WARNING << "timeEndPeriod() failed.";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -897,7 +911,7 @@ bool Utils::isHighContrastModeEnabled()
|
|||
SecureZeroMemory(&hc, sizeof(hc));
|
||||
hc.cbSize = sizeof(hc);
|
||||
if (SystemParametersInfoW(SPI_GETHIGHCONTRAST, sizeof(hc), &hc, 0) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kSystemParametersInfoW);
|
||||
WARNING << getSystemErrorMessage(kSystemParametersInfoW);
|
||||
return false;
|
||||
}
|
||||
return (hc.dwFlags & HCF_HIGHCONTRASTON);
|
||||
|
@ -921,10 +935,10 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal)
|
|||
if (SUCCEEDED(hr) && (dpiX > 0) && (dpiY > 0)) {
|
||||
return (horizontal ? dpiX : dpiY);
|
||||
} else {
|
||||
qWarning() << __getSystemErrorMessage(kGetDpiForMonitor, hr);
|
||||
WARNING << __getSystemErrorMessage(kGetDpiForMonitor, hr);
|
||||
}
|
||||
} else {
|
||||
qWarning() << getSystemErrorMessage(kMonitorFromPoint);
|
||||
WARNING << getSystemErrorMessage(kMonitorFromPoint);
|
||||
}
|
||||
}
|
||||
if (API_SHCORE_AVAILABLE(GetScaleFactorForMonitor)) {
|
||||
|
@ -935,10 +949,10 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal)
|
|||
if (SUCCEEDED(hr) && (factor != DEVICE_SCALE_FACTOR_INVALID)) {
|
||||
return quint32(qRound(qreal(USER_DEFAULT_SCREEN_DPI) * qreal(factor) / qreal(100)));
|
||||
} else {
|
||||
qWarning() << __getSystemErrorMessage(kGetScaleFactorForMonitor, hr);
|
||||
WARNING << __getSystemErrorMessage(kGetScaleFactorForMonitor, hr);
|
||||
}
|
||||
} else {
|
||||
qWarning() << getSystemErrorMessage(kMonitorFromPoint);
|
||||
WARNING << getSystemErrorMessage(kMonitorFromPoint);
|
||||
}
|
||||
}
|
||||
if (API_D2D_AVAILABLE(D2D1CreateFactory)) {
|
||||
|
@ -960,13 +974,13 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal)
|
|||
if ((dpiX > 0.0f) && (dpiY > 0.0f)) {
|
||||
return (horizontal ? quint32(qRound(dpiX)) : quint32(qRound(dpiY)));
|
||||
} else {
|
||||
qWarning() << "GetDesktopDpi() failed.";
|
||||
WARNING << "GetDesktopDpi() failed.";
|
||||
}
|
||||
} else {
|
||||
qWarning() << __getSystemErrorMessage(kReloadSystemMetrics, hr);
|
||||
WARNING << __getSystemErrorMessage(kReloadSystemMetrics, hr);
|
||||
}
|
||||
} else {
|
||||
qWarning() << __getSystemErrorMessage(kD2D1CreateFactory, hr);
|
||||
WARNING << __getSystemErrorMessage(kD2D1CreateFactory, hr);
|
||||
}
|
||||
}
|
||||
const HDC hdc = GetDC(nullptr);
|
||||
|
@ -977,16 +991,16 @@ quint32 Utils::getPrimaryScreenDpi(const bool horizontal)
|
|||
if ((dpiX > 0) && (dpiY > 0)) {
|
||||
valid = true;
|
||||
} else {
|
||||
qWarning() << getSystemErrorMessage(kGetDeviceCaps);
|
||||
WARNING << getSystemErrorMessage(kGetDeviceCaps);
|
||||
}
|
||||
if (ReleaseDC(nullptr, hdc) == 0) {
|
||||
qWarning() << getSystemErrorMessage(kReleaseDC);
|
||||
WARNING << getSystemErrorMessage(kReleaseDC);
|
||||
}
|
||||
if (valid) {
|
||||
return (horizontal ? dpiX : dpiY);
|
||||
}
|
||||
} else {
|
||||
qWarning() << getSystemErrorMessage(kGetDC);
|
||||
WARNING << getSystemErrorMessage(kGetDC);
|
||||
}
|
||||
return USER_DEFAULT_SCREEN_DPI;
|
||||
}
|
||||
|
@ -1003,7 +1017,7 @@ quint32 Utils::getWindowDpi(const WId windowId, const bool horizontal)
|
|||
if (dpi > 0) {
|
||||
return dpi;
|
||||
} else {
|
||||
qWarning() << getSystemErrorMessage(kGetDpiForWindow);
|
||||
WARNING << getSystemErrorMessage(kGetDpiForWindow);
|
||||
}
|
||||
}
|
||||
if (API_USER_AVAILABLE(GetSystemDpiForProcess)) {
|
||||
|
@ -1011,7 +1025,7 @@ quint32 Utils::getWindowDpi(const WId windowId, const bool horizontal)
|
|||
if (dpi > 0) {
|
||||
return dpi;
|
||||
} else {
|
||||
qWarning() << getSystemErrorMessage(kGetSystemDpiForProcess);
|
||||
WARNING << getSystemErrorMessage(kGetSystemDpiForProcess);
|
||||
}
|
||||
}
|
||||
if (API_USER_AVAILABLE(GetDpiForSystem)) {
|
||||
|
@ -1019,7 +1033,7 @@ quint32 Utils::getWindowDpi(const WId windowId, const bool horizontal)
|
|||
if (dpi > 0) {
|
||||
return dpi;
|
||||
} else {
|
||||
qWarning() << getSystemErrorMessage(kGetDpiForSystem);
|
||||
WARNING << getSystemErrorMessage(kGetDpiForSystem);
|
||||
}
|
||||
}
|
||||
return getPrimaryScreenDpi(horizontal);
|
||||
|
@ -1127,7 +1141,7 @@ void Utils::updateWindowFrameBorderColor(const WId windowId, const bool dark)
|
|||
const BOOL value = (dark ? TRUE : FALSE);
|
||||
const HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hwnd, mode, &value, sizeof(value));
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1141,7 +1155,7 @@ void Utils::fixupQtInternals(const WId windowId)
|
|||
SetLastError(ERROR_SUCCESS);
|
||||
const auto oldClassStyle = static_cast<DWORD>(GetClassLongPtrW(hwnd, GCL_STYLE));
|
||||
if (oldClassStyle == 0) {
|
||||
qWarning() << getSystemErrorMessage(kGetClassLongPtrW);
|
||||
WARNING << getSystemErrorMessage(kGetClassLongPtrW);
|
||||
return;
|
||||
}
|
||||
// CS_HREDRAW/CS_VREDRAW will trigger a repaint event when the window size changes
|
||||
|
@ -1152,13 +1166,13 @@ void Utils::fixupQtInternals(const WId windowId)
|
|||
const DWORD newClassStyle = (oldClassStyle & ~(CS_HREDRAW | CS_VREDRAW));
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetClassLongPtrW(hwnd, GCL_STYLE, static_cast<LONG_PTR>(newClassStyle)) == 0) {
|
||||
qWarning() << getSystemErrorMessage(kSetClassLongPtrW);
|
||||
WARNING << getSystemErrorMessage(kSetClassLongPtrW);
|
||||
return;
|
||||
}
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
const auto oldWindowStyle = static_cast<DWORD>(GetWindowLongPtrW(hwnd, GWL_STYLE));
|
||||
if (oldWindowStyle == 0) {
|
||||
qWarning() << getSystemErrorMessage(kGetWindowLongPtrW);
|
||||
WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
|
||||
return;
|
||||
}
|
||||
// Qt by default adds the "WS_POPUP" flag to all Win32 windows it created and maintained,
|
||||
|
@ -1171,7 +1185,7 @@ void Utils::fixupQtInternals(const WId windowId)
|
|||
const DWORD newWindowStyle = ((oldWindowStyle & ~WS_POPUP) | WS_OVERLAPPED);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetWindowLongPtrW(hwnd, GWL_STYLE, static_cast<LONG_PTR>(newWindowStyle)) == 0) {
|
||||
qWarning() << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
return;
|
||||
}
|
||||
triggerFrameChange(windowId);
|
||||
|
@ -1188,12 +1202,12 @@ void Utils::startSystemMove(QWindow *window, const QPoint &globalPos)
|
|||
window->startSystemMove();
|
||||
#else
|
||||
if (ReleaseCapture() == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kReleaseCapture);
|
||||
WARNING << getSystemErrorMessage(kReleaseCapture);
|
||||
return;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(window->winId());
|
||||
if (PostMessageW(hwnd, WM_SYSCOMMAND, 0xF012 /*SC_DRAGMOVE*/, 0) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kPostMessageW);
|
||||
WARNING << getSystemErrorMessage(kPostMessageW);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1212,12 +1226,12 @@ void Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi
|
|||
window->startSystemResize(edges);
|
||||
#else
|
||||
if (ReleaseCapture() == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kReleaseCapture);
|
||||
WARNING << getSystemErrorMessage(kReleaseCapture);
|
||||
return;
|
||||
}
|
||||
const auto hwnd = reinterpret_cast<HWND>(window->winId());
|
||||
if (PostMessageW(hwnd, WM_SYSCOMMAND, qtEdgesToWin32Orientation(edges), 0) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kPostMessageW);
|
||||
WARNING << getSystemErrorMessage(kPostMessageW);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1273,12 +1287,12 @@ void Utils::installSystemMenuHook(const WId windowId,
|
|||
const auto originalWindowProc = reinterpret_cast<WNDPROC>(GetWindowLongPtrW(hwnd, GWLP_WNDPROC));
|
||||
Q_ASSERT(originalWindowProc);
|
||||
if (!originalWindowProc) {
|
||||
qWarning() << getSystemErrorMessage(kGetWindowLongPtrW);
|
||||
WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
|
||||
return;
|
||||
}
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(SystemMenuHookWindowProc)) == 0) {
|
||||
qWarning() << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
return;
|
||||
}
|
||||
//triggerFrameChange(windowId); // Crash
|
||||
|
@ -1308,7 +1322,7 @@ void Utils::uninstallSystemMenuHook(const WId windowId)
|
|||
const auto hwnd = reinterpret_cast<HWND>(windowId);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetWindowLongPtrW(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(data.originalWindowProc)) == 0) {
|
||||
qWarning() << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
return;
|
||||
}
|
||||
//triggerFrameChange(windowId); // Crash
|
||||
|
@ -1330,7 +1344,7 @@ void Utils::tryToBeCompatibleWithQtFramelessWindowHint(const WId windowId,
|
|||
SetLastError(ERROR_SUCCESS);
|
||||
const LONG_PTR originalWindowStyle = GetWindowLongPtrW(hwnd, GWL_STYLE);
|
||||
if (originalWindowStyle == 0) {
|
||||
qWarning() << getSystemErrorMessage(kGetWindowLongPtrW);
|
||||
WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
|
||||
return;
|
||||
}
|
||||
const Qt::WindowFlags originalWindowFlags = getWindowFlags();
|
||||
|
@ -1341,7 +1355,7 @@ void Utils::tryToBeCompatibleWithQtFramelessWindowHint(const WId windowId,
|
|||
// flag to the extended window style.
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetWindowLongPtrW(hwnd, GWL_STYLE, originalWindowStyle) == 0) {
|
||||
qWarning() << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
return;
|
||||
}
|
||||
triggerFrameChange(windowId);
|
||||
|
@ -1357,7 +1371,7 @@ void Utils::setAeroSnappingEnabled(const WId windowId, const bool enable)
|
|||
SetLastError(ERROR_SUCCESS);
|
||||
const auto oldWindowStyle = static_cast<DWORD>(GetWindowLongPtrW(hwnd, GWL_STYLE));
|
||||
if (oldWindowStyle == 0) {
|
||||
qWarning() << getSystemErrorMessage(kGetWindowLongPtrW);
|
||||
WARNING << getSystemErrorMessage(kGetWindowLongPtrW);
|
||||
return;
|
||||
}
|
||||
// The key is the existence of the "WS_THICKFRAME" flag.
|
||||
|
@ -1372,7 +1386,7 @@ void Utils::setAeroSnappingEnabled(const WId windowId, const bool enable)
|
|||
}();
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
if (SetWindowLongPtrW(hwnd, GWL_STYLE, static_cast<LONG_PTR>(newWindowStyle)) == 0) {
|
||||
qWarning() << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
WARNING << getSystemErrorMessage(kSetWindowLongPtrW);
|
||||
return;
|
||||
}
|
||||
triggerFrameChange(windowId);
|
||||
|
@ -1394,11 +1408,11 @@ void Utils::tryToEnableHighestDpiAwarenessLevel()
|
|||
// Any attempt to change the DPI awareness level through API will always fail,
|
||||
// so we treat this situation as succeeded.
|
||||
if (dwError == ERROR_ACCESS_DENIED) {
|
||||
qDebug() << "FramelessHelper doesn't have access to change the current process's DPI awareness level,"
|
||||
" most likely due to it has been set externally already.";
|
||||
DEBUG << "FramelessHelper doesn't have access to change the current process's DPI awareness level,"
|
||||
" most likely due to it has been set externally already.";
|
||||
return true;
|
||||
}
|
||||
qWarning() << __getSystemErrorMessage(kSetProcessDpiAwarenessContext, dwError);
|
||||
WARNING << __getSystemErrorMessage(kSetProcessDpiAwarenessContext, dwError);
|
||||
return false;
|
||||
};
|
||||
if (SetProcessDpiAwarenessContext2(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)) {
|
||||
|
@ -1424,11 +1438,11 @@ void Utils::tryToEnableHighestDpiAwarenessLevel()
|
|||
// Any attempt to change the DPI awareness level through API will always fail,
|
||||
// so we treat this situation as succeeded.
|
||||
if (hr == E_ACCESSDENIED) {
|
||||
qDebug() << "FramelessHelper doesn't have access to change the current process's DPI awareness level,"
|
||||
" most likely due to it has been set externally already.";
|
||||
DEBUG << "FramelessHelper doesn't have access to change the current process's DPI awareness level,"
|
||||
" most likely due to it has been set externally already.";
|
||||
return true;
|
||||
}
|
||||
qWarning() << __getSystemErrorMessage(kSetProcessDpiAwareness, hr);
|
||||
WARNING << __getSystemErrorMessage(kSetProcessDpiAwareness, hr);
|
||||
return false;
|
||||
};
|
||||
if (SetProcessDpiAwareness2(PROCESS_PER_MONITOR_DPI_AWARE_V2)) {
|
||||
|
@ -1445,7 +1459,7 @@ void Utils::tryToEnableHighestDpiAwarenessLevel()
|
|||
// issue by always load it dynamically at runtime.
|
||||
if (API_USER_AVAILABLE(SetProcessDPIAware)) {
|
||||
if (API_CALL_FUNCTION(SetProcessDPIAware) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kSetProcessDPIAware);
|
||||
WARNING << getSystemErrorMessage(kSetProcessDPIAware);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1480,7 +1494,7 @@ void Utils::updateGlobalWin32ControlsTheme(const WId windowId, const bool dark)
|
|||
const HRESULT hr = API_CALL_FUNCTION(SetWindowTheme, hwnd,
|
||||
(dark ? kSystemDarkThemeResourceName : kSystemLightThemeResourceName), nullptr);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(kSetWindowTheme, hr);
|
||||
WARNING << __getSystemErrorMessage(kSetWindowTheme, hr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1527,7 +1541,7 @@ void Utils::forceSquareCornersForWindow(const WId windowId, const bool force)
|
|||
const _DWM_WINDOW_CORNER_PREFERENCE wcp = (force ? _DWMWCP_DONOTROUND : _DWMWCP_ROUND);
|
||||
const HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hwnd, _DWMWA_WINDOW_CORNER_PREFERENCE, &wcp, sizeof(wcp));
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1552,8 +1566,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
const auto pSetWindowCompositionAttribute =
|
||||
reinterpret_cast<SetWindowCompositionAttributePtr>(
|
||||
SysApiLoader::instance()->get(kSetWindowCompositionAttribute));
|
||||
//static const bool isWin11Insider2OrGreater = doCompareWindowsVersion({10, 0, 22557});
|
||||
static const bool isWin11Insider1OrGreater = doCompareWindowsVersion({10, 0, 22523});
|
||||
static const bool isWin1122H2OrGreater = isWindowsVersionOrGreater(WindowsVersion::_11_22H2);
|
||||
static const bool isWin11OrGreater = isWindowsVersionOrGreater(WindowsVersion::_11_21H2);
|
||||
static const bool isWin10OrGreater = isWindowsVersionOrGreater(WindowsVersion::_10_1507);
|
||||
const BlurMode blurMode = [mode]() -> BlurMode {
|
||||
|
@ -1561,15 +1574,15 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
return mode;
|
||||
}
|
||||
if ((mode == BlurMode::Windows_Mica) && !isWin11OrGreater) {
|
||||
qWarning() << "The Mica material is not supported on your system, fallback to the Acrylic blur instead...";
|
||||
WARNING << "The Mica material is not supported on your system, fallback to the Acrylic blur instead...";
|
||||
if (isWin10OrGreater) {
|
||||
return BlurMode::Windows_Acrylic;
|
||||
}
|
||||
qWarning() << "The Acrylic blur is not supported on your system, fallback to the traditional DWM blur instead...";
|
||||
WARNING << "The Acrylic blur is not supported on your system, fallback to the traditional DWM blur instead...";
|
||||
return BlurMode::Windows_Aero;
|
||||
}
|
||||
if ((mode == BlurMode::Windows_Acrylic) && !isWin10OrGreater) {
|
||||
qWarning() << "The Acrylic blur is not supported on your system, fallback to the traditional DWM blur instead...";
|
||||
WARNING << "The Acrylic blur is not supported on your system, fallback to the traditional DWM blur instead...";
|
||||
return BlurMode::Windows_Aero;
|
||||
}
|
||||
if (mode == BlurMode::Default) {
|
||||
|
@ -1585,12 +1598,12 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
return mode;
|
||||
}();
|
||||
if (blurMode == BlurMode::Disable) {
|
||||
if (isWin11Insider1OrGreater) {
|
||||
if (isWin1122H2OrGreater) {
|
||||
const _DWM_SYSTEMBACKDROP_TYPE dwmsbt = _DWMSBT_NONE;
|
||||
const HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute,
|
||||
hwnd, _DWMWA_SYSTEMBACKDROP_TYPE, &dwmsbt, sizeof(dwmsbt));
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
}
|
||||
if (isWin11OrGreater) {
|
||||
|
@ -1598,47 +1611,44 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
HRESULT hr = API_CALL_FUNCTION(DwmSetWindowAttribute,
|
||||
hwnd, _DWMWA_MICA_EFFECT, &enable, sizeof(enable));
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
const MARGINS margins = {0, 0, 0, 0};
|
||||
hr = API_CALL_FUNCTION(DwmExtendFrameIntoClientArea, hwnd, &margins);
|
||||
if (FAILED(hr)) {
|
||||
qWarning() << __getSystemErrorMessage(kDwmExtendFrameIntoClientArea, hr);
|
||||
WARNING << __getSystemErrorMessage(kDwmExtendFrameIntoClientArea, hr);
|
||||
}
|
||||
} else {
|
||||
ACCENT_POLICY policy;
|
||||
SecureZeroMemory(&policy, sizeof(policy));
|
||||
policy.State = ACCENT_DISABLED;
|
||||
WINDOWCOMPOSITIONATTRIBDATA wcad;
|
||||
SecureZeroMemory(&wcad, sizeof(wcad));
|
||||
wcad.Attrib = WCA_ACCENT_POLICY;
|
||||
wcad.pvData = &policy;
|
||||
wcad.cbData = sizeof(policy);
|
||||
if (pSetWindowCompositionAttribute(hwnd, &wcad) == FALSE) {
|
||||
WARNING << getSystemErrorMessage(kSetWindowCompositionAttribute);
|
||||
}
|
||||
}
|
||||
ACCENT_POLICY policy;
|
||||
SecureZeroMemory(&policy, sizeof(policy));
|
||||
policy.State = ACCENT_DISABLED;
|
||||
WINDOWCOMPOSITIONATTRIBDATA wcad;
|
||||
SecureZeroMemory(&wcad, sizeof(wcad));
|
||||
wcad.Attrib = WCA_ACCENT_POLICY;
|
||||
wcad.pvData = &policy;
|
||||
wcad.cbData = sizeof(policy);
|
||||
if (pSetWindowCompositionAttribute(hwnd, &wcad) == FALSE) {
|
||||
qWarning() << getSystemErrorMessage(kSetWindowCompositionAttribute);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (blurMode == BlurMode::Windows_Mica) {
|
||||
// By giving a negative value, DWM will extend the window frame into the whole
|
||||
// client area. We need this step because the Mica material can only be applied
|
||||
// to the non-client area of a window. Without this step, you'll get a window
|
||||
// with a pure black background.
|
||||
const MARGINS margins = {-1, -1, -1, -1};
|
||||
HRESULT hr = API_CALL_FUNCTION(DwmExtendFrameIntoClientArea, hwnd, &margins);
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (isWin11Insider1OrGreater) {
|
||||
// ### FIXME: Is it necessary to enable the host backdrop brush in the first place? To be checked.
|
||||
const BOOL enable = TRUE;
|
||||
if (isWin1122H2OrGreater) {
|
||||
const _DWM_SYSTEMBACKDROP_TYPE dwmsbt = _DWMSBT_MAINWINDOW; // Mica
|
||||
hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hwnd,
|
||||
_DWMWA_USE_HOSTBACKDROPBRUSH, &enable, sizeof(enable));
|
||||
_DWMWA_SYSTEMBACKDROP_TYPE, &dwmsbt, sizeof(dwmsbt));
|
||||
if (SUCCEEDED(hr)) {
|
||||
const _DWM_SYSTEMBACKDROP_TYPE dwmsbt = _DWMSBT_MAINWINDOW; // Mica
|
||||
hr = API_CALL_FUNCTION(DwmSetWindowAttribute, hwnd,
|
||||
_DWMWA_SYSTEMBACKDROP_TYPE, &dwmsbt, sizeof(dwmsbt));
|
||||
if (SUCCEEDED(hr)) {
|
||||
return true;
|
||||
} else {
|
||||
qWarning() << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
qWarning() << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
} else {
|
||||
const BOOL enable = TRUE;
|
||||
|
@ -1647,11 +1657,11 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
if (SUCCEEDED(hr)) {
|
||||
return true;
|
||||
} else {
|
||||
qWarning() << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
WARNING << __getSystemErrorMessage(kDwmSetWindowAttribute, hr);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << __getSystemErrorMessage(kDwmExtendFrameIntoClientArea, hr);
|
||||
WARNING << __getSystemErrorMessage(kDwmExtendFrameIntoClientArea, hr);
|
||||
}
|
||||
} else {
|
||||
ACCENT_POLICY policy;
|
||||
|
@ -1664,7 +1674,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
return color;
|
||||
}
|
||||
QColor clr = (shouldAppsUseDarkMode() ? kDefaultSystemDarkColor : kDefaultSystemLightColor);
|
||||
clr.setAlpha(230); // 90% opacity.
|
||||
clr.setAlphaF(0.9f);
|
||||
return clr;
|
||||
}();
|
||||
// This API expects the #AABBGGRR format.
|
||||
|
@ -1682,15 +1692,15 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
wcad.cbData = sizeof(policy);
|
||||
if (pSetWindowCompositionAttribute(hwnd, &wcad) != FALSE) {
|
||||
if (!isWin11OrGreater) {
|
||||
qDebug() << "Enabling the Acrylic blur for Win32 windows on Windows 10 "
|
||||
"is very buggy. The only recommended way by Microsoft is to "
|
||||
"use the XAML Island technology or use pure UWP instead. If "
|
||||
"you find your window becomes very laggy during moving and "
|
||||
"resizing, please disable the Acrylic blur immediately.";
|
||||
DEBUG << "Enabling the Acrylic blur for Win32 windows on Windows 10 "
|
||||
"is very buggy. The only recommended way by Microsoft is to "
|
||||
"use the XAML Island technology or use pure UWP instead. If "
|
||||
"you find your window becomes very laggy during moving and "
|
||||
"resizing, please disable the Acrylic blur immediately.";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
qWarning() << getSystemErrorMessage(kSetWindowCompositionAttribute);
|
||||
WARNING << getSystemErrorMessage(kSetWindowCompositionAttribute);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1705,7 +1715,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
return FALSE;
|
||||
}
|
||||
if ((mode != BlurMode::Default) && (mode != BlurMode::Windows_Aero)) {
|
||||
qWarning() << "The only supported blur mode on Windows 7 is the traditional DWM blur.";
|
||||
WARNING << "The only supported blur mode on Windows 7 is the traditional DWM blur.";
|
||||
}
|
||||
return TRUE;
|
||||
}();
|
||||
|
@ -1713,7 +1723,7 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
if (SUCCEEDED(hr)) {
|
||||
return true;
|
||||
}
|
||||
qWarning() << __getSystemErrorMessage(kDwmEnableBlurBehindWindow, hr);
|
||||
WARNING << __getSystemErrorMessage(kDwmEnableBlurBehindWindow, hr);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
@ -1721,6 +1731,12 @@ bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode,
|
|||
|
||||
QColor Utils::getDwmAccentColor()
|
||||
{
|
||||
// According to my test, this AccentColor will be exactly the same with
|
||||
// ColorizationColor, what's the meaning of it? But Microsoft products
|
||||
// usually read this setting instead of using DwmGetColorizationColor(),
|
||||
// so we'd better also do the same thing.
|
||||
// There's no Windows API to get this value, so we can only read it
|
||||
// directly from the registry.
|
||||
const QSettings registry(dwmRegistryKey(), QSettings::NativeFormat);
|
||||
bool ok = false;
|
||||
const DWORD value = registry.value(kAccentColor).toULongLong(&ok);
|
||||
|
@ -1733,4 +1749,57 @@ QColor Utils::getDwmAccentColor()
|
|||
return QColor(abgr.blue(), abgr.green(), abgr.red(), abgr.alpha());
|
||||
}
|
||||
|
||||
QString Utils::getWallpaperFilePath()
|
||||
{
|
||||
wchar_t path[MAX_PATH] = {};
|
||||
if (SystemParametersInfoW(SPI_GETDESKWALLPAPER, MAX_PATH, path, 0) == FALSE) {
|
||||
WARNING << getSystemErrorMessage(kSystemParametersInfoW);
|
||||
return {};
|
||||
}
|
||||
return QString::fromWCharArray(path);
|
||||
}
|
||||
|
||||
WallpaperAspectStyle Utils::getWallpaperAspectStyle()
|
||||
{
|
||||
static constexpr const auto defaultStyle = WallpaperAspectStyle::Fill;
|
||||
const QSettings registry(desktopRegistryKey(), QSettings::NativeFormat);
|
||||
bool ok = false;
|
||||
const DWORD wallpaperStyle = registry.value(kWallpaperStyle).toULongLong(&ok);
|
||||
if (!ok) {
|
||||
return defaultStyle;
|
||||
}
|
||||
switch (wallpaperStyle) {
|
||||
case 0: {
|
||||
ok = false;
|
||||
const DWORD tileWallpaper = registry.value(kTileWallpaper).toULongLong(&ok);
|
||||
if (ok && (tileWallpaper != 0)) {
|
||||
return WallpaperAspectStyle::Tile;
|
||||
}
|
||||
return WallpaperAspectStyle::Center;
|
||||
}
|
||||
case 2:
|
||||
return WallpaperAspectStyle::Stretch; // Ignore aspect ratio to fill.
|
||||
case 6:
|
||||
return WallpaperAspectStyle::Fit; // Keep aspect ratio to fill, but don't expand/crop.
|
||||
case 10:
|
||||
return WallpaperAspectStyle::Fill; // Keep aspect ratio to fill, expand/crop if necessary.
|
||||
case 22:
|
||||
return WallpaperAspectStyle::Span; // ???
|
||||
default:
|
||||
return defaultStyle;
|
||||
}
|
||||
}
|
||||
|
||||
bool Utils::isBlurBehindWindowSupported()
|
||||
{
|
||||
static const bool result = []() -> bool {
|
||||
if (FramelessConfig::instance()->isSet(Option::ForceNonNativeBackgroundBlur)) {
|
||||
return false;
|
||||
}
|
||||
static const bool isWin11OrGreater = isWindowsVersionOrGreater(WindowsVersion::_11_21H2);
|
||||
return isWin11OrGreater;
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
|
|
@ -37,6 +37,7 @@ set(PUBLIC_HEADERS
|
|||
${INCLUDE_PREFIX}/framelessquickhelper.h
|
||||
${INCLUDE_PREFIX}/framelessquickutils.h
|
||||
${INCLUDE_PREFIX}/quickchromepalette.h
|
||||
${INCLUDE_PREFIX}/quickmicamaterial.h
|
||||
)
|
||||
|
||||
set(PUBLIC_HEADERS_ALIAS
|
||||
|
@ -45,6 +46,7 @@ set(PUBLIC_HEADERS_ALIAS
|
|||
${INCLUDE_PREFIX}/FramelessQuickHelper
|
||||
${INCLUDE_PREFIX}/FramelessQuickUtils
|
||||
${INCLUDE_PREFIX}/QuickChromePalette
|
||||
${INCLUDE_PREFIX}/QuickMicaMaterial
|
||||
)
|
||||
|
||||
set(PRIVATE_HEADERS
|
||||
|
@ -53,6 +55,7 @@ set(PRIVATE_HEADERS
|
|||
${INCLUDE_PREFIX}/private/framelessquickhelper_p.h
|
||||
${INCLUDE_PREFIX}/private/framelessquickwindow_p.h
|
||||
${INCLUDE_PREFIX}/private/framelessquickwindow_p_p.h
|
||||
${INCLUDE_PREFIX}/private/quickmicamaterial_p.h
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
|
@ -64,6 +67,7 @@ set(SOURCES
|
|||
framelessquickhelper.cpp
|
||||
quickchromepalette.cpp
|
||||
global.cpp
|
||||
quickmicamaterial.cpp
|
||||
)
|
||||
|
||||
if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)
|
||||
|
@ -134,38 +138,9 @@ if(FRAMELESSHELPER_BUILD_STATIC)
|
|||
endif()
|
||||
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
QT_NO_CAST_FROM_ASCII
|
||||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_URL_CAST_FROM_STRING
|
||||
QT_NO_CAST_FROM_BYTEARRAY
|
||||
#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
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060500
|
||||
FRAMELESSHELPER_QUICK_LIBRARY
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
set(_WIN32_WINNT_WIN10 0x0A00)
|
||||
set(NTDDI_WIN10_CO 0x0A00000B)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
_CRT_NON_CONFORMING_SWPRINTFS _CRT_SECURE_NO_WARNINGS
|
||||
_ENABLE_EXTENDED_ALIGNED_STORAGE NOMINMAX UNICODE
|
||||
_UNICODE WIN32_LEAN_AND_MEAN WINRT_LEAN_AND_MEAN
|
||||
WINVER=${_WIN32_WINNT_WIN10} _WIN32_WINNT=${_WIN32_WINNT_WIN10}
|
||||
_WIN32_IE=${_WIN32_WINNT_WIN10} NTDDI_VERSION=${NTDDI_WIN10_CO}
|
||||
)
|
||||
target_compile_options(${SUB_PROJ_NAME} PRIVATE
|
||||
/utf-8 /W3 /WX # Cannot use /W4 here, Qt's own headers are not warning-clean.
|
||||
)
|
||||
else()
|
||||
target_compile_options(${SUB_PROJ_NAME} PRIVATE
|
||||
-Wall -Wextra -Werror
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::QuickPrivate
|
||||
Qt${QT_VERSION_MAJOR}::QuickTemplates2Private
|
||||
|
@ -183,25 +158,6 @@ target_include_directories(${SUB_PROJ_NAME} PUBLIC
|
|||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}/private>"
|
||||
)
|
||||
|
||||
install(TARGETS ${SUB_PROJ_NAME}
|
||||
EXPORT ${SUB_PROJ_NAME}Targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}
|
||||
)
|
||||
|
||||
export(EXPORT ${SUB_PROJ_NAME}Targets
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/${SUB_PROJ_NAME}Targets.cmake"
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
)
|
||||
|
||||
install(FILES ${PUBLIC_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH})
|
||||
install(FILES ${PUBLIC_HEADERS_ALIAS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH})
|
||||
install(FILES ${PRIVATE_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}/private)
|
||||
|
||||
install(EXPORT ${SUB_PROJ_NAME}Targets
|
||||
FILE ${SUB_PROJ_NAME}Targets.cmake
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
include(../core/cmakehelper.cmake)
|
||||
setup_compile_params(${SUB_PROJ_NAME})
|
||||
setup_package_export(${SUB_PROJ_NAME} ${SUB_PROJ_PATH} "${PUBLIC_HEADERS}" "${PUBLIC_HEADERS_ALIAS}" "${PRIVATE_HEADERS}")
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "framelessquickhelper.h"
|
||||
#include "framelessquickhelper_p.h"
|
||||
#include "quickmicamaterial.h"
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
#include <QtCore/qdebug.h>
|
||||
|
@ -33,6 +34,7 @@
|
|||
# include <QtGui/private/qwindow_p.h> // For QWINDOWSIZE_MAX
|
||||
#endif
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
#include <QtQuick/private/qquickitem_p.h>
|
||||
#include <QtQuickTemplates2/private/qquickabstractbutton_p.h>
|
||||
#include <framelessmanager.h>
|
||||
#include <framelessconfig_p.h>
|
||||
|
@ -40,6 +42,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFramelessQuickHelper, "wangwenx190.framelesshelper.quick.framelessquickhelper")
|
||||
#define INFO qCInfo(lcFramelessQuickHelper)
|
||||
#define DEBUG qCDebug(lcFramelessQuickHelper)
|
||||
#define WARNING qCWarning(lcFramelessQuickHelper)
|
||||
#define CRITICAL qCCritical(lcFramelessQuickHelper)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
struct QuickHelperData
|
||||
|
@ -63,6 +71,24 @@ struct QuickHelper
|
|||
|
||||
Q_GLOBAL_STATIC(QuickHelper, g_quickHelper)
|
||||
|
||||
[[nodiscard]] static inline QuickMicaMaterial *findMicaMaterialItem(const QQuickWindow * const window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
QQuickItem * const rootItem = window->contentItem();
|
||||
if (const auto item = rootItem->findChild<QuickMicaMaterial *>()) {
|
||||
return item;
|
||||
}
|
||||
const auto item = new QuickMicaMaterial;
|
||||
item->setParent(rootItem);
|
||||
item->setParentItem(rootItem);
|
||||
item->setZ(-999); // Make sure it always stays on the bottom.
|
||||
QQuickItemPrivate::get(item)->anchors()->setFill(rootItem);
|
||||
return item;
|
||||
}
|
||||
|
||||
FramelessQuickHelperPrivate::FramelessQuickHelperPrivate(FramelessQuickHelper *q) : QObject(q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
|
@ -393,26 +419,32 @@ void FramelessQuickHelperPrivate::setBlurBehindWindowEnabled(const bool value, c
|
|||
if (m_blurBehindWindowEnabled == value) {
|
||||
return;
|
||||
}
|
||||
QuickGlobal::BlurMode mode = QuickGlobal::BlurMode::Disable;
|
||||
if (value) {
|
||||
if (!m_savedWindowBackgroundColor.isValid()) {
|
||||
m_savedWindowBackgroundColor = window->color();
|
||||
if (Utils::isBlurBehindWindowSupported()) {
|
||||
QuickGlobal::BlurMode mode = QuickGlobal::BlurMode::Disable;
|
||||
if (value) {
|
||||
if (!m_savedWindowBackgroundColor.isValid()) {
|
||||
m_savedWindowBackgroundColor = window->color();
|
||||
}
|
||||
window->setColor(kDefaultTransparentColor);
|
||||
mode = QuickGlobal::BlurMode::Default;
|
||||
} else {
|
||||
if (m_savedWindowBackgroundColor.isValid()) {
|
||||
window->setColor(m_savedWindowBackgroundColor);
|
||||
m_savedWindowBackgroundColor = {};
|
||||
}
|
||||
mode = QuickGlobal::BlurMode::Disable;
|
||||
}
|
||||
if (Utils::setBlurBehindWindowEnabled(window->winId(),
|
||||
FRAMELESSHELPER_ENUM_QUICK_TO_CORE(BlurMode, mode), color)) {
|
||||
m_blurBehindWindowEnabled = value;
|
||||
Q_EMIT q->blurBehindWindowEnabledChanged();
|
||||
} else {
|
||||
WARNING << "Failed to enable/disable blur behind window.";
|
||||
}
|
||||
window->setColor(kDefaultTransparentColor);
|
||||
mode = QuickGlobal::BlurMode::Default;
|
||||
} else {
|
||||
if (m_savedWindowBackgroundColor.isValid()) {
|
||||
window->setColor(m_savedWindowBackgroundColor);
|
||||
m_savedWindowBackgroundColor = {};
|
||||
}
|
||||
mode = QuickGlobal::BlurMode::Disable;
|
||||
}
|
||||
if (Utils::setBlurBehindWindowEnabled(window->winId(),
|
||||
FRAMELESSHELPER_ENUM_QUICK_TO_CORE(BlurMode, mode), color)) {
|
||||
m_blurBehindWindowEnabled = value;
|
||||
findMicaMaterialItem(window)->setVisible(m_blurBehindWindowEnabled);
|
||||
Q_EMIT q->blurBehindWindowEnabledChanged();
|
||||
} else {
|
||||
qWarning() << "Failed to enable/disable blur behind window.";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,12 +26,14 @@
|
|||
#include "framelessquickhelper.h"
|
||||
#include "framelessquickutils.h"
|
||||
#include "quickchromepalette.h"
|
||||
#include "quickmicamaterial.h"
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
# include "quickstandardsystembutton_p.h"
|
||||
# include "quickstandardtitlebar_p.h"
|
||||
# include "framelessquickwindow_p.h"
|
||||
# include "framelessquickwindow_p_p.h"
|
||||
# include "framelessquickhelper_p.h"
|
||||
# include "quickmicamaterial_p.h"
|
||||
#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
# include <QtQuick/qquickwindow.h>
|
||||
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
|
@ -50,6 +52,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcQuickModule, "wangwenx190.framelesshelper.quick.quickmodule")
|
||||
#define INFO qCInfo(lcQuickModule)
|
||||
#define DEBUG qCDebug(lcQuickModule)
|
||||
#define WARNING qCWarning(lcQuickModule)
|
||||
#define CRITICAL qCCritical(lcQuickModule)
|
||||
|
||||
void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
|
||||
{
|
||||
Q_ASSERT(engine);
|
||||
|
@ -74,6 +82,7 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
|
|||
qRegisterMetaType<QuickGlobal::BlurMode>();
|
||||
|
||||
qRegisterMetaType<QuickGlobal>();
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
qRegisterMetaType<FramelessQuickUtils>();
|
||||
qRegisterMetaType<QuickChromePalette>();
|
||||
|
@ -83,6 +92,8 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
|
|||
qRegisterMetaType<FramelessQuickWindow>();
|
||||
qRegisterMetaType<FramelessQuickWindowPrivate>();
|
||||
qRegisterMetaType<FramelessQuickHelperPrivate>();
|
||||
qRegisterMetaType<QuickMicaMaterial>();
|
||||
qRegisterMetaType<QuickMicaMaterialPrivate>();
|
||||
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
|
||||
qmlRegisterUncreatableType<QuickGlobal>(QUICK_URI_FULL, "FramelessHelperConstants",
|
||||
|
@ -100,6 +111,8 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
|
|||
qmlRegisterRevision<QQuickItem, 254>(QUICK_URI_FULL);
|
||||
|
||||
qmlRegisterType<FramelessQuickHelper>(QUICK_URI_EXPAND("FramelessHelper"));
|
||||
qmlRegisterType<QuickMicaMaterial>(QUICK_URI_EXPAND("MicaMaterial"));
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||
qmlRegisterType<QuickStandardSystemButton>(QUICK_URI_EXPAND("StandardSystemButton"));
|
||||
qmlRegisterType<QuickStandardTitleBar>(QUICK_URI_EXPAND("StandardTitleBar"));
|
||||
|
|
|
@ -28,6 +28,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFramelessQuickUtils, "wangwenx190.framelesshelper.quick.framelessquickutils")
|
||||
#define INFO qCInfo(lcFramelessQuickUtils)
|
||||
#define DEBUG qCDebug(lcFramelessQuickUtils)
|
||||
#define WARNING qCWarning(lcFramelessQuickUtils)
|
||||
#define CRITICAL qCCritical(lcFramelessQuickUtils)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
FramelessQuickUtils::FramelessQuickUtils(QObject *parent) : QObject(parent)
|
||||
|
@ -73,7 +79,7 @@ QuickGlobal::SystemTheme FramelessQuickUtils::systemTheme() const
|
|||
QColor FramelessQuickUtils::systemAccentColor() const
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
return Utils::getDwmColorizationColor();
|
||||
return Utils::getDwmAccentColor();
|
||||
#elif defined(Q_OS_LINUX)
|
||||
return Utils::getWmThemeColor();
|
||||
#elif defined(Q_OS_MACOS)
|
||||
|
|
|
@ -34,6 +34,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFramelessQuickWindow, "wangwenx190.framelesshelper.quick.framelessquickwindow")
|
||||
#define INFO qCInfo(lcFramelessQuickWindow)
|
||||
#define DEBUG qCDebug(lcFramelessQuickWindow)
|
||||
#define WARNING qCWarning(lcFramelessQuickWindow)
|
||||
#define CRITICAL qCCritical(lcFramelessQuickWindow)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
FramelessQuickWindowPrivate::FramelessQuickWindowPrivate(FramelessQuickWindow *q) : QObject(q)
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcQuickGlobal, "wangwenx190.framelesshelper.quick.global")
|
||||
#define INFO qCInfo(lcQuickGlobal)
|
||||
#define DEBUG qCDebug(lcQuickGlobal)
|
||||
#define WARNING qCWarning(lcQuickGlobal)
|
||||
#define CRITICAL qCCritical(lcQuickGlobal)
|
||||
|
||||
namespace FramelessHelper::Quick
|
||||
{
|
||||
|
||||
|
|
|
@ -26,6 +26,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcQuickChromePalette, "wangwenx190.framelesshelper.quick.quickchromepalette")
|
||||
#define INFO qCInfo(lcQuickChromePalette)
|
||||
#define DEBUG qCDebug(lcQuickChromePalette)
|
||||
#define WARNING qCWarning(lcQuickChromePalette)
|
||||
#define CRITICAL qCCritical(lcQuickChromePalette)
|
||||
|
||||
QuickChromePalette::QuickChromePalette(QObject *parent) : ChromePalette(parent)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -0,0 +1,261 @@
|
|||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (C) 2022 by wangwenx190 (Yuhang Zhao)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "quickmicamaterial.h"
|
||||
#include "quickmicamaterial_p.h"
|
||||
#include <micamaterial.h>
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtGui/qscreen.h>
|
||||
#include <QtGui/qpainter.h>
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#include <QtQuick/qquickwindow.h>
|
||||
#include <QtQuick/qsgsimpletexturenode.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcQuickMicaMaterial, "wangwenx190.framelesshelper.quick.quickmicamaterial")
|
||||
#define INFO qCInfo(lcQuickMicaMaterial)
|
||||
#define DEBUG qCDebug(lcQuickMicaMaterial)
|
||||
#define WARNING qCWarning(lcQuickMicaMaterial)
|
||||
#define CRITICAL qCCritical(lcQuickMicaMaterial)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
struct QuickMicaData
|
||||
{
|
||||
QMutex mutex;
|
||||
};
|
||||
|
||||
Q_GLOBAL_STATIC(QuickMicaData, g_data)
|
||||
|
||||
class WallpaperImageNode : public QObject, public QSGTransformNode
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(WallpaperImageNode)
|
||||
|
||||
public:
|
||||
explicit WallpaperImageNode(QuickMicaMaterial *item);
|
||||
~WallpaperImageNode() override;
|
||||
|
||||
public Q_SLOTS:
|
||||
void maybeUpdateWallpaperImageClipRect();
|
||||
void maybeGenerateWallpaperImageCache(const bool force = false);
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
|
||||
private:
|
||||
QScopedPointer<QSGTexture> m_texture;
|
||||
QPointer<QuickMicaMaterial> m_item = nullptr;
|
||||
QSGSimpleTextureNode *m_node = nullptr;
|
||||
QPixmap m_pixmapCache = {};
|
||||
QPointer<MicaMaterial> m_micaMaterial = nullptr;
|
||||
};
|
||||
|
||||
WallpaperImageNode::WallpaperImageNode(QuickMicaMaterial *item)
|
||||
{
|
||||
Q_ASSERT(item);
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
m_item = item;
|
||||
initialize();
|
||||
}
|
||||
|
||||
WallpaperImageNode::~WallpaperImageNode() = default;
|
||||
|
||||
void WallpaperImageNode::initialize()
|
||||
{
|
||||
g_data()->mutex.lock();
|
||||
|
||||
QQuickWindow * const window = m_item->window();
|
||||
m_micaMaterial = MicaMaterial::attach(window);
|
||||
|
||||
m_node = new QSGSimpleTextureNode;
|
||||
m_node->setFiltering(QSGTexture::Linear);
|
||||
|
||||
g_data()->mutex.unlock();
|
||||
|
||||
maybeGenerateWallpaperImageCache();
|
||||
maybeUpdateWallpaperImageClipRect();
|
||||
|
||||
appendChildNode(m_node);
|
||||
|
||||
connect(m_micaMaterial, &MicaMaterial::shouldRedraw, this, [this](){
|
||||
maybeGenerateWallpaperImageCache(true);
|
||||
});
|
||||
connect(window, &QQuickWindow::beforeRendering, this,
|
||||
&WallpaperImageNode::maybeUpdateWallpaperImageClipRect, Qt::DirectConnection);
|
||||
|
||||
QuickMicaMaterialPrivate::get(m_item)->appendNode(this);
|
||||
}
|
||||
|
||||
void WallpaperImageNode::maybeGenerateWallpaperImageCache(const bool force)
|
||||
{
|
||||
QMutexLocker locker(&g_data()->mutex);
|
||||
if (!m_pixmapCache.isNull() && !force) {
|
||||
return;
|
||||
}
|
||||
const QSize desktopSize = QGuiApplication::primaryScreen()->virtualSize();
|
||||
static constexpr const QPoint originPoint = {0, 0};
|
||||
m_pixmapCache = QPixmap(desktopSize);
|
||||
m_pixmapCache.fill(kDefaultTransparentColor);
|
||||
QPainter painter(&m_pixmapCache);
|
||||
m_micaMaterial->paint(&painter, desktopSize, originPoint);
|
||||
m_texture.reset(m_item->window()->createTextureFromImage(m_pixmapCache.toImage()));
|
||||
m_node->setTexture(m_texture.data());
|
||||
}
|
||||
|
||||
void WallpaperImageNode::maybeUpdateWallpaperImageClipRect()
|
||||
{
|
||||
QMutexLocker locker(&g_data()->mutex);
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
const QSizeF itemSize = m_item->size();
|
||||
#else
|
||||
const QSizeF itemSize = {m_item->width(), m_item->height()};
|
||||
#endif
|
||||
m_node->setRect(QRectF(QPointF(0.0, 0.0), itemSize));
|
||||
m_node->setSourceRect(QRectF(m_item->mapToGlobal(QPointF(0.0, 0.0)), itemSize));
|
||||
}
|
||||
|
||||
QuickMicaMaterialPrivate::QuickMicaMaterialPrivate(QuickMicaMaterial *q) : QObject(q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
if (!q) {
|
||||
return;
|
||||
}
|
||||
q_ptr = q;
|
||||
initialize();
|
||||
}
|
||||
|
||||
QuickMicaMaterialPrivate::~QuickMicaMaterialPrivate() = default;
|
||||
|
||||
QuickMicaMaterialPrivate *QuickMicaMaterialPrivate::get(QuickMicaMaterial *q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
if (!q) {
|
||||
return nullptr;
|
||||
}
|
||||
return q->d_func();
|
||||
}
|
||||
|
||||
const QuickMicaMaterialPrivate *QuickMicaMaterialPrivate::get(const QuickMicaMaterial *q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
if (!q) {
|
||||
return nullptr;
|
||||
}
|
||||
return q->d_func();
|
||||
}
|
||||
|
||||
void QuickMicaMaterialPrivate::initialize()
|
||||
{
|
||||
Q_Q(QuickMicaMaterial);
|
||||
q->setFlag(QuickMicaMaterial::ItemHasContents);
|
||||
q->setClip(true);
|
||||
}
|
||||
|
||||
void QuickMicaMaterialPrivate::rebindWindow()
|
||||
{
|
||||
Q_Q(QuickMicaMaterial);
|
||||
QQuickWindow * const window = q->window();
|
||||
if (!window) {
|
||||
return;
|
||||
}
|
||||
if (m_rootWindowXChangedConnection) {
|
||||
disconnect(m_rootWindowXChangedConnection);
|
||||
m_rootWindowXChangedConnection = {};
|
||||
}
|
||||
if (m_rootWindowYChangedConnection) {
|
||||
disconnect(m_rootWindowYChangedConnection);
|
||||
m_rootWindowYChangedConnection = {};
|
||||
}
|
||||
m_rootWindowXChangedConnection = connect(window, &QQuickWindow::xChanged, q, [q](){ q->update(); });
|
||||
m_rootWindowYChangedConnection = connect(window, &QQuickWindow::yChanged, q, [q](){ q->update(); });
|
||||
}
|
||||
|
||||
void QuickMicaMaterialPrivate::forceRegenerateWallpaperImageCache()
|
||||
{
|
||||
if (m_nodes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (auto &&node : qAsConst(m_nodes)) {
|
||||
if (node) {
|
||||
node->maybeGenerateWallpaperImageCache(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QuickMicaMaterialPrivate::appendNode(WallpaperImageNode *node)
|
||||
{
|
||||
Q_ASSERT(node);
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
if (m_nodes.contains(node)) {
|
||||
return;
|
||||
}
|
||||
m_nodes.append(node);
|
||||
}
|
||||
|
||||
QuickMicaMaterial::QuickMicaMaterial(QQuickItem *parent)
|
||||
: QQuickItem(parent), d_ptr(new QuickMicaMaterialPrivate(this))
|
||||
{
|
||||
}
|
||||
|
||||
QuickMicaMaterial::~QuickMicaMaterial() = default;
|
||||
|
||||
void QuickMicaMaterial::itemChange(const ItemChange change, const ItemChangeData &value)
|
||||
{
|
||||
QQuickItem::itemChange(change, value);
|
||||
Q_D(QuickMicaMaterial);
|
||||
switch (change) {
|
||||
case ItemDevicePixelRatioHasChanged: {
|
||||
d->forceRegenerateWallpaperImageCache();
|
||||
update(); // Force re-paint immediately.
|
||||
} break;
|
||||
case ItemSceneChange: {
|
||||
if (value.window) {
|
||||
d->rebindWindow();
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QSGNode *QuickMicaMaterial::updatePaintNode(QSGNode *old, UpdatePaintNodeData *data)
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
auto node = static_cast<WallpaperImageNode *>(old);
|
||||
if (!node) {
|
||||
node = new WallpaperImageNode(this);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
FRAMELESSHELPER_END_NAMESPACE
|
||||
|
||||
#include "quickmicamaterial.moc"
|
|
@ -0,0 +1 @@
|
|||
#include "../../include/FramelessHelper/Quick/quickmicamaterial.h"
|
|
@ -0,0 +1 @@
|
|||
#include "../../include/FramelessHelper/Quick/private/quickmicamaterial_p.h"
|
|
@ -34,6 +34,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcQuickStandardSystemButton, "wangwenx190.framelesshelper.quick.quickstandardsystembutton")
|
||||
#define INFO qCInfo(lcQuickStandardSystemButton)
|
||||
#define DEBUG qCDebug(lcQuickStandardSystemButton)
|
||||
#define WARNING qCWarning(lcQuickStandardSystemButton)
|
||||
#define CRITICAL qCCritical(lcQuickStandardSystemButton)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
QuickStandardSystemButton::QuickStandardSystemButton(QQuickItem *parent) : QQuickButton(parent)
|
||||
|
|
|
@ -34,6 +34,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcQuickStandardTitleBar, "wangwenx190.framelesshelper.quick.quickstandardtitlebar")
|
||||
#define INFO qCInfo(lcQuickStandardTitleBar)
|
||||
#define DEBUG qCDebug(lcQuickStandardTitleBar)
|
||||
#define WARNING qCWarning(lcQuickStandardTitleBar)
|
||||
#define CRITICAL qCCritical(lcQuickStandardTitleBar)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
QuickStandardTitleBar::QuickStandardTitleBar(QQuickItem *parent) : QQuickRectangle(parent)
|
||||
|
|
|
@ -92,29 +92,10 @@ if(FRAMELESSHELPER_BUILD_STATIC)
|
|||
endif()
|
||||
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
QT_NO_CAST_FROM_ASCII
|
||||
QT_NO_CAST_TO_ASCII
|
||||
QT_NO_URL_CAST_FROM_STRING
|
||||
QT_NO_CAST_FROM_BYTEARRAY
|
||||
QT_NO_KEYWORDS
|
||||
QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
|
||||
QT_NO_FOREACH
|
||||
QT_USE_QSTRINGBUILDER
|
||||
QT_DEPRECATED_WARNINGS
|
||||
QT_DISABLE_DEPRECATED_BEFORE=0x060500
|
||||
FRAMELESSHELPER_WIDGETS_LIBRARY
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_options(${SUB_PROJ_NAME} PRIVATE
|
||||
/utf-8 /W3 /WX # Cannot use /W4 here, Qt's own headers are not warning-clean.
|
||||
)
|
||||
else()
|
||||
target_compile_options(${SUB_PROJ_NAME} PRIVATE
|
||||
-Wall -Wextra -Werror
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::WidgetsPrivate
|
||||
)
|
||||
|
@ -130,25 +111,6 @@ target_include_directories(${SUB_PROJ_NAME} PUBLIC
|
|||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}/private>"
|
||||
)
|
||||
|
||||
install(TARGETS ${SUB_PROJ_NAME}
|
||||
EXPORT ${SUB_PROJ_NAME}Targets
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}
|
||||
)
|
||||
|
||||
export(EXPORT ${SUB_PROJ_NAME}Targets
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/${SUB_PROJ_NAME}Targets.cmake"
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
)
|
||||
|
||||
install(FILES ${PUBLIC_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH})
|
||||
install(FILES ${PUBLIC_HEADERS_ALIAS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH})
|
||||
install(FILES ${PRIVATE_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${SUB_PROJ_PATH}/private)
|
||||
|
||||
install(EXPORT ${SUB_PROJ_NAME}Targets
|
||||
FILE ${SUB_PROJ_NAME}Targets.cmake
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
)
|
||||
include(../core/cmakehelper.cmake)
|
||||
setup_compile_params(${SUB_PROJ_NAME})
|
||||
setup_package_export(${SUB_PROJ_NAME} ${SUB_PROJ_PATH} "${PUBLIC_HEADERS}" "${PUBLIC_HEADERS_ALIAS}" "${PRIVATE_HEADERS}")
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFramelessMainWindow, "wangwenx190.framelesshelper.widgets.framelessmainwindow")
|
||||
#define INFO qCInfo(lcFramelessMainWindow)
|
||||
#define DEBUG qCDebug(lcFramelessMainWindow)
|
||||
#define WARNING qCWarning(lcFramelessMainWindow)
|
||||
#define CRITICAL qCCritical(lcFramelessMainWindow)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
FramelessMainWindowPrivate::FramelessMainWindowPrivate(FramelessMainWindow *q) : QObject(q)
|
||||
|
@ -103,6 +109,11 @@ void FramelessMainWindowPrivate::toggleFullScreen()
|
|||
}
|
||||
}
|
||||
|
||||
WidgetsSharedHelper *FramelessMainWindowPrivate::widgetsSharedHelper() const
|
||||
{
|
||||
return (m_helper.isNull() ? nullptr : m_helper.data());
|
||||
}
|
||||
|
||||
FramelessMainWindow::FramelessMainWindow(QWidget *parent, const Qt::WindowFlags flags)
|
||||
: QMainWindow(parent, flags), d_ptr(new FramelessMainWindowPrivate(this))
|
||||
{
|
||||
|
|
|
@ -30,6 +30,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFramelessWidget, "wangwenx190.framelesshelper.widgets.framelesswidget")
|
||||
#define INFO qCInfo(lcFramelessWidget)
|
||||
#define DEBUG qCDebug(lcFramelessWidget)
|
||||
#define WARNING qCWarning(lcFramelessWidget)
|
||||
#define CRITICAL qCCritical(lcFramelessWidget)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
FramelessWidgetPrivate::FramelessWidgetPrivate(FramelessWidget *q) : QObject(q)
|
||||
|
@ -103,6 +109,11 @@ void FramelessWidgetPrivate::toggleFullScreen()
|
|||
}
|
||||
}
|
||||
|
||||
WidgetsSharedHelper *FramelessWidgetPrivate::widgetsSharedHelper() const
|
||||
{
|
||||
return (m_helper.isNull() ? nullptr : m_helper.data());
|
||||
}
|
||||
|
||||
FramelessWidget::FramelessWidget(QWidget *parent)
|
||||
: QWidget(parent), d_ptr(new FramelessWidgetPrivate(this))
|
||||
{
|
||||
|
|
|
@ -24,6 +24,11 @@
|
|||
|
||||
#include "framelesswidgetshelper.h"
|
||||
#include "framelesswidgetshelper_p.h"
|
||||
#include "framelesswidget.h"
|
||||
#include "framelesswidget_p.h"
|
||||
#include "framelessmainwindow.h"
|
||||
#include "framelessmainwindow_p.h"
|
||||
#include "widgetssharedhelper_p.h"
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
|
@ -37,6 +42,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcFramelessWidgetsHelper, "wangwenx190.framelesshelper.widgets.framelesswidgetshelper")
|
||||
#define INFO qCInfo(lcFramelessWidgetsHelper)
|
||||
#define DEBUG qCDebug(lcFramelessWidgetsHelper)
|
||||
#define WARNING qCWarning(lcFramelessWidgetsHelper)
|
||||
#define CRITICAL qCCritical(lcFramelessWidgetsHelper)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
struct WidgetsHelperData
|
||||
|
@ -60,6 +71,25 @@ struct WidgetsHelper
|
|||
|
||||
Q_GLOBAL_STATIC(WidgetsHelper, g_widgetsHelper)
|
||||
|
||||
[[nodiscard]] static inline WidgetsSharedHelper *findWidgetsSharedHelper(QWidget *window)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
if (const auto widget = qobject_cast<FramelessWidget *>(window)) {
|
||||
if (const auto widgetPriv = FramelessWidgetPrivate::get(widget)) {
|
||||
return widgetPriv->widgetsSharedHelper();
|
||||
}
|
||||
}
|
||||
if (const auto mainWindow = qobject_cast<FramelessMainWindow *>(window)) {
|
||||
if (const auto mainWindowPriv = FramelessMainWindowPrivate::get(mainWindow)) {
|
||||
return mainWindowPriv->widgetsSharedHelper();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FramelessWidgetsHelperPrivate::FramelessWidgetsHelperPrivate(FramelessWidgetsHelper *q) : QObject(q)
|
||||
{
|
||||
Q_ASSERT(q);
|
||||
|
@ -164,28 +194,39 @@ void FramelessWidgetsHelperPrivate::setBlurBehindWindowEnabled(const bool enable
|
|||
if (m_blurBehindWindowEnabled == enable) {
|
||||
return;
|
||||
}
|
||||
BlurMode mode = BlurMode::Disable;
|
||||
QPalette palette = window->palette();
|
||||
if (enable) {
|
||||
if (!m_savedWindowBackgroundColor.isValid()) {
|
||||
m_savedWindowBackgroundColor = palette.color(QPalette::Window);
|
||||
if (Utils::isBlurBehindWindowSupported()) {
|
||||
BlurMode mode = BlurMode::Disable;
|
||||
QPalette palette = window->palette();
|
||||
if (enable) {
|
||||
if (!m_savedWindowBackgroundColor.isValid()) {
|
||||
m_savedWindowBackgroundColor = palette.color(QPalette::Window);
|
||||
}
|
||||
palette.setColor(QPalette::Window, kDefaultTransparentColor);
|
||||
mode = BlurMode::Default;
|
||||
} else {
|
||||
if (m_savedWindowBackgroundColor.isValid()) {
|
||||
palette.setColor(QPalette::Window, m_savedWindowBackgroundColor);
|
||||
m_savedWindowBackgroundColor = {};
|
||||
}
|
||||
mode = BlurMode::Disable;
|
||||
}
|
||||
palette.setColor(QPalette::Window, kDefaultTransparentColor);
|
||||
mode = BlurMode::Default;
|
||||
} else {
|
||||
if (m_savedWindowBackgroundColor.isValid()) {
|
||||
palette.setColor(QPalette::Window, m_savedWindowBackgroundColor);
|
||||
m_savedWindowBackgroundColor = {};
|
||||
window->setPalette(palette);
|
||||
if (Utils::setBlurBehindWindowEnabled(window->winId(), mode, color)) {
|
||||
m_blurBehindWindowEnabled = enable;
|
||||
Q_Q(FramelessWidgetsHelper);
|
||||
Q_EMIT q->blurBehindWindowEnabledChanged();
|
||||
} else {
|
||||
WARNING << "Failed to enable/disable blur behind window.";
|
||||
}
|
||||
mode = BlurMode::Disable;
|
||||
}
|
||||
window->setPalette(palette);
|
||||
if (Utils::setBlurBehindWindowEnabled(window->winId(), mode, color)) {
|
||||
m_blurBehindWindowEnabled = enable;
|
||||
Q_Q(FramelessWidgetsHelper);
|
||||
Q_EMIT q->blurBehindWindowEnabledChanged();
|
||||
} else {
|
||||
qWarning() << "Failed to enable/disable blur behind window.";
|
||||
if (WidgetsSharedHelper * const helper = findWidgetsSharedHelper(window)) {
|
||||
m_blurBehindWindowEnabled = enable;
|
||||
helper->setMicaEnabled(m_blurBehindWindowEnabled);
|
||||
Q_Q(FramelessWidgetsHelper);
|
||||
Q_EMIT q->blurBehindWindowEnabledChanged();
|
||||
} else {
|
||||
DEBUG << "Blur behind window is not supported on current platform.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcWidgetsGlobal, "wangwenx190.framelesshelper.widgets.global")
|
||||
#define INFO qCInfo(lcWidgetsGlobal)
|
||||
#define DEBUG qCDebug(lcWidgetsGlobal)
|
||||
#define WARNING qCWarning(lcWidgetsGlobal)
|
||||
#define CRITICAL qCCritical(lcWidgetsGlobal)
|
||||
|
||||
namespace FramelessHelper::Widgets
|
||||
{
|
||||
|
||||
|
|
|
@ -31,6 +31,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcStandardSystemButton, "wangwenx190.framelesshelper.widgets.standardsystembutton")
|
||||
#define INFO qCInfo(lcStandardSystemButton)
|
||||
#define DEBUG qCDebug(lcStandardSystemButton)
|
||||
#define WARNING qCWarning(lcStandardSystemButton)
|
||||
#define CRITICAL qCCritical(lcStandardSystemButton)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
static constexpr const QRect g_buttonRect = {QPoint(0, 0), kDefaultSystemButtonSize};
|
||||
|
|
|
@ -32,6 +32,12 @@
|
|||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcStandardTitleBar, "wangwenx190.framelesshelper.widgets.standardtitlebar")
|
||||
#define INFO qCInfo(lcStandardTitleBar)
|
||||
#define DEBUG qCDebug(lcStandardTitleBar)
|
||||
#define WARNING qCWarning(lcStandardTitleBar)
|
||||
#define CRITICAL qCCritical(lcStandardTitleBar)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
StandardTitleBarPrivate::StandardTitleBarPrivate(StandardTitleBar *q) : QObject(q)
|
||||
|
|
|
@ -26,11 +26,20 @@
|
|||
#include <QtCore/qcoreevent.h>
|
||||
#include <QtGui/qevent.h>
|
||||
#include <QtGui/qpainter.h>
|
||||
#include <QtGui/qwindow.h>
|
||||
#include <QtWidgets/qwidget.h>
|
||||
#include <micamaterial.h>
|
||||
#include <micamaterial_p.h>
|
||||
#include <utils.h>
|
||||
|
||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||
|
||||
Q_LOGGING_CATEGORY(lcWidgetsSharedHelper, "wangwenx190.framelesshelper.widgets.widgetssharedhelper")
|
||||
#define INFO qCInfo(lcWidgetsSharedHelper)
|
||||
#define DEBUG qCDebug(lcWidgetsSharedHelper)
|
||||
#define WARNING qCWarning(lcWidgetsSharedHelper)
|
||||
#define CRITICAL qCCritical(lcWidgetsSharedHelper)
|
||||
|
||||
using namespace Global;
|
||||
|
||||
WidgetsSharedHelper::WidgetsSharedHelper(QObject *parent) : QObject(parent)
|
||||
|
@ -49,9 +58,44 @@ void WidgetsSharedHelper::setup(QWidget *widget)
|
|||
return;
|
||||
}
|
||||
m_targetWidget = widget;
|
||||
m_micaMaterial = MicaMaterial::attach(m_targetWidget);
|
||||
if (m_micaRedrawConnection) {
|
||||
disconnect(m_micaRedrawConnection);
|
||||
m_micaRedrawConnection = {};
|
||||
}
|
||||
m_micaRedrawConnection = connect(m_micaMaterial, &MicaMaterial::shouldRedraw,
|
||||
this, [this](){
|
||||
if (m_targetWidget) {
|
||||
m_targetWidget->update();
|
||||
}
|
||||
});
|
||||
m_targetWidget->installEventFilter(this);
|
||||
updateContentsMargins();
|
||||
m_targetWidget->update();
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||
QScreen *screen = m_targetWidget->screen();
|
||||
#else
|
||||
QScreen *screen = m_targetWidget->windowHandle()->screen();
|
||||
#endif
|
||||
handleScreenChanged(screen);
|
||||
connect(m_targetWidget->windowHandle(), &QWindow::screenChanged, this, &WidgetsSharedHelper::handleScreenChanged);
|
||||
}
|
||||
|
||||
bool WidgetsSharedHelper::isMicaEnabled() const
|
||||
{
|
||||
return m_micaEnabled;
|
||||
}
|
||||
|
||||
void WidgetsSharedHelper::setMicaEnabled(const bool value)
|
||||
{
|
||||
if (m_micaEnabled == value) {
|
||||
return;
|
||||
}
|
||||
m_micaEnabled = value;
|
||||
if (m_targetWidget) {
|
||||
m_targetWidget->update();
|
||||
}
|
||||
Q_EMIT micaEnabledChanged();
|
||||
}
|
||||
|
||||
bool WidgetsSharedHelper::eventFilter(QObject *object, QEvent *event)
|
||||
|
@ -61,6 +105,9 @@ bool WidgetsSharedHelper::eventFilter(QObject *object, QEvent *event)
|
|||
if (!object || !event) {
|
||||
return false;
|
||||
}
|
||||
if (!m_targetWidget) {
|
||||
return QObject::eventFilter(object, event);
|
||||
}
|
||||
if (!object->isWidgetType()) {
|
||||
return QObject::eventFilter(object, event);
|
||||
}
|
||||
|
@ -76,6 +123,12 @@ bool WidgetsSharedHelper::eventFilter(QObject *object, QEvent *event)
|
|||
case QEvent::WindowStateChange: {
|
||||
changeEventHandler(event);
|
||||
} break;
|
||||
case QEvent::Move:
|
||||
case QEvent::Resize: {
|
||||
if (m_micaEnabled) {
|
||||
m_targetWidget->update();
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -99,28 +152,27 @@ void WidgetsSharedHelper::changeEventHandler(QEvent *event)
|
|||
|
||||
void WidgetsSharedHelper::paintEventHandler(QPaintEvent *event)
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
Q_ASSERT(event);
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (!shouldDrawFrameBorder()) {
|
||||
return;
|
||||
}
|
||||
QPainter painter(m_targetWidget);
|
||||
painter.save();
|
||||
QPen pen = {};
|
||||
pen.setColor(Utils::getFrameBorderColor(m_targetWidget->isActiveWindow()));
|
||||
pen.setWidth(kDefaultWindowFrameBorderThickness);
|
||||
painter.setPen(pen);
|
||||
// In fact, we should use "m_targetWidget->width() - 1" here but we can't
|
||||
// because Qt's drawing system has some rounding errors internally and if
|
||||
// we minus one here we'll get a one pixel gap, so sad. But drawing a line
|
||||
// with a little extra pixels won't hurt anyway.
|
||||
painter.drawLine(0, 0, m_targetWidget->width(), 0);
|
||||
painter.restore();
|
||||
#else
|
||||
Q_UNUSED(event);
|
||||
if (m_micaEnabled && m_micaMaterial) {
|
||||
QPainter painter(m_targetWidget);
|
||||
m_micaMaterial->paint(&painter, m_targetWidget->size(),
|
||||
m_targetWidget->mapToGlobal(QPoint(0, 0)));
|
||||
}
|
||||
#ifdef Q_OS_WINDOWS
|
||||
if (shouldDrawFrameBorder()) {
|
||||
QPainter painter(m_targetWidget);
|
||||
painter.save();
|
||||
QPen pen = {};
|
||||
pen.setColor(Utils::getFrameBorderColor(m_targetWidget->isActiveWindow()));
|
||||
pen.setWidth(kDefaultWindowFrameBorderThickness);
|
||||
painter.setPen(pen);
|
||||
// In fact, we should use "m_targetWidget->width() - 1" here but we can't
|
||||
// because Qt's drawing system has some rounding errors internally and if
|
||||
// we minus one here we'll get a one pixel gap, so sad. But drawing a line
|
||||
// with a little extra pixels won't hurt anyway.
|
||||
painter.drawLine(0, 0, m_targetWidget->width(), 0);
|
||||
painter.restore();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -135,6 +187,39 @@ bool WidgetsSharedHelper::shouldDrawFrameBorder() const
|
|||
#endif
|
||||
}
|
||||
|
||||
void WidgetsSharedHelper::handleScreenChanged(QScreen *screen)
|
||||
{
|
||||
Q_ASSERT(m_targetWidget);
|
||||
if (!m_targetWidget) {
|
||||
return;
|
||||
}
|
||||
// The QScreen handle can be null if a window was moved out of a screen.
|
||||
if (!screen) {
|
||||
return;
|
||||
}
|
||||
if (m_screen == screen) {
|
||||
return;
|
||||
}
|
||||
m_screen = screen;
|
||||
m_screenDpr = m_screen->devicePixelRatio();
|
||||
if (m_screenDpiChangeConnection) {
|
||||
disconnect(m_screenDpiChangeConnection);
|
||||
m_screenDpiChangeConnection = {};
|
||||
}
|
||||
m_screenDpiChangeConnection = connect(m_screen, &QScreen::physicalDotsPerInchChanged,
|
||||
this, [this](const qreal dpi){
|
||||
Q_UNUSED(dpi);
|
||||
const qreal currentDpr = m_screen->devicePixelRatio();
|
||||
if (m_screenDpr == currentDpr) {
|
||||
return;
|
||||
}
|
||||
m_screenDpr = currentDpr;
|
||||
if (m_micaEnabled && m_micaMaterial) {
|
||||
MicaMaterialPrivate::get(m_micaMaterial)->maybeGenerateBlurredWallpaper(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void WidgetsSharedHelper::updateContentsMargins()
|
||||
{
|
||||
#ifdef Q_OS_WINDOWS
|
||||
|
|