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-compiler-runtime
|
||||
--no-opengl-sw
|
||||
--verbose 0
|
||||
${__old_deploy_params}
|
||||
"$<TARGET_FILE:${arg_target}>"
|
||||
)
|
||||
elseif(APPLE)
|
||||
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()
|
||||
endfunction()
|
||||
|
|
|
@ -142,6 +142,7 @@ if(APPLE)
|
|||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||
"-framework Foundation"
|
||||
"-framework Cocoa"
|
||||
"-framework AppKit"
|
||||
)
|
||||
elseif(UNIX)
|
||||
target_compile_definitions(${SUB_PROJ_NAME} PRIVATE
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "framelessmanager.h"
|
||||
#include <QtCore/qdebug.h>
|
||||
#include <QtCore/qhash.h>
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
|
@ -38,20 +39,23 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
|
|||
|
||||
using namespace Global;
|
||||
|
||||
class NSWindowProxy
|
||||
class NSWindowProxy : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY_MOVE(NSWindowProxy)
|
||||
|
||||
public:
|
||||
explicit NSWindowProxy(NSWindow *window)
|
||||
explicit NSWindowProxy(QWindow *qtWindow, NSWindow *macWindow, QObject *parent = nil) : QObject(parent)
|
||||
{
|
||||
Q_ASSERT(window);
|
||||
Q_ASSERT(!instances.contains(window));
|
||||
if (!window || instances.contains(window)) {
|
||||
Q_ASSERT(qtWindow);
|
||||
Q_ASSERT(macWindow);
|
||||
Q_ASSERT(!instances.contains(macWindow));
|
||||
if (!qtWindow || !macWindow || instances.contains(macWindow)) {
|
||||
return;
|
||||
}
|
||||
nswindow = window;
|
||||
instances.insert(nswindow, this);
|
||||
qwindow = qtWindow;
|
||||
nswindow = macWindow;
|
||||
instances.insert(macWindow, this);
|
||||
saveState();
|
||||
if (!windowClass) {
|
||||
windowClass = [nswindow class];
|
||||
|
@ -60,7 +64,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
~NSWindowProxy()
|
||||
~NSWindowProxy() override
|
||||
{
|
||||
instances.remove(nswindow);
|
||||
if (instances.count() <= 0) {
|
||||
|
@ -71,6 +75,7 @@ public:
|
|||
nswindow = nil;
|
||||
}
|
||||
|
||||
public Q_SLOTS:
|
||||
void saveState()
|
||||
{
|
||||
oldStyleMask = nswindow.styleMask;
|
||||
|
@ -180,6 +185,77 @@ public:
|
|||
[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:
|
||||
static BOOL canBecomeKeyWindow(id obj, SEL sel)
|
||||
{
|
||||
|
@ -249,8 +325,10 @@ private:
|
|||
}
|
||||
|
||||
private:
|
||||
QWindow *qwindow = nil;
|
||||
NSWindow *nswindow = nil;
|
||||
NSEvent *lastMouseDownEvent = nil;
|
||||
NSView *blurEffect = nil;
|
||||
|
||||
NSWindowStyleMask oldStyleMask = 0;
|
||||
BOOL oldTitlebarAppearsTransparent = NO;
|
||||
|
@ -263,6 +341,10 @@ private:
|
|||
BOOL oldZoomButtonVisible = NO;
|
||||
NSWindowTitleVisibility oldTitleVisibility = NSWindowTitleVisible;
|
||||
|
||||
QMetaObject::Connection widthChangeConnection = {};
|
||||
QMetaObject::Connection heightChangeConnection = {};
|
||||
QMetaObject::Connection themeChangeConnection = {};
|
||||
|
||||
static inline QHash<NSWindow *, NSWindowProxy *> instances = {};
|
||||
|
||||
static inline Class windowClass = nil;
|
||||
|
@ -300,6 +382,29 @@ Q_GLOBAL_STATIC(NSWindowProxyHash, g_nswindowOverrideHash);
|
|||
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()
|
||||
{
|
||||
// ### TODO: how to detect high contrast mode on macOS?
|
||||
|
@ -312,20 +417,7 @@ void Utils::setSystemTitleBarVisible(const WId windowId, const bool visible)
|
|||
if (!windowId) {
|
||||
return;
|
||||
}
|
||||
if (!g_nswindowOverrideHash()->contains(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;
|
||||
}
|
||||
NSWindowProxy * const proxy = ensureWindowProxy(windowId);
|
||||
proxy->setSystemTitleBarVisible(visible);
|
||||
}
|
||||
|
||||
|
@ -398,4 +490,25 @@ bool Utils::shouldAppsUseDarkMode_macos()
|
|||
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
|
||||
|
||||
#include "utils_mac.moc"
|
||||
|
|
|
@ -95,6 +95,10 @@ if(${QT_VERSION} VERSION_GREATER_EQUAL 6.2)
|
|||
QtQuick
|
||||
QtQuick.Controls.Basic
|
||||
)
|
||||
set(__lib_prefix)
|
||||
if(UNIX)
|
||||
set(__lib_prefix lib)
|
||||
endif()
|
||||
set(__lib_suffix)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(__lib_suffix ${CMAKE_DEBUG_POSTFIX})
|
||||
|
@ -110,7 +114,7 @@ if(${QT_VERSION} VERSION_GREATER_EQUAL 6.2)
|
|||
install(FILES
|
||||
"${__import_dir}/qmldir"
|
||||
"${__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}
|
||||
)
|
||||
endif()
|
||||
|
|
Loading…
Reference in New Issue