forked from github_mirror/framelesshelper
blur behind window: add macos implementation
Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
parent
7e3a735a7d
commit
2f36d1f73e
|
@ -55,12 +55,19 @@ function(deploy_qt_libraries arg_target)
|
||||||
--no-virtualkeyboard
|
--no-virtualkeyboard
|
||||||
--no-compiler-runtime
|
--no-compiler-runtime
|
||||||
--no-opengl-sw
|
--no-opengl-sw
|
||||||
|
--verbose 0
|
||||||
${__old_deploy_params}
|
${__old_deploy_params}
|
||||||
"$<TARGET_FILE:${arg_target}>"
|
"$<TARGET_FILE:${arg_target}>"
|
||||||
)
|
)
|
||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
add_custom_command(TARGET ${arg_target} POST_BUILD COMMAND
|
add_custom_command(TARGET ${arg_target} POST_BUILD COMMAND
|
||||||
"${QT_DEPLOY_EXECUTABLE}" "$<TARGET_BUNDLE_DIR:${arg_target}>"
|
"${QT_DEPLOY_EXECUTABLE}"
|
||||||
|
"$<TARGET_BUNDLE_DIR:${arg_target}>"
|
||||||
|
-qmldir="$<TARGET_PROPERTY:${arg_target},SOURCE_DIR>"
|
||||||
|
-qmlimport="${PROJECT_BINARY_DIR}/qml"
|
||||||
|
-verbose=0
|
||||||
)
|
)
|
||||||
|
elseif(UNIX)
|
||||||
|
# TODO
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
|
@ -142,6 +142,7 @@ if(APPLE)
|
||||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||||
"-framework Foundation"
|
"-framework Foundation"
|
||||||
"-framework Cocoa"
|
"-framework Cocoa"
|
||||||
|
"-framework AppKit"
|
||||||
)
|
)
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "framelessmanager.h"
|
||||||
#include <QtCore/qdebug.h>
|
#include <QtCore/qdebug.h>
|
||||||
#include <QtCore/qhash.h>
|
#include <QtCore/qhash.h>
|
||||||
#include <QtCore/qcoreapplication.h>
|
#include <QtCore/qcoreapplication.h>
|
||||||
|
@ -38,20 +39,23 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||||
|
|
||||||
using namespace Global;
|
using namespace Global;
|
||||||
|
|
||||||
class NSWindowProxy
|
class NSWindowProxy : public QObject
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
Q_DISABLE_COPY_MOVE(NSWindowProxy)
|
Q_DISABLE_COPY_MOVE(NSWindowProxy)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit NSWindowProxy(NSWindow *window)
|
explicit NSWindowProxy(QWindow *qtWindow, NSWindow *macWindow, QObject *parent = nil) : QObject(parent)
|
||||||
{
|
{
|
||||||
Q_ASSERT(window);
|
Q_ASSERT(qtWindow);
|
||||||
Q_ASSERT(!instances.contains(window));
|
Q_ASSERT(macWindow);
|
||||||
if (!window || instances.contains(window)) {
|
Q_ASSERT(!instances.contains(macWindow));
|
||||||
|
if (!qtWindow || !macWindow || instances.contains(macWindow)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nswindow = window;
|
qwindow = qtWindow;
|
||||||
instances.insert(nswindow, this);
|
nswindow = macWindow;
|
||||||
|
instances.insert(macWindow, this);
|
||||||
saveState();
|
saveState();
|
||||||
if (!windowClass) {
|
if (!windowClass) {
|
||||||
windowClass = [nswindow class];
|
windowClass = [nswindow class];
|
||||||
|
@ -60,7 +64,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
~NSWindowProxy()
|
~NSWindowProxy() override
|
||||||
{
|
{
|
||||||
instances.remove(nswindow);
|
instances.remove(nswindow);
|
||||||
if (instances.count() <= 0) {
|
if (instances.count() <= 0) {
|
||||||
|
@ -71,6 +75,7 @@ public:
|
||||||
nswindow = nil;
|
nswindow = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
void saveState()
|
void saveState()
|
||||||
{
|
{
|
||||||
oldStyleMask = nswindow.styleMask;
|
oldStyleMask = nswindow.styleMask;
|
||||||
|
@ -180,6 +185,77 @@ public:
|
||||||
[nswindow standardWindowButton:NSWindowZoomButton].hidden = (visible ? NO : YES);
|
[nswindow standardWindowButton:NSWindowZoomButton].hidden = (visible ? NO : YES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setBlurBehindWindowEnabled(const bool enable)
|
||||||
|
{
|
||||||
|
if (enable) {
|
||||||
|
if (blurEffect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSView * const view = [nswindow contentView];
|
||||||
|
#if 1
|
||||||
|
const Class visualEffectViewClass = NSClassFromString(@"NSVisualEffectView");
|
||||||
|
if (!visualEffectViewClass) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSVisualEffectView * const blurView = [[visualEffectViewClass alloc] initWithFrame:view.bounds];
|
||||||
|
#else
|
||||||
|
NSVisualEffectView * const blurView = [[NSVisualEffectView alloc] initWithFrame:view.bounds];
|
||||||
|
#endif
|
||||||
|
blurView.material = NSVisualEffectMaterialUnderWindowBackground;
|
||||||
|
blurView.blendingMode = NSVisualEffectBlendingModeBehindWindow;
|
||||||
|
blurView.state = NSVisualEffectStateFollowsWindowActiveState;
|
||||||
|
const NSView * const parent = [view superview];
|
||||||
|
[parent addSubview:blurView positioned:NSWindowBelow relativeTo:view];
|
||||||
|
blurEffect = blurView;
|
||||||
|
updateBlurTheme();
|
||||||
|
updateBlurSize();
|
||||||
|
connect(FramelessManager::instance(),
|
||||||
|
&FramelessManager::systemThemeChanged, this, &NSWindowProxy::updateBlurTheme);
|
||||||
|
connect(qwindow, &QWindow::widthChanged, this, &NSWindowProxy::updateBlurSize);
|
||||||
|
connect(qwindow, &QWindow::heightChanged, this, &NSWindowProxy::updateBlurSize);
|
||||||
|
} else {
|
||||||
|
if (!blurEffect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (widthChangeConnection) {
|
||||||
|
disconnect(widthChangeConnection);
|
||||||
|
widthChangeConnection = {};
|
||||||
|
}
|
||||||
|
if (heightChangeConnection) {
|
||||||
|
disconnect(heightChangeConnection);
|
||||||
|
heightChangeConnection = {};
|
||||||
|
}
|
||||||
|
if (themeChangeConnection) {
|
||||||
|
disconnect(themeChangeConnection);
|
||||||
|
themeChangeConnection = {};
|
||||||
|
}
|
||||||
|
[blurEffect removeFromSuperview];
|
||||||
|
blurEffect = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateBlurSize()
|
||||||
|
{
|
||||||
|
if (!blurEffect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const NSView * const view = [nswindow contentView];
|
||||||
|
blurEffect.frame = view.frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateBlurTheme()
|
||||||
|
{
|
||||||
|
if (!blurEffect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto view = static_cast<NSVisualEffectView *>(blurEffect);
|
||||||
|
if (Utils::shouldAppsUseDarkMode()) {
|
||||||
|
view.appearance = [NSAppearance appearanceNamed:@"NSAppearanceNameVibrantDark"];
|
||||||
|
} else {
|
||||||
|
view.appearance = [NSAppearance appearanceNamed:@"NSAppearanceNameVibrantLight"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static BOOL canBecomeKeyWindow(id obj, SEL sel)
|
static BOOL canBecomeKeyWindow(id obj, SEL sel)
|
||||||
{
|
{
|
||||||
|
@ -249,8 +325,10 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
QWindow *qwindow = nil;
|
||||||
NSWindow *nswindow = nil;
|
NSWindow *nswindow = nil;
|
||||||
NSEvent *lastMouseDownEvent = nil;
|
NSEvent *lastMouseDownEvent = nil;
|
||||||
|
NSView *blurEffect = nil;
|
||||||
|
|
||||||
NSWindowStyleMask oldStyleMask = 0;
|
NSWindowStyleMask oldStyleMask = 0;
|
||||||
BOOL oldTitlebarAppearsTransparent = NO;
|
BOOL oldTitlebarAppearsTransparent = NO;
|
||||||
|
@ -263,6 +341,10 @@ private:
|
||||||
BOOL oldZoomButtonVisible = NO;
|
BOOL oldZoomButtonVisible = NO;
|
||||||
NSWindowTitleVisibility oldTitleVisibility = NSWindowTitleVisible;
|
NSWindowTitleVisibility oldTitleVisibility = NSWindowTitleVisible;
|
||||||
|
|
||||||
|
QMetaObject::Connection widthChangeConnection = {};
|
||||||
|
QMetaObject::Connection heightChangeConnection = {};
|
||||||
|
QMetaObject::Connection themeChangeConnection = {};
|
||||||
|
|
||||||
static inline QHash<NSWindow *, NSWindowProxy *> instances = {};
|
static inline QHash<NSWindow *, NSWindowProxy *> instances = {};
|
||||||
|
|
||||||
static inline Class windowClass = nil;
|
static inline Class windowClass = nil;
|
||||||
|
@ -300,6 +382,29 @@ Q_GLOBAL_STATIC(NSWindowProxyHash, g_nswindowOverrideHash);
|
||||||
return [nsview window];
|
return [nsview window];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] static inline NSWindowProxy *ensureWindowProxy(const WId windowId)
|
||||||
|
{
|
||||||
|
Q_ASSERT(windowId);
|
||||||
|
if (!windowId) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
if (!g_nswindowOverrideHash()->contains(windowId)) {
|
||||||
|
QWindow * const qwindow = Utils::findWindow(windowId);
|
||||||
|
Q_ASSERT(qwindow);
|
||||||
|
if (!qwindow) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
NSWindow * const nswindow = mac_getNSWindow(windowId);
|
||||||
|
Q_ASSERT(nswindow);
|
||||||
|
if (!nswindow) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
const auto proxy = new NSWindowProxy(qwindow, nswindow);
|
||||||
|
g_nswindowOverrideHash()->insert(windowId, proxy);
|
||||||
|
}
|
||||||
|
return g_nswindowOverrideHash()->value(windowId);
|
||||||
|
}
|
||||||
|
|
||||||
SystemTheme Utils::getSystemTheme()
|
SystemTheme Utils::getSystemTheme()
|
||||||
{
|
{
|
||||||
// ### TODO: how to detect high contrast mode on macOS?
|
// ### TODO: how to detect high contrast mode on macOS?
|
||||||
|
@ -312,20 +417,7 @@ void Utils::setSystemTitleBarVisible(const WId windowId, const bool visible)
|
||||||
if (!windowId) {
|
if (!windowId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!g_nswindowOverrideHash()->contains(windowId)) {
|
NSWindowProxy * const proxy = ensureWindowProxy(windowId);
|
||||||
NSWindow * const nswindow = mac_getNSWindow(windowId);
|
|
||||||
Q_ASSERT(nswindow);
|
|
||||||
if (!nswindow) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const auto proxy = new NSWindowProxy(nswindow);
|
|
||||||
g_nswindowOverrideHash()->insert(windowId, proxy);
|
|
||||||
}
|
|
||||||
NSWindowProxy * const proxy = g_nswindowOverrideHash()->value(windowId);
|
|
||||||
Q_ASSERT(proxy);
|
|
||||||
if (!proxy) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
proxy->setSystemTitleBarVisible(visible);
|
proxy->setSystemTitleBarVisible(visible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -398,4 +490,25 @@ bool Utils::shouldAppsUseDarkMode_macos()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Utils::setBlurBehindWindowEnabled(const WId windowId, const BlurMode mode, const QColor &color)
|
||||||
|
{
|
||||||
|
Q_UNUSED(color);
|
||||||
|
Q_ASSERT(windowId);
|
||||||
|
if (!windowId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const BlurMode blurMode = [mode]() -> BlurMode {
|
||||||
|
if ((mode == BlurMode::Disable) || (mode == BlurMode::Default)) {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
qWarning() << "The BlurMode::Windows_* enum values are not supported on macOS.";
|
||||||
|
return BlurMode::Default;
|
||||||
|
}();
|
||||||
|
NSWindowProxy * const proxy = ensureWindowProxy(windowId);
|
||||||
|
proxy->setBlurBehindWindowEnabled(blurMode == BlurMode::Default);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
FRAMELESSHELPER_END_NAMESPACE
|
FRAMELESSHELPER_END_NAMESPACE
|
||||||
|
|
||||||
|
#include "utils_mac.moc"
|
||||||
|
|
|
@ -95,6 +95,10 @@ if(${QT_VERSION} VERSION_GREATER_EQUAL 6.2)
|
||||||
QtQuick
|
QtQuick
|
||||||
QtQuick.Controls.Basic
|
QtQuick.Controls.Basic
|
||||||
)
|
)
|
||||||
|
set(__lib_prefix)
|
||||||
|
if(UNIX)
|
||||||
|
set(__lib_prefix lib)
|
||||||
|
endif()
|
||||||
set(__lib_suffix)
|
set(__lib_suffix)
|
||||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||||
set(__lib_suffix ${CMAKE_DEBUG_POSTFIX})
|
set(__lib_suffix ${CMAKE_DEBUG_POSTFIX})
|
||||||
|
@ -110,7 +114,7 @@ if(${QT_VERSION} VERSION_GREATER_EQUAL 6.2)
|
||||||
install(FILES
|
install(FILES
|
||||||
"${__import_dir}/qmldir"
|
"${__import_dir}/qmldir"
|
||||||
"${__import_dir}/${SUB_PROJ_NAME}.qmltypes"
|
"${__import_dir}/${SUB_PROJ_NAME}.qmltypes"
|
||||||
"${__import_dir}/${SUB_PROJ_NAME}plugin${__lib_suffix}.${__lib_ext}"
|
"${__import_dir}/${__lib_prefix}${SUB_PROJ_NAME}plugin${__lib_suffix}.${__lib_ext}"
|
||||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/qml/${__import_uri}
|
DESTINATION ${CMAKE_INSTALL_PREFIX}/qml/${__import_uri}
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
Loading…
Reference in New Issue