Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-03-22 15:03:22 +08:00
parent 6a43ef39f8
commit 5ecc06df2f
11 changed files with 206 additions and 17 deletions

View File

@ -34,12 +34,6 @@ FramelessWindow {
height: 600
title: qsTr("Hello, World! - Qt Quick")
color: FramelessUtils.darkModeEnabled ? FramelessUtils.defaultSystemDarkColor : FramelessUtils.defaultSystemLightColor
Component.onCompleted: {
FramelessHelper.setTitleBarItem(window, titleBar);
FramelessHelper.setHitTestVisible(window, minimizeButton, true);
FramelessHelper.setHitTestVisible(window, maximizeButton, true);
FramelessHelper.setHitTestVisible(window, closeButton, true);
}
Timer {
interval: 500
@ -62,12 +56,12 @@ FramelessWindow {
id: titleBar
anchors {
top: parent.top
topMargin: window.windowTopBorder.height
topMargin: 1
left: parent.left
right: parent.right
}
active: window.active
maximized: (window.visibility === Window.Maximized) || (window.visibility === Window.FullScreen)
maximized: window.zoomed
title: window.title
minimizeButton {
id: minimizeButton
@ -81,5 +75,11 @@ FramelessWindow {
id: closeButton
onClicked: window.close()
}
Component.onCompleted: {
FramelessHelper.setTitleBarItem(window, titleBar);
FramelessHelper.setHitTestVisible(window, minimizeButton, true);
FramelessHelper.setHitTestVisible(window, maximizeButton, true);
FramelessHelper.setHitTestVisible(window, closeButton, true);
}
}
}

View File

@ -118,6 +118,8 @@ Q_NAMESPACE_EXPORT(FRAMELESSHELPER_CORE_API)
[[maybe_unused]] static const QString kForceHideFrameBorderKeyPath = QStringLiteral("Options/ForceHideFrameBorder");
[[maybe_unused]] static const QString kForceShowFrameBorderKeyPath = QStringLiteral("Options/ForceShowFrameBorder");
[[maybe_unused]] static constexpr const QSize kInvalidWindowSize = {160, 160};
enum class Option : int
{
Default = 0x00000000, // Default placeholder, have no effect.
@ -136,7 +138,8 @@ enum class Option : int
NoDoubleClickMaximizeToggle = 0x00001000, // Don't toggle the maximize state when double clicks the titlebar.
DisableResizing = 0x00002000, // Disable resizing of the window.
DisableDragging = 0x00004000, // Disable dragging through the titlebar of the window.
DontTouchCursorShape = 0x00008000 // Don't change the cursor shape while the mouse is hovering above the window.
DontTouchCursorShape = 0x00008000, // Don't change the cursor shape while the mouse is hovering above the window.
DontMoveWindowToDesktopCenter = 0x00010000 // Don't move the window to the desktop center before shown.
};
Q_DECLARE_FLAGS(Options, Option)
Q_FLAG_NS(Options)

View File

@ -79,6 +79,7 @@ FRAMELESSHELPER_CORE_API void startSystemResize(QWindow *window, const Qt::Edges
(const SystemButtonType button, const SystemTheme theme, const ResourceType type);
FRAMELESSHELPER_CORE_API void sendMouseReleaseEvent();
[[nodiscard]] FRAMELESSHELPER_CORE_API QWindow *findWindow(const WId winId);
FRAMELESSHELPER_CORE_API void moveWindowToDesktopCenter(QWindow *window, const bool considerTaskBar);
#ifdef Q_OS_WINDOWS
[[nodiscard]] FRAMELESSHELPER_CORE_API bool isWin8OrGreater();

View File

@ -29,14 +29,26 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessQuickWindowPrivate;
class FRAMELESSHELPER_QUICK_API FramelessQuickWindow : public QQuickWindow
{
Q_OBJECT
Q_DECLARE_PRIVATE(FramelessQuickWindow)
Q_DISABLE_COPY_MOVE(FramelessQuickWindow)
Q_PROPERTY(bool zoomed READ zoomed NOTIFY zoomedChanged FINAL)
public:
explicit FramelessQuickWindow(QWindow *parent = nullptr);
~FramelessQuickWindow() override;
Q_NODISCARD bool zoomed() const;
Q_SIGNALS:
void zoomedChanged();
private:
QScopedPointer<FramelessQuickWindowPrivate> d_ptr;
};
FRAMELESSHELPER_END_NAMESPACE

View File

@ -58,6 +58,15 @@ FramelessWindowsManagerPrivate *FramelessWindowsManagerPrivate::get(FramelessWin
return manager->d_func();
}
const FramelessWindowsManagerPrivate *FramelessWindowsManagerPrivate::get(const FramelessWindowsManager *manager)
{
Q_ASSERT(manager);
if (!manager) {
return nullptr;
}
return manager->d_func();
}
bool FramelessWindowsManagerPrivate::usePureQtImplementation() const
{
#ifdef Q_OS_WINDOWS
@ -188,6 +197,7 @@ void FramelessWindowsManager::addWindow(QWindow *window)
}
#endif
d->mutex.unlock();
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
if (pureQt) {
FramelessHelperQt::addWindow(window);
}
@ -195,11 +205,13 @@ void FramelessWindowsManager::addWindow(QWindow *window)
if (!pureQt) {
FramelessHelperWin::addWindow(window);
}
const auto options = qvariant_cast<Options>(window->property(kInternalOptionsFlag));
if (!(options & Option::DontInstallSystemMenuHook)) {
Utils::installSystemMenuHook(window);
}
#endif
if (!(options & Option::DontMoveWindowToDesktopCenter)) {
Utils::moveWindowToDesktopCenter(window, true);
}
}
void FramelessWindowsManager::removeWindow(QWindow *window)

View File

@ -44,6 +44,7 @@ public:
~FramelessWindowsManagerPrivate();
[[nodiscard]] static FramelessWindowsManagerPrivate *get(FramelessWindowsManager *manager);
[[nodiscard]] static const FramelessWindowsManagerPrivate *get(const FramelessWindowsManager *manager);
[[nodiscard]] bool usePureQtImplementation() const;

View File

@ -26,6 +26,7 @@
#include <QtCore/qvariant.h>
#include <QtGui/qwindow.h>
#include <QtGui/qguiapplication.h>
#include <QtGui/qscreen.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
@ -171,4 +172,30 @@ QWindow *Utils::findWindow(const WId winId)
return nullptr;
}
void Utils::moveWindowToDesktopCenter(QWindow *window, const bool considerTaskBar)
{
Q_ASSERT(window);
if (!window) {
return;
}
const QSize windowSize = window->size();
if (windowSize.isEmpty() || (windowSize == kInvalidWindowSize)) {
return;
}
const QScreen * const screen = [window]() -> const QScreen * {
const QScreen * const s = window->screen();
return (s ? s : QGuiApplication::primaryScreen());
}();
Q_ASSERT(screen);
if (!screen) {
return;
}
const QSize screenSize = (considerTaskBar ? screen->availableSize() : screen->size());
const QPoint offset = (considerTaskBar ? screen->availableGeometry().topLeft() : QPoint(0, 0));
const auto newX = static_cast<int>(qRound(qreal(screenSize.width() - windowSize.width()) / 2.0));
const auto newY = static_cast<int>(qRound(qreal(screenSize.height() - windowSize.height()) / 2.0));
window->setX(newX + offset.x());
window->setY(newY + offset.y());
}
FRAMELESSHELPER_END_NAMESPACE

View File

@ -10,6 +10,7 @@ set(SOURCES
${INCLUDE_PREFIX}/framelessquickeventfilter.h
${INCLUDE_PREFIX}/framelesshelper_quick.h
${INCLUDE_PREFIX}/framelessquickwindow.h
framelessquickwindow_p.h
framelesshelperquick.qrc
framelesshelper_quick.cpp
framelessquickhelper.cpp

View File

@ -23,11 +23,78 @@
*/
#include "framelessquickwindow.h"
#include "framelessquickwindow_p.h"
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/private/qquickanchors_p.h>
#include <framelesswindowsmanager.h>
#include <utils.h>
FRAMELESSHELPER_BEGIN_NAMESPACE
FramelessQuickWindow::FramelessQuickWindow(QWindow *parent) : QQuickWindow(parent) {}
FramelessQuickWindowPrivate::FramelessQuickWindowPrivate(FramelessQuickWindow *q) : QObject(q)
{
Q_ASSERT(q);
if (!q) {
return;
}
q_ptr = q;
initialize();
}
FramelessQuickWindowPrivate::~FramelessQuickWindowPrivate() = default;
bool FramelessQuickWindowPrivate::isZoomed() const
{
Q_Q(const FramelessQuickWindow);
const FramelessQuickWindow::Visibility visibility = q->visibility();
return ((visibility == FramelessQuickWindow::Maximized) || (visibility == FramelessQuickWindow::FullScreen));
}
void FramelessQuickWindowPrivate::initialize()
{
Q_Q(FramelessQuickWindow);
FramelessWindowsManager * const manager = FramelessWindowsManager::instance();
manager->addWindow(q);
QQuickItem * const rootItem = q->contentItem();
const QQuickItemPrivate * const rootItemPrivate = QQuickItemPrivate::get(rootItem);
m_topBorderRectangle.reset(new QQuickRectangle(rootItem));
updateTopBorderHeight();
updateTopBorderColor();
connect(q, &FramelessQuickWindow::visibilityChanged, this, &FramelessQuickWindowPrivate::updateTopBorderHeight);
connect(q, &FramelessQuickWindow::activeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor);
connect(manager, &FramelessWindowsManager::systemThemeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor);
const auto topBorderAnchors = new QQuickAnchors(m_topBorderRectangle.data(), m_topBorderRectangle.data());
topBorderAnchors->setTop(rootItemPrivate->top());
topBorderAnchors->setLeft(rootItemPrivate->left());
topBorderAnchors->setRight(rootItemPrivate->right());
connect(q, &FramelessQuickWindow::visibilityChanged, q, &FramelessQuickWindow::zoomedChanged);
}
void FramelessQuickWindowPrivate::updateTopBorderColor()
{
Q_Q(FramelessQuickWindow);
m_topBorderRectangle->setColor(Utils::getFrameBorderColor(q->isActive()));
}
void FramelessQuickWindowPrivate::updateTopBorderHeight()
{
Q_Q(FramelessQuickWindow);
const qreal newHeight = ((q->visibility() == FramelessQuickWindow::Windowed) ? 1.0 : 0.0);
m_topBorderRectangle->setHeight(newHeight);
}
FramelessQuickWindow::FramelessQuickWindow(QWindow *parent) : QQuickWindow(parent)
{
d_ptr.reset(new FramelessQuickWindowPrivate(this));
}
FramelessQuickWindow::~FramelessQuickWindow() = default;
bool FramelessQuickWindow::zoomed() const
{
Q_D(const FramelessQuickWindow);
return d->isZoomed();
}
FRAMELESSHELPER_END_NAMESPACE

View File

@ -0,0 +1,62 @@
/*
* 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>
QT_BEGIN_NAMESPACE
class QQuickRectangle;
QT_END_NAMESPACE
FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessQuickWindow;
class FRAMELESSHELPER_QUICK_API FramelessQuickWindowPrivate : public QObject
{
Q_OBJECT
Q_DECLARE_PUBLIC(FramelessQuickWindow)
Q_DISABLE_COPY_MOVE(FramelessQuickWindowPrivate)
public:
explicit FramelessQuickWindowPrivate(FramelessQuickWindow *q);
~FramelessQuickWindowPrivate() override;
Q_NODISCARD bool isZoomed() const;
private:
void initialize();
private Q_SLOTS:
void updateTopBorderColor();
void updateTopBorderHeight();
private:
FramelessQuickWindow *q_ptr = nullptr;
QScopedPointer<QQuickRectangle> m_topBorderRectangle;
};
FRAMELESSHELPER_END_NAMESPACE

View File

@ -36,6 +36,8 @@
FRAMELESSHELPER_BEGIN_NAMESPACE
static constexpr const char QT_MAINWINDOW_CLASS_NAME[] = "QMainWindow";
static const QString kSystemButtonStyleSheet = QStringLiteral(R"(
QPushButton {
border-style: none;
@ -54,11 +56,12 @@ QPushButton:pressed {
FramelessWidgetsHelper::FramelessWidgetsHelper(QWidget *q, const Options options) : QObject(q)
{
Q_ASSERT(q);
if (q) {
this->q = q;
m_options = options;
initialize();
if (!q) {
return;
}
this->q = q;
m_options = options;
initialize();
}
FramelessWidgetsHelper::~FramelessWidgetsHelper() = default;
@ -299,7 +302,7 @@ void FramelessWidgetsHelper::initialize()
}
window->setProperty(kInternalOptionsFlag, QVariant::fromValue(m_options));
if (m_options & Option::UseStandardWindowLayout) {
if (q->inherits("QMainWindow")) {
if (q->inherits(QT_MAINWINDOW_CLASS_NAME)) {
m_options &= ~Options(Option::UseStandardWindowLayout);
qWarning() << "\"Option::UseStandardWindowLayout\" is not compatible with QMainWindow and it's subclasses."
" Enabling this option will mess up with your main window's layout.";
@ -310,7 +313,7 @@ void FramelessWidgetsHelper::initialize()
Q_ASSERT(window->flags() & Qt::FramelessWindowHint);
}
FramelessWindowsManager *manager = FramelessWindowsManager::instance();
manager->addWindow(q->windowHandle());
manager->addWindow(window);
connect(manager, &FramelessWindowsManager::systemThemeChanged, this, [this](){
if (m_options & Option::UseStandardWindowLayout) {
updateSystemTitleBarStyleSheet();