forked from github_mirror/framelesshelper
macos: add initial implementation
Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
parent
dee635c0b9
commit
5173fb51af
|
@ -311,6 +311,8 @@ using GetWindowDevicePixelRatioCallback = std::function<qreal()>;
|
||||||
|
|
||||||
using SetSystemButtonStateCallback = std::function<void(const SystemButtonType, const ButtonState)>;
|
using SetSystemButtonStateCallback = std::function<void(const SystemButtonType, const ButtonState)>;
|
||||||
|
|
||||||
|
using GetWindowIdCallback = std::function<WId()>;
|
||||||
|
|
||||||
struct UserSettings
|
struct UserSettings
|
||||||
{
|
{
|
||||||
QPoint startupPosition = {};
|
QPoint startupPosition = {};
|
||||||
|
@ -327,8 +329,6 @@ struct UserSettings
|
||||||
|
|
||||||
struct SystemParameters
|
struct SystemParameters
|
||||||
{
|
{
|
||||||
WId windowId = 0;
|
|
||||||
|
|
||||||
GetWindowFlagsCallback getWindowFlags = nullptr;
|
GetWindowFlagsCallback getWindowFlags = nullptr;
|
||||||
SetWindowFlagsCallback setWindowFlags = nullptr;
|
SetWindowFlagsCallback setWindowFlags = nullptr;
|
||||||
|
|
||||||
|
@ -358,15 +358,17 @@ struct SystemParameters
|
||||||
|
|
||||||
SetSystemButtonStateCallback setSystemButtonState = nullptr;
|
SetSystemButtonStateCallback setSystemButtonState = nullptr;
|
||||||
|
|
||||||
|
GetWindowIdCallback getWindowId = nullptr;
|
||||||
|
|
||||||
[[nodiscard]] inline bool isValid() const
|
[[nodiscard]] inline bool isValid() const
|
||||||
{
|
{
|
||||||
return (windowId && getWindowFlags && setWindowFlags && getWindowSize
|
return (getWindowFlags && setWindowFlags && getWindowSize
|
||||||
&& setWindowSize && getWindowPosition && setWindowPosition
|
&& setWindowSize && getWindowPosition && setWindowPosition
|
||||||
&& getWindowScreen && isWindowFixedSize && setWindowFixedSize
|
&& getWindowScreen && isWindowFixedSize && setWindowFixedSize
|
||||||
&& getWindowState && setWindowState && getWindowHandle
|
&& getWindowState && setWindowState && getWindowHandle
|
||||||
&& windowToScreen && screenToWindow && isInsideSystemButtons
|
&& windowToScreen && screenToWindow && isInsideSystemButtons
|
||||||
&& isInsideTitleBarDraggableArea && getWindowDevicePixelRatio
|
&& isInsideTitleBarDraggableArea && getWindowDevicePixelRatio
|
||||||
&& setSystemButtonState);
|
&& setSystemButtonState && getWindowId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -36,8 +36,8 @@ namespace Utils
|
||||||
const QPoint &pos);
|
const QPoint &pos);
|
||||||
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::Edges calculateWindowEdges(const QWindow *window,
|
[[nodiscard]] FRAMELESSHELPER_CORE_API Qt::Edges calculateWindowEdges(const QWindow *window,
|
||||||
const QPoint &pos);
|
const QPoint &pos);
|
||||||
FRAMELESSHELPER_CORE_API void startSystemMove(QWindow *window);
|
FRAMELESSHELPER_CORE_API void startSystemMove(QWindow *window, const QPoint &globalPos);
|
||||||
FRAMELESSHELPER_CORE_API void startSystemResize(QWindow *window, const Qt::Edges edges);
|
FRAMELESSHELPER_CORE_API void startSystemResize(QWindow *window, const Qt::Edges edges, const QPoint &globalPos);
|
||||||
[[nodiscard]] FRAMELESSHELPER_CORE_API QVariant
|
[[nodiscard]] FRAMELESSHELPER_CORE_API QVariant
|
||||||
getSystemButtonIconResource(const Global::SystemButtonType button,
|
getSystemButtonIconResource(const Global::SystemButtonType button,
|
||||||
const Global::SystemTheme theme,
|
const Global::SystemTheme theme,
|
||||||
|
@ -113,6 +113,11 @@ FRAMELESSHELPER_CORE_API void tryToEnableHighestDpiAwarenessLevel();
|
||||||
FRAMELESSHELPER_CORE_API void updateGlobalWin32ControlsTheme(const WId windowId, const bool dark);
|
FRAMELESSHELPER_CORE_API void updateGlobalWin32ControlsTheme(const WId windowId, const bool dark);
|
||||||
#endif // Q_OS_WINDOWS
|
#endif // Q_OS_WINDOWS
|
||||||
|
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
FRAMELESSHELPER_CORE_API void setWindowHook(const WId windowId);
|
||||||
|
FRAMELESSHELPER_CORE_API void unsetWindowHook(const WId windowId);
|
||||||
|
FRAMELESSHELPER_CORE_API void removeWindowFrame(const WId windowId);
|
||||||
|
#endif // Q_OS_MACOS
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|
||||||
FRAMELESSHELPER_END_NAMESPACE
|
FRAMELESSHELPER_END_NAMESPACE
|
||||||
|
|
|
@ -100,7 +100,7 @@ private Q_SLOTS:
|
||||||
void updateSystemMaximizeButton();
|
void updateSystemMaximizeButton();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QPointer<QWidget> q = nullptr;
|
QWidget *q = nullptr;
|
||||||
bool m_initialized = false;
|
bool m_initialized = false;
|
||||||
QScopedPointer<QWidget> m_systemTitleBarWidget;
|
QScopedPointer<QWidget> m_systemTitleBarWidget;
|
||||||
QScopedPointer<QLabel> m_systemWindowTitleLabel;
|
QScopedPointer<QLabel> m_systemWindowTitleLabel;
|
||||||
|
@ -114,7 +114,6 @@ private:
|
||||||
QScopedPointer<QWidget> m_userContentContainerWidget;
|
QScopedPointer<QWidget> m_userContentContainerWidget;
|
||||||
QScopedPointer<QVBoxLayout> m_userContentContainerLayout;
|
QScopedPointer<QVBoxLayout> m_userContentContainerLayout;
|
||||||
Qt::WindowState m_savedWindowState = {};
|
Qt::WindowState m_savedWindowState = {};
|
||||||
QPointer<QWindow> m_window = nullptr;
|
|
||||||
Global::UserSettings m_settings = {};
|
Global::UserSettings m_settings = {};
|
||||||
Global::SystemParameters m_params = {};
|
Global::SystemParameters m_params = {};
|
||||||
bool m_windowExposed = false;
|
bool m_windowExposed = false;
|
||||||
|
|
|
@ -53,7 +53,7 @@ if(WIN32)
|
||||||
framelesshelper_win.cpp
|
framelesshelper_win.cpp
|
||||||
)
|
)
|
||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
list(APPEND SOURCES utils_mac.cpp)
|
list(APPEND SOURCES utils_mac.mm)
|
||||||
elseif(UNIX)
|
elseif(UNIX)
|
||||||
list(APPEND SOURCES utils_linux.cpp)
|
list(APPEND SOURCES utils_linux.cpp)
|
||||||
endif()
|
endif()
|
||||||
|
@ -121,6 +121,13 @@ if(UNIX AND NOT APPLE)
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||||
|
"-framework Cocoa"
|
||||||
|
"-framework Carbon"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
target_link_libraries(${SUB_PROJ_NAME} PRIVATE
|
||||||
Qt${QT_VERSION_MAJOR}::CorePrivate
|
Qt${QT_VERSION_MAJOR}::CorePrivate
|
||||||
Qt${QT_VERSION_MAJOR}::GuiPrivate
|
Qt${QT_VERSION_MAJOR}::GuiPrivate
|
||||||
|
|
|
@ -59,8 +59,9 @@ void FramelessHelperQt::addWindow(const UserSettings &settings, const SystemPara
|
||||||
if (!params.isValid()) {
|
if (!params.isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const WId windowId = params.getWindowId();
|
||||||
g_qtHelper()->mutex.lock();
|
g_qtHelper()->mutex.lock();
|
||||||
if (g_qtHelper()->data.contains(params.windowId)) {
|
if (g_qtHelper()->data.contains(windowId)) {
|
||||||
g_qtHelper()->mutex.unlock();
|
g_qtHelper()->mutex.unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -70,10 +71,16 @@ void FramelessHelperQt::addWindow(const UserSettings &settings, const SystemPara
|
||||||
QWindow *window = params.getWindowHandle();
|
QWindow *window = params.getWindowHandle();
|
||||||
// Give it a parent so that it can be deleted even if we forget to do so.
|
// Give it a parent so that it can be deleted even if we forget to do so.
|
||||||
data.eventFilter = new FramelessHelperQt(window);
|
data.eventFilter = new FramelessHelperQt(window);
|
||||||
g_qtHelper()->data.insert(params.windowId, data);
|
g_qtHelper()->data.insert(windowId, data);
|
||||||
g_qtHelper()->mutex.unlock();
|
g_qtHelper()->mutex.unlock();
|
||||||
|
#ifndef Q_OS_MACOS
|
||||||
params.setWindowFlags(params.getWindowFlags() | Qt::FramelessWindowHint);
|
params.setWindowFlags(params.getWindowFlags() | Qt::FramelessWindowHint);
|
||||||
|
#endif
|
||||||
window->installEventFilter(data.eventFilter);
|
window->installEventFilter(data.eventFilter);
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
Utils::setWindowHook(windowId);
|
||||||
|
Utils::removeWindowFrame(windowId);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
||||||
|
@ -115,8 +122,10 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
||||||
const auto mouseEvent = static_cast<QMouseEvent *>(event);
|
const auto mouseEvent = static_cast<QMouseEvent *>(event);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
|
||||||
const QPoint scenePos = mouseEvent->scenePosition().toPoint();
|
const QPoint scenePos = mouseEvent->scenePosition().toPoint();
|
||||||
|
const QPoint globalPos = mouseEvent->globalPosition().toPoint();
|
||||||
#else
|
#else
|
||||||
const QPoint scenePos = mouseEvent->windowPos().toPoint();
|
const QPoint scenePos = mouseEvent->windowPos().toPoint();
|
||||||
|
const QPoint globalPos = mouseEvent->globalPos();
|
||||||
#endif
|
#endif
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case QEvent::MouseMove: {
|
case QEvent::MouseMove: {
|
||||||
|
@ -138,7 +147,7 @@ bool FramelessHelperQt::eventFilter(QObject *object, QEvent *event)
|
||||||
if (edges == Qt::Edges{}) {
|
if (edges == Qt::Edges{}) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Utils::startSystemResize(window, edges);
|
Utils::startSystemResize(window, edges, globalPos);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -50,6 +50,9 @@ Q_GLOBAL_STATIC(FramelessWindowsManagerHelper, g_helper)
|
||||||
|
|
||||||
Q_GLOBAL_STATIC(FramelessWindowsManager, g_manager)
|
Q_GLOBAL_STATIC(FramelessWindowsManager, g_manager)
|
||||||
|
|
||||||
|
static constexpr const char MAC_LAYER_ENV_VAR[] = "QT_MAC_WANTS_LAYER";
|
||||||
|
FRAMELESSHELPER_BYTEARRAY_CONSTANT2(OptionEnabled, "1")
|
||||||
|
|
||||||
FramelessWindowsManagerPrivate::FramelessWindowsManagerPrivate(FramelessWindowsManager *q) : QObject(q)
|
FramelessWindowsManagerPrivate::FramelessWindowsManagerPrivate(FramelessWindowsManager *q) : QObject(q)
|
||||||
{
|
{
|
||||||
Q_ASSERT(q);
|
Q_ASSERT(q);
|
||||||
|
@ -80,7 +83,7 @@ const FramelessWindowsManagerPrivate *FramelessWindowsManagerPrivate::get(const
|
||||||
return pub->d_func();
|
return pub->d_func();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FramelessWindowsManagerPrivate::usePureQtImplementation() const
|
bool FramelessWindowsManagerPrivate::usePureQtImplementation()
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
static const bool result = []() -> bool {
|
static const bool result = []() -> bool {
|
||||||
|
@ -108,12 +111,13 @@ void FramelessWindowsManagerPrivate::addWindow(const UserSettings &settings, con
|
||||||
if (!params.isValid()) {
|
if (!params.isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const WId windowId = params.getWindowId();
|
||||||
g_helper()->mutex.lock();
|
g_helper()->mutex.lock();
|
||||||
if (g_helper()->windowIds.contains(params.windowId)) {
|
if (g_helper()->windowIds.contains(windowId)) {
|
||||||
g_helper()->mutex.unlock();
|
g_helper()->mutex.unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
g_helper()->windowIds.append(params.windowId);
|
g_helper()->windowIds.append(windowId);
|
||||||
g_helper()->mutex.unlock();
|
g_helper()->mutex.unlock();
|
||||||
static const bool pureQt = usePureQtImplementation();
|
static const bool pureQt = usePureQtImplementation();
|
||||||
#ifdef Q_OS_WINDOWS
|
#ifdef Q_OS_WINDOWS
|
||||||
|
@ -121,11 +125,11 @@ void FramelessWindowsManagerPrivate::addWindow(const UserSettings &settings, con
|
||||||
// Work-around Win32 multi-monitor artifacts.
|
// Work-around Win32 multi-monitor artifacts.
|
||||||
QWindow * const window = params.getWindowHandle();
|
QWindow * const window = params.getWindowHandle();
|
||||||
Q_ASSERT(window);
|
Q_ASSERT(window);
|
||||||
connect(window, &QWindow::screenChanged, window, [¶ms, window](QScreen *screen){
|
connect(window, &QWindow::screenChanged, window, [windowId, window](QScreen *screen){
|
||||||
Q_UNUSED(screen);
|
Q_UNUSED(screen);
|
||||||
// Force a WM_NCCALCSIZE event to inform Windows about our custom window frame,
|
// Force a WM_NCCALCSIZE event to inform Windows about our custom window frame,
|
||||||
// this is only necessary when the window is being moved cross monitors.
|
// this is only necessary when the window is being moved cross monitors.
|
||||||
Utils::triggerFrameChange(params.windowId);
|
Utils::triggerFrameChange(windowId);
|
||||||
// For some reason the window is not repainted correctly when moving cross monitors,
|
// For some reason the window is not repainted correctly when moving cross monitors,
|
||||||
// we workaround this issue by force a re-paint and re-layout of the window by triggering
|
// we workaround this issue by force a re-paint and re-layout of the window by triggering
|
||||||
// a resize event manually. Although the actual size does not change, the issue we
|
// a resize event manually. Although the actual size does not change, the issue we
|
||||||
|
@ -142,8 +146,12 @@ void FramelessWindowsManagerPrivate::addWindow(const UserSettings &settings, con
|
||||||
FramelessHelperWin::addWindow(settings, params);
|
FramelessHelperWin::addWindow(settings, params);
|
||||||
}
|
}
|
||||||
if (!(settings.options & Option::DontInstallSystemMenuHook)) {
|
if (!(settings.options & Option::DontInstallSystemMenuHook)) {
|
||||||
Utils::installSystemMenuHook(params.windowId, settings.options,
|
Utils::installSystemMenuHook(windowId, settings.options, settings.systemMenuOffset, params.isWindowFixedSize);
|
||||||
settings.systemMenuOffset, params.isWindowFixedSize);
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef Q_OS_MACOS
|
||||||
|
if (qEnvironmentVariableIntValue(MAC_LAYER_ENV_VAR) != 1) {
|
||||||
|
qputenv(MAC_LAYER_ENV_VAR, kOptionEnabled);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,11 +44,11 @@ public:
|
||||||
Q_NODISCARD static FramelessWindowsManagerPrivate *get(FramelessWindowsManager *pub);
|
Q_NODISCARD static FramelessWindowsManagerPrivate *get(FramelessWindowsManager *pub);
|
||||||
Q_NODISCARD static const FramelessWindowsManagerPrivate *get(const FramelessWindowsManager *pub);
|
Q_NODISCARD static const FramelessWindowsManagerPrivate *get(const FramelessWindowsManager *pub);
|
||||||
|
|
||||||
Q_NODISCARD bool usePureQtImplementation() const;
|
Q_NODISCARD static bool usePureQtImplementation();
|
||||||
Q_NODISCARD Global::SystemTheme systemTheme() const;
|
Q_NODISCARD Global::SystemTheme systemTheme() const;
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void addWindow(const Global::UserSettings &settings, const Global::SystemParameters ¶ms);
|
static void addWindow(const Global::UserSettings &settings, const Global::SystemParameters ¶ms);
|
||||||
void notifySystemThemeHasChangedOrNot();
|
void notifySystemThemeHasChangedOrNot();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -1,31 +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 "utils.h"
|
|
||||||
|
|
||||||
FRAMELESSHELPER_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
FRAMELESSHELPER_END_NAMESPACE
|
|
|
@ -0,0 +1,250 @@
|
||||||
|
/*
|
||||||
|
* 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 "utils.h"
|
||||||
|
#include <QtCore/qdebug.h>
|
||||||
|
#include <QtCore/qhash.h>
|
||||||
|
#include <QtGui/qwindow.h>
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
#include <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
FRAMELESSHELPER_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
using namespace Global;
|
||||||
|
|
||||||
|
[[nodiscard]] bool shouldAppsUseDarkMode_macos()
|
||||||
|
{
|
||||||
|
#if QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14)
|
||||||
|
if (__builtin_available(macOS 10.14, *)) {
|
||||||
|
const auto appearance = [NSApp.effectiveAppearance bestMatchFromAppearancesWithNames:
|
||||||
|
@[NSAppearanceNameAqua, NSAppearanceNameDarkAqua]];
|
||||||
|
return [appearance isEqualToString:NSAppearanceNameDarkAqua];
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class NSWindowProxy
|
||||||
|
{
|
||||||
|
Q_DISABLE_COPY_MOVE(NSWindowProxy)
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit NSWindowProxy(NSWindow *window)
|
||||||
|
{
|
||||||
|
Q_ASSERT(window);
|
||||||
|
if (!window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nswindow = window;
|
||||||
|
saveState();
|
||||||
|
}
|
||||||
|
|
||||||
|
~NSWindowProxy()
|
||||||
|
{
|
||||||
|
restoreState();
|
||||||
|
nswindow = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveState()
|
||||||
|
{
|
||||||
|
oldStyleMask = nswindow.styleMask;
|
||||||
|
oldTitlebarAppearsTransparent = nswindow.titlebarAppearsTransparent;
|
||||||
|
oldTitleVisibility = nswindow.titleVisibility;
|
||||||
|
oldHasShadow = nswindow.hasShadow;
|
||||||
|
oldShowsToolbarButton = nswindow.showsToolbarButton;
|
||||||
|
oldMovableByWindowBackground = nswindow.movableByWindowBackground;
|
||||||
|
oldMovable = nswindow.movable;
|
||||||
|
oldCloseButtonVisible = ![nswindow standardWindowButton:NSWindowCloseButton].hidden;
|
||||||
|
oldMiniaturizeButtonVisible = ![nswindow standardWindowButton:NSWindowMiniaturizeButton].hidden;
|
||||||
|
oldZoomButtonVisible = ![nswindow standardWindowButton:NSWindowZoomButton].hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreState()
|
||||||
|
{
|
||||||
|
nswindow.styleMask = oldStyleMask;
|
||||||
|
nswindow.titlebarAppearsTransparent = oldTitlebarAppearsTransparent;
|
||||||
|
nswindow.titleVisibility = oldTitleVisibility;
|
||||||
|
nswindow.hasShadow = oldHasShadow;
|
||||||
|
nswindow.showsToolbarButton = oldShowsToolbarButton;
|
||||||
|
nswindow.movableByWindowBackground = oldMovableByWindowBackground;
|
||||||
|
nswindow.movable = oldMovable;
|
||||||
|
[nswindow standardWindowButton:NSWindowCloseButton].hidden = !oldCloseButtonVisible;
|
||||||
|
[nswindow standardWindowButton:NSWindowMiniaturizeButton].hidden = !oldMiniaturizeButtonVisible;
|
||||||
|
[nswindow standardWindowButton:NSWindowZoomButton].hidden = !oldZoomButtonVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeWindowFrame()
|
||||||
|
{
|
||||||
|
NSView *nsview = [nswindow contentView];
|
||||||
|
Q_ASSERT(nsview);
|
||||||
|
if (!nsview) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nsview.wantsLayer = YES;
|
||||||
|
nswindow.styleMask |= NSWindowStyleMaskFullSizeContentView;
|
||||||
|
nswindow.titlebarAppearsTransparent = true;
|
||||||
|
nswindow.titleVisibility = NSWindowTitleHidden;
|
||||||
|
nswindow.hasShadow = true;
|
||||||
|
nswindow.showsToolbarButton = false;
|
||||||
|
nswindow.movableByWindowBackground = false;
|
||||||
|
nswindow.movable = false;
|
||||||
|
[nswindow standardWindowButton:NSWindowCloseButton].hidden = true;
|
||||||
|
[nswindow standardWindowButton:NSWindowMiniaturizeButton].hidden = true;
|
||||||
|
[nswindow standardWindowButton:NSWindowZoomButton].hidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
NSWindow *nswindow;
|
||||||
|
|
||||||
|
NSWindowStyleMask oldStyleMask;
|
||||||
|
BOOL oldTitlebarAppearsTransparent;
|
||||||
|
BOOL oldHasShadow;
|
||||||
|
BOOL oldShowsToolbarButton;
|
||||||
|
BOOL oldMovableByWindowBackground;
|
||||||
|
BOOL oldMovable;
|
||||||
|
BOOL oldCloseButtonVisible;
|
||||||
|
BOOL oldMiniaturizeButtonVisible;
|
||||||
|
BOOL oldZoomButtonVisible;
|
||||||
|
NSWindowTitleVisibility oldTitleVisibility;
|
||||||
|
};
|
||||||
|
|
||||||
|
using NSWindowProxyHash = QHash<WId, NSWindowProxy *>;
|
||||||
|
Q_GLOBAL_STATIC(NSWindowProxyHash, g_nswindowOverrideHash);
|
||||||
|
|
||||||
|
[[nodiscard]] static inline NSWindow *mac_getNSWindow(const WId windowId)
|
||||||
|
{
|
||||||
|
Q_ASSERT(windowId);
|
||||||
|
if (!windowId) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const auto nsview = reinterpret_cast<NSView *>(windowId);
|
||||||
|
Q_ASSERT(nsview);
|
||||||
|
if (!nsview) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return [nsview window];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mac_windowStartNativeDrag(const WId windowId, const QPoint &globalPos)
|
||||||
|
{
|
||||||
|
Q_ASSERT(windowId);
|
||||||
|
if (!windowId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const NSWindow * const nswindow = mac_getNSWindow(windowId);
|
||||||
|
if (!nswindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const CGEventRef clickDown = CGEventCreateMouseEvent(
|
||||||
|
NULL, kCGEventLeftMouseDown, CGPointMake(globalPos.x(), globalPos.y()), kCGMouseButtonLeft);
|
||||||
|
NSEvent * const nsevent = [NSEvent eventWithCGEvent:clickDown];
|
||||||
|
Q_ASSERT(nsevent);
|
||||||
|
if (!nsevent) {
|
||||||
|
CFRelease(clickDown);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
[nswindow performWindowDragWithEvent:nsevent];
|
||||||
|
CFRelease(clickDown);
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemTheme Utils::getSystemTheme()
|
||||||
|
{
|
||||||
|
// ### TODO: how to detect high contrast mode on macOS?
|
||||||
|
return (shouldAppsUseDarkMode() ? SystemTheme::Dark : SystemTheme::Light);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::setWindowHook(const WId windowId)
|
||||||
|
{
|
||||||
|
Q_ASSERT(windowId);
|
||||||
|
if (!windowId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (g_nswindowOverrideHash()->contains(windowId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSWindow * const nswindow = mac_getNSWindow(windowId);
|
||||||
|
if (!nswindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto proxy = new NSWindowProxy(nswindow);
|
||||||
|
g_nswindowOverrideHash()->insert(windowId, proxy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::unsetWindowHook(const WId windowId)
|
||||||
|
{
|
||||||
|
Q_ASSERT(windowId);
|
||||||
|
if (!windowId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!g_nswindowOverrideHash()->contains(windowId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const NSWindowProxy * const proxy = g_nswindowOverrideHash()->value(windowId);
|
||||||
|
g_nswindowOverrideHash()->remove(windowId);
|
||||||
|
Q_ASSERT(proxy);
|
||||||
|
if (!proxy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
delete proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::removeWindowFrame(const WId windowId)
|
||||||
|
{
|
||||||
|
Q_ASSERT(windowId);
|
||||||
|
if (!windowId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!g_nswindowOverrideHash()->contains(windowId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSWindowProxy * const proxy = g_nswindowOverrideHash()->value(windowId);
|
||||||
|
Q_ASSERT(proxy);
|
||||||
|
if (!proxy) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
proxy->removeWindowFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::startSystemMove(QWindow *window, const QPoint &globalPos)
|
||||||
|
{
|
||||||
|
Q_ASSERT(window);
|
||||||
|
if (!window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mac_windowStartNativeDrag(window->winId(), globalPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoint &globalPos)
|
||||||
|
{
|
||||||
|
Q_ASSERT(window);
|
||||||
|
if (!window) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (edges == Qt::Edges{}) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mac_windowStartNativeDrag(window->winId(), globalPos);
|
||||||
|
}
|
||||||
|
|
||||||
|
FRAMELESSHELPER_END_NAMESPACE
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
#include "framelessquickwindow.h"
|
#include "framelessquickwindow.h"
|
||||||
#include "framelessquickwindow_p.h"
|
#include "framelessquickwindow_p.h"
|
||||||
|
#include <QtGui/qcursor.h>
|
||||||
#include <QtQuick/private/qquickitem_p.h>
|
#include <QtQuick/private/qquickitem_p.h>
|
||||||
#include <QtQuick/private/qquickrectangle_p.h>
|
#include <QtQuick/private/qquickrectangle_p.h>
|
||||||
#include <QtQuick/private/qquickanchors_p.h>
|
#include <QtQuick/private/qquickanchors_p.h>
|
||||||
|
@ -373,11 +374,7 @@ void FramelessQuickWindowPrivate::showSystemMenu(const QPoint &pos)
|
||||||
void FramelessQuickWindowPrivate::startSystemMove2()
|
void FramelessQuickWindowPrivate::startSystemMove2()
|
||||||
{
|
{
|
||||||
Q_Q(FramelessQuickWindow);
|
Q_Q(FramelessQuickWindow);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
Utils::startSystemMove(q, QCursor::pos(q->screen()));
|
||||||
q->startSystemMove();
|
|
||||||
#else
|
|
||||||
Utils::startSystemMove(q);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramelessQuickWindowPrivate::startSystemResize2(const Qt::Edges edges)
|
void FramelessQuickWindowPrivate::startSystemResize2(const Qt::Edges edges)
|
||||||
|
@ -389,11 +386,7 @@ void FramelessQuickWindowPrivate::startSystemResize2(const Qt::Edges edges)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Q_Q(FramelessQuickWindow);
|
Q_Q(FramelessQuickWindow);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
Utils::startSystemResize(q, edges, QCursor::pos(q->screen()));
|
||||||
q->startSystemResize(edges);
|
|
||||||
#else
|
|
||||||
Utils::startSystemResize(q, edges);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramelessQuickWindowPrivate::initialize()
|
void FramelessQuickWindowPrivate::initialize()
|
||||||
|
@ -403,12 +396,7 @@ void FramelessQuickWindowPrivate::initialize()
|
||||||
}
|
}
|
||||||
m_initialized = true;
|
m_initialized = true;
|
||||||
Q_Q(FramelessQuickWindow);
|
Q_Q(FramelessQuickWindow);
|
||||||
const WId windowId = q->winId();
|
m_params.getWindowId = [q]() -> WId { return q->winId(); };
|
||||||
Q_ASSERT(windowId);
|
|
||||||
if (!windowId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_params.windowId = windowId;
|
|
||||||
m_params.getWindowFlags = [q]() -> Qt::WindowFlags { return q->flags(); };
|
m_params.getWindowFlags = [q]() -> Qt::WindowFlags { return q->flags(); };
|
||||||
m_params.setWindowFlags = [q](const Qt::WindowFlags flags) -> void { q->setFlags(flags); };
|
m_params.setWindowFlags = [q](const Qt::WindowFlags flags) -> void { q->setFlags(flags); };
|
||||||
m_params.getWindowSize = [q]() -> QSize { return q->size(); };
|
m_params.getWindowSize = [q]() -> QSize { return q->size(); };
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include <QtCore/qdebug.h>
|
#include <QtCore/qdebug.h>
|
||||||
#include <QtGui/qpainter.h>
|
#include <QtGui/qpainter.h>
|
||||||
#include <QtGui/qevent.h>
|
#include <QtGui/qevent.h>
|
||||||
|
#include <QtGui/qcursor.h>
|
||||||
#include <QtWidgets/qboxlayout.h>
|
#include <QtWidgets/qboxlayout.h>
|
||||||
#include <QtWidgets/qlabel.h>
|
#include <QtWidgets/qlabel.h>
|
||||||
#include <framelesswindowsmanager.h>
|
#include <framelesswindowsmanager.h>
|
||||||
|
@ -356,17 +357,7 @@ void FramelessWidgetsHelper::initialize()
|
||||||
// Force the widget become a native window now so that we can deal with its
|
// Force the widget become a native window now so that we can deal with its
|
||||||
// win32 events as soon as possible.
|
// win32 events as soon as possible.
|
||||||
q->setAttribute(Qt::WA_NativeWindow);
|
q->setAttribute(Qt::WA_NativeWindow);
|
||||||
const WId windowId = q->winId();
|
m_params.getWindowId = [this]() -> WId { return q->winId(); };
|
||||||
Q_ASSERT(windowId);
|
|
||||||
if (!windowId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_window = q->windowHandle();
|
|
||||||
Q_ASSERT(m_window);
|
|
||||||
if (!m_window) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_params.windowId = windowId;
|
|
||||||
m_params.getWindowFlags = [this]() -> Qt::WindowFlags { return q->windowFlags(); };
|
m_params.getWindowFlags = [this]() -> Qt::WindowFlags { return q->windowFlags(); };
|
||||||
m_params.setWindowFlags = [this](const Qt::WindowFlags flags) -> void { q->setWindowFlags(flags); };
|
m_params.setWindowFlags = [this](const Qt::WindowFlags flags) -> void { q->setWindowFlags(flags); };
|
||||||
m_params.getWindowSize = [this]() -> QSize { return q->size(); };
|
m_params.getWindowSize = [this]() -> QSize { return q->size(); };
|
||||||
|
@ -377,14 +368,14 @@ void FramelessWidgetsHelper::initialize()
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
||||||
return q->screen();
|
return q->screen();
|
||||||
#else
|
#else
|
||||||
return m_window->screen();
|
return q->windowHandle()->screen();
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
m_params.isWindowFixedSize = [this]() -> bool { return isFixedSize(); };
|
m_params.isWindowFixedSize = [this]() -> bool { return isFixedSize(); };
|
||||||
m_params.setWindowFixedSize = [this](const bool value) -> void { setFixedSize(value); };
|
m_params.setWindowFixedSize = [this](const bool value) -> void { setFixedSize(value); };
|
||||||
m_params.getWindowState = [this]() -> Qt::WindowState { return Utils::windowStatesToWindowState(q->windowState()); };
|
m_params.getWindowState = [this]() -> Qt::WindowState { return Utils::windowStatesToWindowState(q->windowState()); };
|
||||||
m_params.setWindowState = [this](const Qt::WindowState state) -> void { q->setWindowState(state); };
|
m_params.setWindowState = [this](const Qt::WindowState state) -> void { q->setWindowState(state); };
|
||||||
m_params.getWindowHandle = [this]() -> QWindow * { return m_window; };
|
m_params.getWindowHandle = [this]() -> QWindow * { return q->windowHandle(); };
|
||||||
m_params.windowToScreen = [this](const QPoint &pos) -> QPoint { return q->mapToGlobal(pos); };
|
m_params.windowToScreen = [this](const QPoint &pos) -> QPoint { return q->mapToGlobal(pos); };
|
||||||
m_params.screenToWindow = [this](const QPoint &pos) -> QPoint { return q->mapFromGlobal(pos); };
|
m_params.screenToWindow = [this](const QPoint &pos) -> QPoint { return q->mapFromGlobal(pos); };
|
||||||
m_params.isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { return isInSystemButtons(pos, button); };
|
m_params.isInsideSystemButtons = [this](const QPoint &pos, SystemButtonType *button) -> bool { return isInSystemButtons(pos, button); };
|
||||||
|
@ -474,7 +465,7 @@ void FramelessWidgetsHelper::initialize()
|
||||||
}
|
}
|
||||||
QMetaObject::invokeMethod(q, "systemThemeChanged");
|
QMetaObject::invokeMethod(q, "systemThemeChanged");
|
||||||
});
|
});
|
||||||
connect(m_window, &QWindow::visibilityChanged, this, [this](){
|
connect(q->windowHandle(), &QWindow::visibilityChanged, this, [this](){
|
||||||
QMetaObject::invokeMethod(q, "hiddenChanged");
|
QMetaObject::invokeMethod(q, "hiddenChanged");
|
||||||
QMetaObject::invokeMethod(q, "normalChanged");
|
QMetaObject::invokeMethod(q, "normalChanged");
|
||||||
QMetaObject::invokeMethod(q, "zoomedChanged");
|
QMetaObject::invokeMethod(q, "zoomedChanged");
|
||||||
|
@ -787,20 +778,14 @@ void FramelessWidgetsHelper::showSystemMenu(const QPoint &pos)
|
||||||
|
|
||||||
void FramelessWidgetsHelper::startSystemMove2()
|
void FramelessWidgetsHelper::startSystemMove2()
|
||||||
{
|
{
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
QWindow * const window = q->windowHandle();
|
||||||
m_window->startSystemMove();
|
Utils::startSystemMove(window, QCursor::pos(window->screen()));
|
||||||
#else
|
|
||||||
Utils::startSystemMove(m_window);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FramelessWidgetsHelper::startSystemResize2(const Qt::Edges edges)
|
void FramelessWidgetsHelper::startSystemResize2(const Qt::Edges edges)
|
||||||
{
|
{
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
QWindow * const window = q->windowHandle();
|
||||||
m_window->startSystemResize(edges);
|
Utils::startSystemResize(window, edges, QCursor::pos(window->screen()));
|
||||||
#else
|
|
||||||
Utils::startSystemResize(m_window, edges);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FramelessWidgetsHelper::eventFilter(QObject *object, QEvent *event)
|
bool FramelessWidgetsHelper::eventFilter(QObject *object, QEvent *event)
|
||||||
|
|
Loading…
Reference in New Issue