Add WindowBorderPainter and WindowBorder

1. Added WindowBorderPainter for QtWidgets
2. Added WindowBorder for QtQuick (uses WindowBorderPainter internally)
3. Adjust some header includes
4. Limit a Linux workaround to the appropriate Qt versions

Signed-off-by: Yuhang Zhao <2546789017@qq.com>
This commit is contained in:
Yuhang Zhao 2022-10-08 16:14:40 +08:00
parent 9f17c8afdd
commit 92415fb61c
75 changed files with 1106 additions and 203 deletions

View File

@ -46,7 +46,7 @@ FramelessWindow {
title: qsTr("FramelessHelper demo application - Qt Quick")
color: {
if (FramelessHelper.blurBehindWindowEnabled) {
return Qt.color("transparent");
return "transparent";
}
if (FramelessUtils.systemTheme === FramelessHelperConstants.Dark) {
return FramelessUtils.defaultSystemDarkColor;
@ -107,7 +107,8 @@ FramelessWindow {
StandardTitleBar {
id: titleBar
anchors {
top: window.topBorderBottom // VERY IMPORTANT!
top: parent.top
topMargin: window.visibility === Window.Windowed ? 1 : 0
left: parent.left
right: parent.right
}

View File

@ -24,14 +24,8 @@
#pragma once
#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 <framelesshelperquick_global.h>
QT_BEGIN_NAMESPACE
class QSettings;

View File

@ -0,0 +1 @@
#include <windowborderpainter.h>

View File

@ -25,8 +25,6 @@
#pragma once
#include "framelesshelpercore_global.h"
#include <QtCore/qobject.h>
#include <QtCore/qloggingcategory.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -25,8 +25,6 @@
#pragma once
#include "framelesshelpercore_global.h"
#include <QtCore/qobject.h>
#include <QtCore/qloggingcategory.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -26,7 +26,6 @@
#include "framelesshelpercore_global.h"
#include <QtCore/qabstractnativeeventfilter.h>
#include <QtCore/qloggingcategory.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -28,10 +28,14 @@
#include <QtCore/qpoint.h>
#include <QtCore/qsize.h>
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <QtCore/qloggingcategory.h>
#include <QtGui/qcolor.h>
#include <QtGui/qwindowdefs.h>
#include <functional>
#include <optional>
#include <memory>
#include <cmath>
QT_BEGIN_NAMESPACE
class QScreen;
@ -366,6 +370,19 @@ enum class RegistryRootKey
Q_ENUM_NS(RegistryRootKey)
#endif // Q_OS_WINDOWS
enum class WindowEdge
{
Unspecified = 0x00000000,
Left = 0x00000002,
Top = 0x00000004,
Right = 0x00000008,
Bottom = 0x00000010
};
Q_ENUM_NS(WindowEdge)
Q_DECLARE_FLAGS(WindowEdges, WindowEdge)
Q_FLAG_NS(WindowEdges)
Q_DECLARE_OPERATORS_FOR_FLAGS(WindowEdges)
struct VersionNumber
{
int major = 0;

View File

@ -25,8 +25,6 @@
#pragma once
#include "framelesshelpercore_global.h"
#include <QtCore/qobject.h>
#include <QtCore/qloggingcategory.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -25,8 +25,6 @@
#pragma once
#include "framelesshelpercore_global.h"
#include <QtCore/qobject.h>
#include <QtCore/qloggingcategory.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -26,9 +26,6 @@
#include "framelesshelpercore_global.h"
#include "chromepalette.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <optional>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -25,9 +25,7 @@
#pragma once
#include "framelesshelpercore_global.h"
#include <QtCore/qobject.h>
#include <QtCore/qvariant.h>
#include <optional>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -26,8 +26,6 @@
#include "framelesshelpercore_global.h"
#include "framelessmanager.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -26,8 +26,6 @@
#include "framelesshelpercore_global.h"
#include "micamaterial.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <QtGui/qbrush.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -25,9 +25,7 @@
#pragma once
#include "framelesshelpercore_global.h"
#include <QtCore/qobject.h>
#include <QtCore/qvariant.h>
#include <optional>
#ifndef REGISTRYKEY_FORCE_QSETTINGS
# define REGISTRYKEY_FORCE_QSETTINGS (0)

View File

@ -25,12 +25,9 @@
#pragma once
#include "framelesshelpercore_global.h"
#include <QtCore/qobject.h>
#include <QtCore/qhash.h>
#include <QtCore/qmutex.h>
#include <optional>
FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_CORE_API SysApiLoader : public QObject

View File

@ -0,0 +1,65 @@
/*
* 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 "windowborderpainter.h"
FRAMELESSHELPER_BEGIN_NAMESPACE
class FRAMELESSHELPER_CORE_API WindowBorderPainterPrivate : public QObject
{
Q_OBJECT
Q_DECLARE_PUBLIC(WindowBorderPainter)
Q_DISABLE_COPY_MOVE(WindowBorderPainterPrivate)
public:
explicit WindowBorderPainterPrivate(WindowBorderPainter *q);
~WindowBorderPainterPrivate() override;
Q_NODISCARD static WindowBorderPainterPrivate *get(WindowBorderPainter *q);
Q_NODISCARD static const WindowBorderPainterPrivate *get(const WindowBorderPainter *q);
Q_NODISCARD static int getNativeBorderThickness();
Q_NODISCARD static QColor getNativeBorderColor(const bool active);
Q_NODISCARD static Global::WindowEdges getNativeBorderEdges();
public Q_SLOTS:
void paint(QPainter *painter, const QSize &size, const bool active) const;
private:
void initialize();
private:
QPointer<WindowBorderPainter> q_ptr = nullptr;
std::optional<int> m_thickness = std::nullopt;
std::optional<Global::WindowEdges> m_edges = std::nullopt;
std::optional<QColor> m_activeColor = std::nullopt;
std::optional<QColor> m_inactiveColor = std::nullopt;
};
FRAMELESSHELPER_END_NAMESPACE
Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(WindowBorderPainterPrivate))

View File

@ -25,8 +25,6 @@
#pragma once
#include "framelesshelpercore_global.h"
#include <QtGui/qwindowdefs.h>
#include <QtCore/qloggingcategory.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -0,0 +1,86 @@
/*
* 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"
FRAMELESSHELPER_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcWindowBorderPainter)
class WindowBorderPainterPrivate;
class FRAMELESSHELPER_CORE_API WindowBorderPainter : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(WindowBorderPainter)
Q_DECLARE_PRIVATE(WindowBorderPainter)
Q_PROPERTY(int thickness READ thickness WRITE setThickness NOTIFY thicknessChanged FINAL)
Q_PROPERTY(Global::WindowEdges edges READ edges WRITE setEdges NOTIFY edgesChanged FINAL)
Q_PROPERTY(QColor activeColor READ activeColor WRITE setActiveColor NOTIFY activeColorChanged FINAL)
Q_PROPERTY(QColor inactiveColor READ inactiveColor WRITE setInactiveColor NOTIFY inactiveColorChanged FINAL)
Q_PROPERTY(int nativeThickness READ nativeThickness NOTIFY nativeBorderChanged FINAL)
Q_PROPERTY(Global::WindowEdges nativeEdges READ nativeEdges NOTIFY nativeBorderChanged FINAL)
Q_PROPERTY(QColor nativeActiveColor READ nativeActiveColor NOTIFY nativeBorderChanged FINAL)
Q_PROPERTY(QColor nativeInactiveColor READ nativeInactiveColor NOTIFY nativeBorderChanged FINAL)
public:
explicit WindowBorderPainter(QObject *parent = nullptr);
~WindowBorderPainter() override;
Q_NODISCARD int thickness() const;
Q_NODISCARD Global::WindowEdges edges() const;
Q_NODISCARD QColor activeColor() const;
Q_NODISCARD QColor inactiveColor() const;
Q_NODISCARD int nativeThickness() const;
Q_NODISCARD Global::WindowEdges nativeEdges() const;
Q_NODISCARD QColor nativeActiveColor() const;
Q_NODISCARD QColor nativeInactiveColor() const;
public Q_SLOTS:
void paint(QPainter *painter, const QSize &size, const bool active) const;
void setThickness(const int value);
void setEdges(const Global::WindowEdges value);
void setActiveColor(const QColor &value);
void setInactiveColor(const QColor &value);
Q_SIGNALS:
void thicknessChanged();
void edgesChanged();
void activeColorChanged();
void inactiveColorChanged();
void nativeBorderChanged();
void shouldRepaint();
private:
QScopedPointer<WindowBorderPainterPrivate> d_ptr;
};
FRAMELESSHELPER_END_NAMESPACE
Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(WindowBorderPainter))

View File

@ -0,0 +1 @@
#include <quickwindowborder.h>

View File

@ -25,11 +25,9 @@
#pragma once
#include <framelesshelpercore_global.h>
#include <QtCore/qloggingcategory.h>
#include <QtQml/qqml.h>
#if __has_include(<QtQml/qqmlregistration.h>)
# include <QtQml/qqmlregistration.h>
#else
# include <QtQml/qqml.h>
#endif
#ifndef FRAMELESSHELPER_QUICK_API
@ -186,7 +184,20 @@ public:
FRAMELESSHELPER_QUICK_ENUM_VALUE(BlurMode, Windows_Mica)
};
Q_ENUM(BlurMode)
enum class WindowEdge
{
FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowEdge, Unspecified)
FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowEdge, Left)
FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowEdge, Top)
FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowEdge, Right)
FRAMELESSHELPER_QUICK_ENUM_VALUE(WindowEdge, Bottom)
};
Q_ENUM(WindowEdge)
Q_DECLARE_FLAGS(WindowEdges, WindowEdge)
Q_FLAG(WindowEdges)
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QuickGlobal::WindowEdges)
namespace FramelessHelper::Quick
{

View File

@ -25,7 +25,6 @@
#pragma once
#include "framelesshelperquick_global.h"
#include <QtCore/qloggingcategory.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickwindow.h>
@ -34,6 +33,8 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcFramelessQuickHelper)
class FramelessQuickHelperPrivate;
class QuickMicaMaterial;
class QuickWindowBorder;
class FRAMELESSHELPER_QUICK_API FramelessQuickHelper : public QQuickItem
{
@ -64,6 +65,9 @@ public:
Q_NODISCARD bool isBlurBehindWindowEnabled() const;
Q_NODISCARD bool isContentExtendedIntoTitleBar() const;
Q_NODISCARD QuickMicaMaterial *micaMaterial() const;
Q_NODISCARD QuickWindowBorder *windowBorder() const;
public Q_SLOTS:
void extendsContentIntoTitleBar(const bool value = true);

View File

@ -25,7 +25,6 @@
#pragma once
#include "framelesshelperquick_global.h"
#include <QtCore/qloggingcategory.h>
QT_BEGIN_NAMESPACE
class QQmlEngine;

View File

@ -25,10 +25,6 @@
#pragma once
#include "framelesshelperquick_global.h"
#include <QtCore/qobject.h>
#include <QtCore/qloggingcategory.h>
#include <QtGui/qcolor.h>
#include <QtQml/qqml.h>
#include <QtQml/qqmlparserstatus.h>
QT_BEGIN_NAMESPACE

View File

@ -26,9 +26,6 @@
#include "framelesshelperquick_global.h"
#include "framelessquickhelper.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <optional>
QT_BEGIN_NAMESPACE
class QQuickItem;
@ -80,6 +77,9 @@ public:
void setProperty(const QByteArray &name, const QVariant &value);
Q_NODISCARD QVariant getProperty(const QByteArray &name, const QVariant &defaultValue = {});
Q_NODISCARD QuickMicaMaterial *findOrCreateMicaMaterial() const;
Q_NODISCARD QuickWindowBorder *findOrCreateWindowBorder() const;
protected:
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;

View File

@ -25,12 +25,9 @@
#pragma once
#include "framelesshelperquick_global.h"
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
#include <QtQml/qqmlparserstatus.h>
#include <QtQuick/qquickwindow.h>
Q_MOC_INCLUDE("framelessquickwindow_p_p.h")
FRAMELESSHELPER_BEGIN_NAMESPACE
class FramelessQuickWindowPrivate;
@ -49,7 +46,6 @@ class FRAMELESSHELPER_QUICK_API FramelessQuickWindow : public QQuickWindow, publ
Q_PROPERTY(bool maximized READ isMaximized NOTIFY maximizedChanged FINAL)
Q_PROPERTY(bool zoomed READ isZoomed NOTIFY zoomedChanged FINAL)
Q_PROPERTY(bool fullScreen READ isFullScreen NOTIFY fullScreenChanged FINAL)
Q_PRIVATE_PROPERTY(FramelessQuickWindow::d_func(), QQuickAnchorLine topBorderBottom READ getTopBorderBottom CONSTANT FINAL)
public:
explicit FramelessQuickWindow(QWindow *parent = nullptr);
@ -85,6 +81,5 @@ private:
FRAMELESSHELPER_END_NAMESPACE
Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickWindow))
Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickWindow))
QML_DECLARE_TYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickWindow))
#endif

View File

@ -25,18 +25,12 @@
#pragma once
#include "framelesshelperquick_global.h"
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
#include "framelessquickwindow_p.h"
#include <QtCore/qobject.h>
#include <QtQuick/qquickwindow.h>
#include <QtQuick/private/qquickanchors_p_p.h>
QT_BEGIN_NAMESPACE
class QQuickRectangle;
QT_END_NAMESPACE
FRAMELESSHELPER_BEGIN_NAMESPACE
class QuickWindowBorder;
class FRAMELESSHELPER_QUICK_API FramelessQuickWindowPrivate : public QObject
{
Q_OBJECT
@ -57,9 +51,6 @@ public:
Q_INVOKABLE Q_NODISCARD bool isZoomed() const;
Q_INVOKABLE Q_NODISCARD bool isFullScreen() const;
Q_INVOKABLE Q_NODISCARD QColor getFrameBorderColor() const;
Q_INVOKABLE Q_NODISCARD QQuickAnchorLine getTopBorderBottom() const;
public Q_SLOTS:
void showMinimized2();
void toggleMaximized();
@ -70,17 +61,14 @@ private:
Q_NODISCARD bool shouldDrawFrameBorder() const;
private Q_SLOTS:
void updateTopBorderColor();
void updateTopBorderHeight();
void updateWindowBorderVisibility();
private:
QPointer<FramelessQuickWindow> q_ptr = nullptr;
QScopedPointer<QQuickRectangle> m_topBorderRectangle;
QScopedPointer<QQuickAnchors> m_topBorderAnchors;
QScopedPointer<QuickWindowBorder> m_windowBorder;
QQuickWindow::Visibility m_savedVisibility = QQuickWindow::Windowed;
};
FRAMELESSHELPER_END_NAMESPACE
Q_DECLARE_METATYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickWindowPrivate))
#endif
Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(FramelessQuickWindowPrivate))

View File

@ -26,8 +26,6 @@
#include "framelesshelperquick_global.h"
#include "quickimageitem.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <QtCore/qvariant.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -26,8 +26,6 @@
#include "framelesshelperquick_global.h"
#include "quickmicamaterial.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -0,0 +1,59 @@
/*
* 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 "quickwindowborder.h"
FRAMELESSHELPER_BEGIN_NAMESPACE
class WindowBorderPainter;
class FRAMELESSHELPER_QUICK_API QuickWindowBorderPrivate : public QObject
{
Q_OBJECT
Q_DISABLE_COPY_MOVE(QuickWindowBorderPrivate)
Q_DECLARE_PUBLIC(QuickWindowBorder)
public:
explicit QuickWindowBorderPrivate(QuickWindowBorder *q);
~QuickWindowBorderPrivate() override;
Q_NODISCARD static QuickWindowBorderPrivate *get(QuickWindowBorder *q);
Q_NODISCARD static const QuickWindowBorderPrivate *get(const QuickWindowBorder *q);
void paint(QPainter *painter) const;
private:
void initialize();
private:
QPointer<QuickWindowBorder> q_ptr = nullptr;
QScopedPointer<WindowBorderPainter> m_borderPainter;
};
FRAMELESSHELPER_END_NAMESPACE
Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(QuickWindowBorderPrivate))

View File

@ -25,10 +25,8 @@
#pragma once
#include "framelesshelperquick_global.h"
#include <QtCore/qloggingcategory.h>
#include <QtQml/qqml.h>
#include <QtQml/qqmlparserstatus.h>
#include <chromepalette.h>
#include <QtQml/qqmlparserstatus.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -25,7 +25,6 @@
#pragma once
#include "framelesshelperquick_global.h"
#include <QtCore/qloggingcategory.h>
#include <QtQuick/qquickpainteditem.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -25,7 +25,6 @@
#pragma once
#include "framelesshelperquick_global.h"
#include <QtCore/qloggingcategory.h>
#include <QtQuick/qquickitem.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -0,0 +1,95 @@
/*
* 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 <QtQuick/qquickpainteditem.h>
FRAMELESSHELPER_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcQuickWindowBorder)
class QuickWindowBorderPrivate;
class FRAMELESSHELPER_QUICK_API QuickWindowBorder : public QQuickPaintedItem
{
Q_OBJECT
#ifdef QML_NAMED_ELEMENT
QML_NAMED_ELEMENT(WindowBorder)
#endif
Q_DISABLE_COPY_MOVE(QuickWindowBorder)
Q_DECLARE_PRIVATE(QuickWindowBorder)
Q_PROPERTY(qreal thickness READ thickness WRITE setThickness NOTIFY thicknessChanged FINAL)
Q_PROPERTY(QuickGlobal::WindowEdges edges READ edges WRITE setEdges NOTIFY edgesChanged FINAL)
Q_PROPERTY(QColor activeColor READ activeColor WRITE setActiveColor NOTIFY activeColorChanged FINAL)
Q_PROPERTY(QColor inactiveColor READ inactiveColor WRITE setInactiveColor NOTIFY inactiveColorChanged FINAL)
Q_PROPERTY(qreal nativeThickness READ nativeThickness NOTIFY nativeBorderChanged FINAL)
Q_PROPERTY(QuickGlobal::WindowEdges nativeEdges READ nativeEdges NOTIFY nativeBorderChanged FINAL)
Q_PROPERTY(QColor nativeActiveColor READ nativeActiveColor NOTIFY nativeBorderChanged FINAL)
Q_PROPERTY(QColor nativeInactiveColor READ nativeInactiveColor NOTIFY nativeBorderChanged FINAL)
public:
explicit QuickWindowBorder(QQuickItem *parent = nullptr);
~QuickWindowBorder() override;
void paint(QPainter *painter) override;
Q_NODISCARD qreal thickness() const;
Q_NODISCARD QuickGlobal::WindowEdges edges() const;
Q_NODISCARD QColor activeColor() const;
Q_NODISCARD QColor inactiveColor() const;
Q_NODISCARD qreal nativeThickness() const;
Q_NODISCARD QuickGlobal::WindowEdges nativeEdges() const;
Q_NODISCARD QColor nativeActiveColor() const;
Q_NODISCARD QColor nativeInactiveColor() const;
public Q_SLOTS:
void setThickness(const qreal value);
void setEdges(const QuickGlobal::WindowEdges value);
void setActiveColor(const QColor &value);
void setInactiveColor(const QColor &value);
protected:
void classBegin() override;
void componentComplete() override;
Q_SIGNALS:
void thicknessChanged();
void edgesChanged();
void activeColorChanged();
void inactiveColorChanged();
void nativeBorderChanged();
private:
QScopedPointer<QuickWindowBorderPrivate> d_ptr;
};
FRAMELESSHELPER_END_NAMESPACE
Q_DECLARE_METATYPE2(FRAMELESSHELPER_PREPEND_NAMESPACE(QuickWindowBorder))
QML_DECLARE_TYPE(FRAMELESSHELPER_PREPEND_NAMESPACE(QuickWindowBorder))

View File

@ -25,7 +25,6 @@
#pragma once
#include "framelesshelperwidgets_global.h"
#include <QtCore/qloggingcategory.h>
#include <QtWidgets/qdialog.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -25,7 +25,6 @@
#pragma once
#include <framelesshelpercore_global.h>
#include <QtCore/qloggingcategory.h>
#ifndef FRAMELESSHELPER_WIDGETS_API
# ifdef FRAMELESSHELPER_WIDGETS_STATIC

View File

@ -25,7 +25,6 @@
#pragma once
#include "framelesshelperwidgets_global.h"
#include <QtCore/qloggingcategory.h>
#include <QtWidgets/qmainwindow.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -25,7 +25,6 @@
#pragma once
#include "framelesshelperwidgets_global.h"
#include <QtCore/qloggingcategory.h>
#include <QtWidgets/qwidget.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -25,8 +25,6 @@
#pragma once
#include "framelesshelperwidgets_global.h"
#include <QtCore/qobject.h>
#include <QtCore/qloggingcategory.h>
#include <QtWidgets/qwidget.h>
FRAMELESSHELPER_BEGIN_NAMESPACE
@ -34,6 +32,8 @@ FRAMELESSHELPER_BEGIN_NAMESPACE
Q_DECLARE_LOGGING_CATEGORY(lcFramelessWidgetsHelper)
class FramelessWidgetsHelperPrivate;
class MicaMaterial;
class WindowBorderPainter;
class FRAMELESSHELPER_WIDGETS_API FramelessWidgetsHelper : public QObject
{
@ -58,6 +58,9 @@ public:
Q_NODISCARD QWidget *window() const;
Q_NODISCARD bool isContentExtendedIntoTitleBar() const;
Q_NODISCARD MicaMaterial *micaMaterial() const;
Q_NODISCARD WindowBorderPainter *windowBorder() const;
public Q_SLOTS:
void extendsContentIntoTitleBar(const bool value = true);

View File

@ -26,8 +26,6 @@
#include "framelesshelperwidgets_global.h"
#include "framelessdialog.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -26,8 +26,6 @@
#include "framelesshelperwidgets_global.h"
#include "framelessmainwindow.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -26,8 +26,6 @@
#include "framelesshelperwidgets_global.h"
#include "framelesswidget.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -26,8 +26,6 @@
#include "framelesshelperwidgets_global.h"
#include "framelesswidgetshelper.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
FRAMELESSHELPER_BEGIN_NAMESPACE
@ -77,6 +75,9 @@ public:
Q_NODISCARD QWidget *window() const;
Q_NODISCARD MicaMaterial *getMicaMaterialIfAny() const;
Q_NODISCARD WindowBorderPainter *getWindowBorderIfAny() const;
private:
Q_NODISCARD QRect mapWidgetGeometryToScene(const QWidget * const widget) const;
Q_NODISCARD bool isInSystemButtons(const QPoint &pos, Global::SystemButtonType *button) const;

View File

@ -26,9 +26,6 @@
#include "framelesshelperwidgets_global.h"
#include "standardsystembutton.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <optional>
QT_BEGIN_NAMESPACE
class QEnterEvent;

View File

@ -26,9 +26,6 @@
#include "framelesshelperwidgets_global.h"
#include "standardtitlebar.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <optional>
QT_BEGIN_NAMESPACE
class QPaintEvent;

View File

@ -25,8 +25,6 @@
#pragma once
#include "framelesshelperwidgets_global.h"
#include <QtCore/qobject.h>
#include <QtCore/qpointer.h>
#include <QtGui/qscreen.h>
QT_BEGIN_NAMESPACE
@ -36,6 +34,7 @@ QT_END_NAMESPACE
FRAMELESSHELPER_BEGIN_NAMESPACE
class MicaMaterial;
class WindowBorderPainter;
class FRAMELESSHELPER_WIDGETS_API WidgetsSharedHelper : public QObject
{
@ -52,6 +51,9 @@ public:
Q_NODISCARD bool isMicaEnabled() const;
void setMicaEnabled(const bool value);
Q_NODISCARD MicaMaterial *rawMicaMaterial() const;
Q_NODISCARD WindowBorderPainter *rawWindowBorder() const;
protected:
Q_NODISCARD bool eventFilter(QObject *object, QEvent *event) override;
@ -82,6 +84,9 @@ private:
QMetaObject::Connection m_micaRedrawConnection = {};
qreal m_screenDpr = 0.0;
QMetaObject::Connection m_screenDpiChangeConnection = {};
QScopedPointer<WindowBorderPainter> m_borderPainter;
QMetaObject::Connection m_borderRepaintConnection = {};
QMetaObject::Connection m_screenChangeConnection = {};
};
FRAMELESSHELPER_END_NAMESPACE

View File

@ -25,7 +25,6 @@
#pragma once
#include "framelesshelperwidgets_global.h"
#include <QtCore/qloggingcategory.h>
#include <QtWidgets/qabstractbutton.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -27,7 +27,6 @@
#include "framelesshelperwidgets_global.h"
#include "standardsystembutton.h"
#include <chromepalette.h>
#include <QtCore/qloggingcategory.h>
#include <QtWidgets/qwidget.h>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -26,11 +26,13 @@ HEADERS += \
$$CORE_PUB_INC_DIR/framelessmanager.h \
$$CORE_PUB_INC_DIR/micamaterial.h \
$$CORE_PUB_INC_DIR/utils.h \
$$CORE_PUB_INC_DIR/windowborderpainter.h \
$$CORE_PRIV_INC_DIR/chromepalette_p.h \
$$CORE_PRIV_INC_DIR/framelessconfig_p.h \
$$CORE_PRIV_INC_DIR/framelessmanager_p.h \
$$CORE_PRIV_INC_DIR/micamaterial_p.h \
$$CORE_PRIV_INC_DIR/sysapiloader_p.h
$$CORE_PRIV_INC_DIR/sysapiloader_p.h \
$$CORE_PRIV_INC_DIR/windowborderpainter_p.h
SOURCES += \
$$CORE_SRC_DIR/chromepalette.cpp \
@ -40,7 +42,8 @@ SOURCES += \
$$CORE_SRC_DIR/framelesshelpercore_global.cpp \
$$CORE_SRC_DIR/micamaterial.cpp \
$$CORE_SRC_DIR/sysapiloader.cpp \
$$CORE_SRC_DIR/utils.cpp
$$CORE_SRC_DIR/utils.cpp \
$$CORE_SRC_DIR/windowborderpainter.cpp
RESOURCES += \
$$CORE_SRC_DIR/framelesshelpercore.qrc

View File

@ -26,13 +26,15 @@ HEADERS += \
$$QUICK_PUB_INC_DIR/quickchromepalette.h \
$$QUICK_PUB_INC_DIR/quickmicamaterial.h \
$$QUICK_PUB_INC_DIR/quickimageitem.h \
$$QUICK_PUB_INC_DIR/quickwindowborder.h \
$$QUICK_PRIV_INC_DIR/quickstandardsystembutton_p.h \
$$QUICK_PRIV_INC_DIR/quickstandardtitlebar_p.h \
$$QUICK_PRIV_INC_DIR/framelessquickhelper_p.h \
$$QUICK_PRIV_INC_DIR/framelessquickwindow_p.h \
$$QUICK_PRIV_INC_DIR/framelessquickwindow_p_p.h \
$$QUICK_PRIV_INC_DIR/quickmicamaterial_p.h \
$$QUICK_PRIV_INC_DIR/quickimageitem_p.h
$$QUICK_PRIV_INC_DIR/quickimageitem_p.h \
$$QUICK_PRIV_INC_DIR/quickwindowborder_p.h
SOURCES += \
$$QUICK_SRC_DIR/quickstandardsystembutton.cpp \
@ -44,4 +46,5 @@ SOURCES += \
$$QUICK_SRC_DIR/quickchromepalette.cpp \
$$QUICK_SRC_DIR/framelesshelperquick_global.cpp \
$$QUICK_SRC_DIR/quickmicamaterial.cpp \
$$QUICK_SRC_DIR/quickimageitem.cpp
$$QUICK_SRC_DIR/quickimageitem.cpp \
$$QUICK_SRC_DIR/quickwindowborder.cpp

View File

@ -45,6 +45,7 @@ set(PUBLIC_HEADERS
${INCLUDE_PREFIX}/utils.h
${INCLUDE_PREFIX}/chromepalette.h
${INCLUDE_PREFIX}/micamaterial.h
${INCLUDE_PREFIX}/windowborderpainter.h
)
set(PUBLIC_HEADERS_ALIAS
@ -54,6 +55,7 @@ set(PUBLIC_HEADERS_ALIAS
${INCLUDE_PREFIX}/Utils
${INCLUDE_PREFIX}/ChromePalette
${INCLUDE_PREFIX}/MicaMaterial
${INCLUDE_PREFIX}/WindowBorderPainter
)
set(PRIVATE_HEADERS
@ -62,6 +64,7 @@ set(PRIVATE_HEADERS
${INCLUDE_PREFIX}/private/sysapiloader_p.h
${INCLUDE_PREFIX}/private/chromepalette_p.h
${INCLUDE_PREFIX}/private/micamaterial_p.h
${INCLUDE_PREFIX}/private/windowborderpainter_p.h
)
set(SOURCES
@ -73,6 +76,7 @@ set(SOURCES
chromepalette.cpp
framelesshelpercore_global.cpp
micamaterial.cpp
windowborderpainter.cpp
)
if(WIN32)

View File

@ -23,7 +23,6 @@
*/
#include "framelesshelper_win.h"
#include <QtCore/qdebug.h>
#include <QtCore/qhash.h>
#include <QtCore/qmutex.h>
#include <QtCore/qvariant.h>
@ -35,7 +34,6 @@
#include "utils.h"
#include "winverhelper_p.h"
#include "framelesshelper_windows.h"
#include <optional>
FRAMELESSHELPER_BEGIN_NAMESPACE

View File

@ -31,11 +31,13 @@
#include "framelesshelper_qt.h"
#include "chromepalette.h"
#include "micamaterial.h"
#include "windowborderpainter.h"
#include "sysapiloader_p.h"
#include "framelessmanager_p.h"
#include "framelessconfig_p.h"
#include "chromepalette_p.h"
#include "micamaterial_p.h"
#include "windowborderpainter_p.h"
#ifdef Q_OS_WINDOWS
# include "registrykey_p.h"
#endif
@ -166,6 +168,8 @@ void initialize()
# ifdef Q_OS_WINDOWS
qRegisterMetaType<RegistryRootKey>();
# endif
qRegisterMetaType<WindowEdge>();
qRegisterMetaType<WindowEdges>();
qRegisterMetaType<VersionNumber>();
qRegisterMetaType<SystemParameters>();
qRegisterMetaType<VersionInfo>();
@ -182,6 +186,8 @@ void initialize()
qRegisterMetaType<ChromePalettePrivate>();
qRegisterMetaType<MicaMaterial>();
qRegisterMetaType<MicaMaterialPrivate>();
qRegisterMetaType<WindowBorderPainter>();
qRegisterMetaType<WindowBorderPainterPrivate>();
# ifdef Q_OS_WINDOWS
qRegisterMetaType<RegistryKey>();
# endif

View File

@ -23,7 +23,6 @@
*/
#include "framelessmanager_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qmutex.h>
#include <QtCore/qcoreapplication.h>
#include <QtGui/qscreen.h>

View File

@ -27,7 +27,6 @@
#include "framelessmanager.h"
#include "utils.h"
#include "framelessconfig_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qsysinfo.h>
#include <QtCore/qmutex.h>
#include <QtGui/qpixmap.h>

View File

@ -24,7 +24,6 @@
#include "registrykey_p.h"
#include "framelesshelper_windows.h"
#include <QtCore/qdebug.h>
#if REGISTRYKEY_QWINREGISTRYKEY
# include <QtCore/private/qwinregistry_p.h>
#else

View File

@ -23,7 +23,6 @@
*/
#include "sysapiloader_p.h"
#include <QtCore/qdebug.h>
#ifdef Q_OS_WINDOWS
# include <QtCore/private/qsystemlibrary_p.h>
#else

View File

@ -23,7 +23,6 @@
*/
#include "utils.h"
#include <QtCore/qdebug.h>
#include <QtGui/qwindow.h>
#include <QtGui/qscreen.h>
#include <QtGui/qguiapplication.h>

View File

@ -26,7 +26,6 @@
#include "framelessconfig_p.h"
#include "framelessmanager.h"
#include "framelessmanager_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qregularexpression.h>
#include <QtGui/qwindow.h>
#include <QtGui/qscreen.h>
@ -373,7 +372,8 @@ static inline void
xcb_flush(connection);
}
static inline void sendMouseReleaseEvent(QWindow *window, const QPoint &globalPos)
[[maybe_unused]] static inline void
sendMouseReleaseEvent(QWindow *window, const QPoint &globalPos)
{
Q_ASSERT(window);
if (!window) {
@ -398,8 +398,10 @@ void Utils::startSystemMove(QWindow *window, const QPoint &globalPos)
if (!window) {
return;
}
#if (QT_VERSION < QT_VERSION_CHECK(6, 2, 0))
// Before we start the dragging we need to tell Qt that the mouse is released.
sendMouseReleaseEvent(window, globalPos);
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
window->startSystemMove();
#else
@ -417,8 +419,10 @@ void Utils::startSystemResize(QWindow *window, const Qt::Edges edges, const QPoi
if (edges == Qt::Edges{}) {
return;
}
#if (QT_VERSION < QT_VERSION_CHECK(6, 2, 0))
// Before we start the resizing we need to tell Qt that the mouse is released.
sendMouseReleaseEvent(window, globalPos);
#endif
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
window->startSystemResize(edges);
#else

View File

@ -26,7 +26,6 @@
#include "framelessmanager.h"
#include "framelessmanager_p.h"
#include "framelessconfig_p.h"
#include <QtCore/qdebug.h>
#include <QtCore/qhash.h>
#include <QtCore/qmutex.h>
#include <QtCore/qcoreapplication.h>

View File

@ -23,7 +23,6 @@
*/
#include "utils.h"
#include <QtCore/qdebug.h>
#include <QtCore/qmutex.h>
#include <QtCore/qhash.h>
#include <QtCore/private/qsystemerror_p.h>

View File

@ -0,0 +1,290 @@
/*
* 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 "windowborderpainter.h"
#include "windowborderpainter_p.h"
#include "utils.h"
#include "framelessmanager.h"
#ifdef Q_OS_WINDOWS
# include "winverhelper_p.h"
#endif
#include <QtGui/qpainter.h>
FRAMELESSHELPER_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcWindowBorderPainter, "wangwenx190.framelesshelper.core.windowborderpainter")
#define INFO qCInfo(lcWindowBorderPainter)
#define DEBUG qCDebug(lcWindowBorderPainter)
#define WARNING qCWarning(lcWindowBorderPainter)
#define CRITICAL qCCritical(lcWindowBorderPainter)
using namespace Global;
static constexpr const int kMaximumBorderThickness = 100;
WindowBorderPainterPrivate::WindowBorderPainterPrivate(WindowBorderPainter *q) : QObject(q)
{
Q_ASSERT(q);
if (!q) {
return;
}
q_ptr = q;
initialize();
}
WindowBorderPainterPrivate::~WindowBorderPainterPrivate() = default;
WindowBorderPainterPrivate *WindowBorderPainterPrivate::get(WindowBorderPainter *q)
{
Q_ASSERT(q);
if (!q) {
return nullptr;
}
return q->d_func();
}
const WindowBorderPainterPrivate *WindowBorderPainterPrivate::get(const WindowBorderPainter *q)
{
Q_ASSERT(q);
if (!q) {
return nullptr;
}
return q->d_func();
}
int WindowBorderPainterPrivate::getNativeBorderThickness()
{
return kDefaultWindowFrameBorderThickness;
}
QColor WindowBorderPainterPrivate::getNativeBorderColor(const bool active)
{
#ifdef Q_OS_WINDOWS
return Utils::getFrameBorderColor(active);
#elif defined(Q_OS_LINUX)
return (active ? Utils::getWmThemeColor() : kDefaultDarkGrayColor);
#elif defined(Q_OS_MACOS)
return (active ? Utils::getControlsAccentColor() : kDefaultDarkGrayColor);
#else
return (active ? kDefaultBlackColor : kDefaultDarkGrayColor);
#endif
}
WindowEdges WindowBorderPainterPrivate::getNativeBorderEdges()
{
#ifdef Q_OS_WINDOWS
return (WindowsVersionHelper::isWin10OrGreater() ? WindowEdges(WindowEdge::Top) : WindowEdges());
#else
return {};
#endif
}
void WindowBorderPainterPrivate::paint(QPainter *painter, const QSize &size, const bool active) const
{
Q_ASSERT(painter);
if (!painter) {
return;
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
QList<QLine> lines = {};
#else
QVector<QLine> lines = {};
#endif
const QPoint leftTop = {0, 0};
// In fact, we should use "size.width() - 1" here in theory 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.
const QPoint rightTop = {size.width(), 0};
// Same here as above: we should use "size.height() - 1" ideally but we
// can't, sadly.
const QPoint rightBottom = {size.width(), size.height()};
const QPoint leftBottom = {0, size.height()};
const WindowEdges edges = m_edges.value_or(getNativeBorderEdges());
if (edges & WindowEdge::Left) {
lines.append({leftBottom, leftTop});
}
if (edges & WindowEdge::Top) {
lines.append({leftTop, rightTop});
}
if (edges & WindowEdge::Right) {
lines.append({rightTop, rightBottom});
}
if (edges & WindowEdge::Bottom) {
lines.append({rightBottom, leftBottom});
}
if (lines.isEmpty()) {
return;
}
painter->save();
painter->setRenderHints(QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
// We can't enable antialiasing here, because the border is too thin and antialiasing
// will break it's painting.
painter->setRenderHint(QPainter::Antialiasing, false);
QPen pen = {};
pen.setColor([active, this]() -> QColor {
QColor color = {};
if (active) {
color = m_activeColor.value_or(getNativeBorderColor(true));
} else {
color = m_inactiveColor.value_or(getNativeBorderColor(false));
}
if (color.isValid()) {
return color;
}
return (active ? kDefaultBlackColor : kDefaultDarkGrayColor);
}());
pen.setWidth(m_thickness.value_or(getNativeBorderThickness()));
painter->setPen(pen);
painter->drawLines(lines);
painter->restore();
}
void WindowBorderPainterPrivate::initialize()
{
Q_Q(WindowBorderPainter);
connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged,
q, &WindowBorderPainter::nativeBorderChanged);
connect(q, &WindowBorderPainter::nativeBorderChanged, q, &WindowBorderPainter::shouldRepaint);
}
WindowBorderPainter::WindowBorderPainter(QObject *parent)
: QObject(parent), d_ptr(new WindowBorderPainterPrivate(this))
{
}
WindowBorderPainter::~WindowBorderPainter() = default;
int WindowBorderPainter::thickness() const
{
Q_D(const WindowBorderPainter);
return d->m_thickness.value_or(d->getNativeBorderThickness());
}
WindowEdges WindowBorderPainter::edges() const
{
Q_D(const WindowBorderPainter);
return d->m_edges.value_or(d->getNativeBorderEdges());
}
QColor WindowBorderPainter::activeColor() const
{
Q_D(const WindowBorderPainter);
return d->m_activeColor.value_or(d->getNativeBorderColor(true));
}
QColor WindowBorderPainter::inactiveColor() const
{
Q_D(const WindowBorderPainter);
return d->m_inactiveColor.value_or(d->getNativeBorderColor(false));
}
int WindowBorderPainter::nativeThickness() const
{
Q_D(const WindowBorderPainter);
return d->getNativeBorderThickness();
}
WindowEdges WindowBorderPainter::nativeEdges() const
{
Q_D(const WindowBorderPainter);
return d->getNativeBorderEdges();
}
QColor WindowBorderPainter::nativeActiveColor() const
{
Q_D(const WindowBorderPainter);
return d->getNativeBorderColor(true);
}
QColor WindowBorderPainter::nativeInactiveColor() const
{
Q_D(const WindowBorderPainter);
return d->getNativeBorderColor(false);
}
void WindowBorderPainter::paint(QPainter *painter, const QSize &size, const bool active) const
{
Q_D(const WindowBorderPainter);
d->paint(painter, size, active);
}
void WindowBorderPainter::setThickness(const int value)
{
Q_ASSERT(value >= 0);
Q_ASSERT(value < kMaximumBorderThickness);
if ((value < 0) || (value >= kMaximumBorderThickness)) {
return;
}
if (thickness() == value) {
return;
}
Q_D(WindowBorderPainter);
d->m_thickness = value;
Q_EMIT thicknessChanged();
Q_EMIT shouldRepaint();
}
void WindowBorderPainter::setEdges(const Global::WindowEdges value)
{
if (edges() == value) {
return;
}
Q_D(WindowBorderPainter);
d->m_edges = value;
Q_EMIT edgesChanged();
Q_EMIT shouldRepaint();
}
void WindowBorderPainter::setActiveColor(const QColor &value)
{
Q_ASSERT(value.isValid());
if (!value.isValid()) {
return;
}
if (activeColor() == value) {
return;
}
Q_D(WindowBorderPainter);
d->m_activeColor = value;
Q_EMIT activeColorChanged();
Q_EMIT shouldRepaint();
}
void WindowBorderPainter::setInactiveColor(const QColor &value)
{
Q_ASSERT(value.isValid());
if (!value.isValid()) {
return;
}
if (inactiveColor() == value) {
return;
}
Q_D(WindowBorderPainter);
d->m_inactiveColor = value;
Q_EMIT inactiveColorChanged();
Q_EMIT shouldRepaint();
}
FRAMELESSHELPER_END_NAMESPACE

View File

@ -0,0 +1 @@
#include "../../include/FramelessHelper/Core/windowborderpainter.h"

View File

@ -0,0 +1 @@
#include "../../include/FramelessHelper/Core/private/windowborderpainter_p.h"

View File

@ -39,6 +39,7 @@ set(PUBLIC_HEADERS
${INCLUDE_PREFIX}/quickchromepalette.h
${INCLUDE_PREFIX}/quickmicamaterial.h
${INCLUDE_PREFIX}/quickimageitem.h
${INCLUDE_PREFIX}/quickwindowborder.h
)
set(PUBLIC_HEADERS_ALIAS
@ -49,6 +50,7 @@ set(PUBLIC_HEADERS_ALIAS
${INCLUDE_PREFIX}/QuickChromePalette
${INCLUDE_PREFIX}/QuickMicaMaterial
${INCLUDE_PREFIX}/QuickImageItem
${INCLUDE_PREFIX}/QuickWindowBorder
)
set(PRIVATE_HEADERS
@ -59,6 +61,7 @@ set(PRIVATE_HEADERS
${INCLUDE_PREFIX}/private/framelessquickwindow_p_p.h
${INCLUDE_PREFIX}/private/quickmicamaterial_p.h
${INCLUDE_PREFIX}/private/quickimageitem_p.h
${INCLUDE_PREFIX}/private/quickwindowborder_p.h
)
set(SOURCES
@ -72,6 +75,7 @@ set(SOURCES
framelesshelperquick_global.cpp
quickmicamaterial.cpp
quickimageitem.cpp
quickwindowborder.cpp
)
if(WIN32 AND NOT FRAMELESSHELPER_BUILD_STATIC)

View File

@ -36,6 +36,8 @@
# include "quickmicamaterial_p.h"
# include "quickimageitem.h"
# include "quickimageitem_p.h"
# include "quickwindowborder.h"
# include "quickwindowborder_p.h"
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
FRAMELESSHELPER_BEGIN_NAMESPACE
@ -76,6 +78,8 @@ void initialize()
#endif
qRegisterMetaType<QuickGlobal::ApplicationType>();
qRegisterMetaType<QuickGlobal::BlurMode>();
qRegisterMetaType<QuickGlobal::WindowEdge>();
qRegisterMetaType<QuickGlobal::WindowEdges>();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
qRegisterMetaType<QuickGlobal>();
@ -99,6 +103,9 @@ void initialize()
qRegisterMetaType<QuickImageItem>();
qRegisterMetaType<QuickImageItem *>();
qRegisterMetaType<QuickImageItemPrivate>();
qRegisterMetaType<QuickWindowBorder>();
qRegisterMetaType<QuickWindowBorder *>();
qRegisterMetaType<QuickWindowBorderPrivate>();
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
}

View File

@ -25,9 +25,9 @@
#include "framelessquickhelper.h"
#include "framelessquickhelper_p.h"
#include "quickmicamaterial.h"
#include "quickwindowborder.h"
#include <QtCore/qmutex.h>
#include <QtCore/qtimer.h>
#include <QtCore/qdebug.h>
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
# include <QtGui/qpa/qplatformwindow.h> // For QWINDOWSIZE_MAX
#else
@ -75,7 +75,7 @@ struct QuickHelper
Q_GLOBAL_STATIC(QuickHelper, g_quickHelper)
[[nodiscard]] static inline QuickMicaMaterial *findMicaMaterialItem(const QQuickWindow * const window)
[[nodiscard]] static inline QuickMicaMaterial *findOrCreateMicaMaterial(const QQuickWindow * const window)
{
Q_ASSERT(window);
if (!window) {
@ -93,6 +93,24 @@ Q_GLOBAL_STATIC(QuickHelper, g_quickHelper)
return item;
}
[[nodiscard]] static inline QuickWindowBorder *findOrCreateWindowBorder(const QQuickWindow * const window)
{
Q_ASSERT(window);
if (!window) {
return nullptr;
}
QQuickItem * const rootItem = window->contentItem();
if (const auto item = rootItem->findChild<QuickWindowBorder *>()) {
return item;
}
const auto item = new QuickWindowBorder;
item->setParent(rootItem);
item->setParentItem(rootItem);
item->setZ(999); // Make sure it always stays on the top.
QQuickItemPrivate::get(item)->anchors()->setFill(rootItem);
return item;
}
FramelessQuickHelperPrivate::FramelessQuickHelperPrivate(FramelessQuickHelper *q) : QObject(q)
{
Q_ASSERT(q);
@ -517,7 +535,7 @@ void FramelessQuickHelperPrivate::setBlurBehindWindowEnabled(const bool value, c
}
} else {
m_blurBehindWindowEnabled = value;
findMicaMaterialItem(window)->setVisible(m_blurBehindWindowEnabled);
findOrCreateMicaMaterial()->setVisible(m_blurBehindWindowEnabled);
emitSignalForAllInstances(FRAMELESSHELPER_BYTEARRAY_LITERAL("blurBehindWindowEnabledChanged"));
}
}
@ -552,6 +570,26 @@ QVariant FramelessQuickHelperPrivate::getProperty(const QByteArray &name, const
return (value.isValid() ? value : defaultValue);
}
QuickMicaMaterial *FramelessQuickHelperPrivate::findOrCreateMicaMaterial() const
{
Q_Q(const FramelessQuickHelper);
const QQuickWindow * const window = q->window();
if (!window) {
return nullptr;
}
return FRAMELESSHELPER_PREPEND_NAMESPACE(findOrCreateMicaMaterial)(window);
}
QuickWindowBorder *FramelessQuickHelperPrivate::findOrCreateWindowBorder() const
{
Q_Q(const FramelessQuickHelper);
const QQuickWindow * const window = q->window();
if (!window) {
return nullptr;
}
return FRAMELESSHELPER_PREPEND_NAMESPACE(findOrCreateWindowBorder)(window);
}
bool FramelessQuickHelperPrivate::eventFilter(QObject *object, QEvent *event)
{
Q_ASSERT(object);
@ -909,6 +947,18 @@ bool FramelessQuickHelper::isContentExtendedIntoTitleBar() const
return d->isContentExtendedIntoTitleBar();
}
QuickMicaMaterial *FramelessQuickHelper::micaMaterial() const
{
Q_D(const FramelessQuickHelper);
return d->findOrCreateMicaMaterial();
}
QuickWindowBorder *FramelessQuickHelper::windowBorder() const
{
Q_D(const FramelessQuickHelper);
return d->findOrCreateWindowBorder();
}
void FramelessQuickHelper::extendsContentIntoTitleBar(const bool value)
{
Q_D(FramelessQuickHelper);

View File

@ -28,12 +28,11 @@
#include "quickchromepalette.h"
#include "quickmicamaterial.h"
#include "quickimageitem.h"
#include "quickwindowborder.h"
#include "framelessquickwindow_p.h"
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
# include "quickstandardsystembutton_p.h"
# include "quickstandardtitlebar_p.h"
# include "framelessquickwindow_p.h"
#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
# include <QtQuick/qquickwindow.h>
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
#ifndef QUICK_URI_SHORT
@ -86,20 +85,19 @@ void FramelessHelper::Quick::registerTypes(QQmlEngine *engine)
qmlRegisterRevision<QQuickItem, 254>(QUICK_URI_FULL);
qmlRegisterType<FramelessQuickHelper>(QUICK_URI_EXPAND("FramelessHelper"));
qmlRegisterType<FramelessQuickWindow>(QUICK_URI_EXPAND("FramelessWindow"));
qmlRegisterType<QuickMicaMaterial>(QUICK_URI_EXPAND("MicaMaterial"));
qmlRegisterType<QuickImageItem>(QUICK_URI_EXPAND("ImageItem"));
qmlRegisterType<QuickWindowBorder>(QUICK_URI_EXPAND("WindowBorder"));
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
qmlRegisterType<QuickStandardSystemButton>(QUICK_URI_EXPAND("StandardSystemButton"));
qmlRegisterType<QuickStandardTitleBar>(QUICK_URI_EXPAND("StandardTitleBar"));
qmlRegisterType<FramelessQuickWindow>(QUICK_URI_EXPAND("FramelessWindow"));
#else // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
qmlRegisterTypeNotAvailable(QUICK_URI_EXPAND("StandardSystemButton"),
FRAMELESSHELPER_STRING_LITERAL("StandardSystemButton is not available until Qt6."));
qmlRegisterTypeNotAvailable(QUICK_URI_EXPAND("StandardTitleBar"),
FRAMELESSHELPER_STRING_LITERAL("StandardTitleBar is not available until Qt6."));
qmlRegisterTypeNotAvailable(QUICK_URI_EXPAND("FramelessWindow"),
FRAMELESSHELPER_STRING_LITERAL("FramelessWindow is not available until Qt6."));
#endif // (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
qmlRegisterModule(QUICK_URI_FULL);

View File

@ -23,17 +23,15 @@
*/
#include "framelessquickwindow_p.h"
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
#include "framelessquickwindow_p_p.h"
#include "framelessquickhelper.h"
#include "quickwindowborder.h"
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qquickrectangle_p.h>
#include <QtQuick/private/qquickanchors_p.h>
#include <framelessmanager.h>
#include <utils.h>
#ifdef Q_OS_WINDOWS
# include <winverhelper_p.h>
#endif // Q_OS_WINDOWS
#endif
FRAMELESSHELPER_BEGIN_NAMESPACE
@ -111,21 +109,6 @@ bool FramelessQuickWindowPrivate::isFullScreen() const
return (q->visibility() == FramelessQuickWindow::FullScreen);
}
QColor FramelessQuickWindowPrivate::getFrameBorderColor() const
{
#ifdef Q_OS_WINDOWS
Q_Q(const FramelessQuickWindow);
return Utils::getFrameBorderColor(q->isActive());
#else
return {};
#endif
}
QQuickAnchorLine FramelessQuickWindowPrivate::getTopBorderBottom() const
{
return QQuickAnchorLine(m_topBorderRectangle.data(), QQuickAnchors::BottomAnchor);
}
void FramelessQuickWindowPrivate::showMinimized2()
{
Q_Q(FramelessQuickWindow);
@ -166,22 +149,13 @@ void FramelessQuickWindowPrivate::initialize()
Q_Q(FramelessQuickWindow);
QQuickItem * const rootItem = q->contentItem();
FramelessQuickHelper::get(rootItem)->extendsContentIntoTitleBar();
m_topBorderRectangle.reset(new QQuickRectangle(rootItem));
m_topBorderRectangle->setZ(999); // Make sure the frame border stays on top of eveything.
m_topBorderRectangle->setColor(kDefaultTransparentColor);
m_topBorderRectangle->setHeight(0.0);
QQuickPen * const b = m_topBorderRectangle->border();
b->setWidth(0.0);
b->setColor(kDefaultTransparentColor);
updateTopBorderHeight();
updateTopBorderColor();
m_topBorderAnchors.reset(new QQuickAnchors(m_topBorderRectangle.data(), m_topBorderRectangle.data()));
const QQuickItemPrivate * const rootItemPrivate = QQuickItemPrivate::get(rootItem);
m_topBorderAnchors->setTop(rootItemPrivate->top());
m_topBorderAnchors->setLeft(rootItemPrivate->left());
m_topBorderAnchors->setRight(rootItemPrivate->right());
m_windowBorder.reset(new QuickWindowBorder);
m_windowBorder->setParent(rootItem);
m_windowBorder->setParentItem(rootItem);
m_windowBorder->setZ(999); // Make sure it always stays on the top.
QQuickItemPrivate::get(m_windowBorder.data())->anchors()->setFill(rootItem);
connect(q, &FramelessQuickWindow::visibilityChanged, this, [this, q](){
updateTopBorderHeight();
updateWindowBorderVisibility();
Q_EMIT q->hiddenChanged();
Q_EMIT q->normalChanged();
Q_EMIT q->minimizedChanged();
@ -189,38 +163,27 @@ void FramelessQuickWindowPrivate::initialize()
Q_EMIT q->zoomedChanged();
Q_EMIT q->fullScreenChanged();
});
connect(q, &FramelessQuickWindow::activeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor);
connect(FramelessManager::instance(), &FramelessManager::systemThemeChanged, this, &FramelessQuickWindowPrivate::updateTopBorderColor);
connect(q, &FramelessQuickWindow::activeChanged,
m_windowBorder.data(), [this](){ m_windowBorder->update(); });
updateWindowBorderVisibility();
}
bool FramelessQuickWindowPrivate::shouldDrawFrameBorder() const
{
#ifdef Q_OS_WINDOWS
return (Utils::isWindowFrameBorderVisible() && !WindowsVersionHelper::isWin11OrGreater());
return (Utils::isWindowFrameBorderVisible()
&& !WindowsVersionHelper::isWin11OrGreater() && isNormal());
#else
return false;
#endif
}
void FramelessQuickWindowPrivate::updateTopBorderColor()
void FramelessQuickWindowPrivate::updateWindowBorderVisibility()
{
#ifdef Q_OS_WINDOWS
if (!shouldDrawFrameBorder()) {
if (m_windowBorder.isNull()) {
return;
}
m_topBorderRectangle->setColor(getFrameBorderColor());
#endif
}
void FramelessQuickWindowPrivate::updateTopBorderHeight()
{
#ifdef Q_OS_WINDOWS
if (!shouldDrawFrameBorder()) {
return;
}
const qreal newHeight = (isNormal() ? qreal(kDefaultWindowFrameBorderThickness) : 0.0);
m_topBorderRectangle->setHeight(newHeight);
#endif
m_windowBorder->setVisible(shouldDrawFrameBorder());
}
FramelessQuickWindow::FramelessQuickWindow(QWindow *parent)
@ -293,4 +256,3 @@ void FramelessQuickWindow::componentComplete()
}
FRAMELESSHELPER_END_NAMESPACE
#endif

View File

@ -24,7 +24,6 @@
#include "quickimageitem.h"
#include "quickimageitem_p.h"
#include <QtCore/qdebug.h>
#include <QtGui/qpainter.h>
#include <QtGui/qimage.h>
#include <QtGui/qpixmap.h>

View File

@ -25,7 +25,6 @@
#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>

View File

@ -0,0 +1,265 @@
/*
* 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 "quickwindowborder.h"
#include "quickwindowborder_p.h"
#include <windowborderpainter.h>
#include <QtQuick/qquickwindow.h>
FRAMELESSHELPER_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(lcQuickWindowBorder, "wangwenx190.framelesshelper.quick.quickwindowborder")
#define INFO qCInfo(lcQuickWindowBorder)
#define DEBUG qCDebug(lcQuickWindowBorder)
#define WARNING qCWarning(lcQuickWindowBorder)
#define CRITICAL qCCritical(lcQuickWindowBorder)
using namespace Global;
[[nodiscard]] static inline QuickGlobal::WindowEdges edgesToQuickEdges(const WindowEdges edges)
{
QuickGlobal::WindowEdges result = {};
if (edges & WindowEdge::Left) {
result |= QuickGlobal::WindowEdge::Left;
}
if (edges & WindowEdge::Top) {
result |= QuickGlobal::WindowEdge::Top;
}
if (edges & WindowEdge::Right) {
result |= QuickGlobal::WindowEdge::Right;
}
if (edges & WindowEdge::Bottom) {
result |= QuickGlobal::WindowEdge::Bottom;
}
return result;
}
[[nodiscard]] static inline WindowEdges quickEdgesToEdges(const QuickGlobal::WindowEdges edges)
{
WindowEdges result = {};
if (edges & QuickGlobal::WindowEdge::Left) {
result |= WindowEdge::Left;
}
if (edges & QuickGlobal::WindowEdge::Top) {
result |= WindowEdge::Top;
}
if (edges & QuickGlobal::WindowEdge::Right) {
result |= WindowEdge::Right;
}
if (edges & QuickGlobal::WindowEdge::Bottom) {
result |= WindowEdge::Bottom;
}
return result;
}
QuickWindowBorderPrivate::QuickWindowBorderPrivate(QuickWindowBorder *q) : QObject(q)
{
Q_ASSERT(q);
if (!q) {
return;
}
q_ptr = q;
initialize();
}
QuickWindowBorderPrivate::~QuickWindowBorderPrivate() = default;
QuickWindowBorderPrivate *QuickWindowBorderPrivate::get(QuickWindowBorder *q)
{
Q_ASSERT(q);
if (!q) {
return nullptr;
}
return q->d_func();
}
const QuickWindowBorderPrivate *QuickWindowBorderPrivate::get(const QuickWindowBorder *q)
{
Q_ASSERT(q);
if (!q) {
return nullptr;
}
return q->d_func();
}
void QuickWindowBorderPrivate::paint(QPainter *painter) const
{
Q_ASSERT(painter);
if (!painter || m_borderPainter.isNull()) {
return;
}
Q_Q(const QuickWindowBorder);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
const QSize size = q->size().toSize();
#else
const QSize size = QSizeF(q->width(), q->height()).toSize();
#endif
m_borderPainter->paint(painter, size, (q->window() && q->window()->isActive()));
}
void QuickWindowBorderPrivate::initialize()
{
Q_Q(QuickWindowBorder);
q->setClip(true);
q->setSmooth(true);
// We can't enable antialising for this element due to we are drawing
// some very thin lines that are too fragile.
q->setAntialiasing(false);
m_borderPainter.reset(new WindowBorderPainter);
connect(m_borderPainter.data(), &WindowBorderPainter::thicknessChanged,
q, &QuickWindowBorder::thicknessChanged);
connect(m_borderPainter.data(), &WindowBorderPainter::edgesChanged,
q, &QuickWindowBorder::edgesChanged);
connect(m_borderPainter.data(), &WindowBorderPainter::activeColorChanged,
q, &QuickWindowBorder::activeColorChanged);
connect(m_borderPainter.data(), &WindowBorderPainter::inactiveColorChanged,
q, &QuickWindowBorder::inactiveColorChanged);
connect(m_borderPainter.data(), &WindowBorderPainter::nativeBorderChanged,
q, &QuickWindowBorder::nativeBorderChanged);
connect(m_borderPainter.data(), &WindowBorderPainter::shouldRepaint, q, [q](){ q->update(); });
}
QuickWindowBorder::QuickWindowBorder(QQuickItem *parent)
: QQuickPaintedItem(parent), d_ptr(new QuickWindowBorderPrivate(this))
{
}
QuickWindowBorder::~QuickWindowBorder() = default;
void QuickWindowBorder::paint(QPainter *painter)
{
Q_D(QuickWindowBorder);
d->paint(painter);
}
qreal QuickWindowBorder::thickness() const
{
Q_D(const QuickWindowBorder);
return (d->m_borderPainter.isNull() ? 0 : d->m_borderPainter->thickness());
}
QuickGlobal::WindowEdges QuickWindowBorder::edges() const
{
Q_D(const QuickWindowBorder);
return (d->m_borderPainter.isNull() ? QuickGlobal::WindowEdges()
: edgesToQuickEdges(d->m_borderPainter->edges()));
}
QColor QuickWindowBorder::activeColor() const
{
Q_D(const QuickWindowBorder);
return (d->m_borderPainter.isNull() ? QColor() : d->m_borderPainter->activeColor());
}
QColor QuickWindowBorder::inactiveColor() const
{
Q_D(const QuickWindowBorder);
return (d->m_borderPainter.isNull() ? QColor() : d->m_borderPainter->inactiveColor());
}
qreal QuickWindowBorder::nativeThickness() const
{
Q_D(const QuickWindowBorder);
return (d->m_borderPainter.isNull() ? 0 : d->m_borderPainter->nativeThickness());
}
QuickGlobal::WindowEdges QuickWindowBorder::nativeEdges() const
{
Q_D(const QuickWindowBorder);
return (d->m_borderPainter.isNull() ? QuickGlobal::WindowEdges()
: edgesToQuickEdges(d->m_borderPainter->nativeEdges()));
}
QColor QuickWindowBorder::nativeActiveColor() const
{
Q_D(const QuickWindowBorder);
return (d->m_borderPainter.isNull() ? QColor() : d->m_borderPainter->nativeActiveColor());
}
QColor QuickWindowBorder::nativeInactiveColor() const
{
Q_D(const QuickWindowBorder);
return (d->m_borderPainter.isNull() ? QColor() : d->m_borderPainter->nativeInactiveColor());
}
void QuickWindowBorder::setThickness(const qreal value)
{
Q_D(QuickWindowBorder);
if (d->m_borderPainter.isNull()) {
return;
}
if (qFuzzyCompare(thickness(), value)) {
return;
}
d->m_borderPainter->setThickness(qRound(value));
}
void QuickWindowBorder::setEdges(const QuickGlobal::WindowEdges value)
{
Q_D(QuickWindowBorder);
if (d->m_borderPainter.isNull()) {
return;
}
if (edges() == value) {
return;
}
d->m_borderPainter->setEdges(quickEdgesToEdges(value));
}
void QuickWindowBorder::setActiveColor(const QColor &value)
{
Q_D(QuickWindowBorder);
if (d->m_borderPainter.isNull()) {
return;
}
if (activeColor() == value) {
return;
}
d->m_borderPainter->setActiveColor(value);
}
void QuickWindowBorder::setInactiveColor(const QColor &value)
{
Q_D(QuickWindowBorder);
if (d->m_borderPainter.isNull()) {
return;
}
if (inactiveColor() == value) {
return;
}
d->m_borderPainter->setInactiveColor(value);
}
void QuickWindowBorder::classBegin()
{
QQuickPaintedItem::classBegin();
}
void QuickWindowBorder::componentComplete()
{
QQuickPaintedItem::componentComplete();
}
FRAMELESSHELPER_END_NAMESPACE

View File

@ -0,0 +1 @@
#include "../../include/FramelessHelper/Quick/quickwindowborder.h"

View File

@ -0,0 +1 @@
#include "../../include/FramelessHelper/Quick/private/quickwindowborder_p.h"

View File

@ -34,7 +34,6 @@
#include <QtCore/qmutex.h>
#include <QtCore/qhash.h>
#include <QtCore/qtimer.h>
#include <QtCore/qdebug.h>
#include <QtGui/qwindow.h>
#include <QtGui/qpalette.h>
#include <QtWidgets/qwidget.h>
@ -268,6 +267,28 @@ QWidget *FramelessWidgetsHelperPrivate::window() const
return m_window;
}
MicaMaterial *FramelessWidgetsHelperPrivate::getMicaMaterialIfAny() const
{
if (!m_window) {
return nullptr;
}
if (const WidgetsSharedHelper * const helper = findWidgetsSharedHelper(m_window)) {
return helper->rawMicaMaterial();
}
return nullptr;
}
WindowBorderPainter *FramelessWidgetsHelperPrivate::getWindowBorderIfAny() const
{
if (!m_window) {
return nullptr;
}
if (const WidgetsSharedHelper * const helper = findWidgetsSharedHelper(m_window)) {
return helper->rawWindowBorder();
}
return nullptr;
}
bool FramelessWidgetsHelperPrivate::isContentExtendedIntoTitleBar() const
{
return getWindowData().ready;
@ -859,6 +880,18 @@ bool FramelessWidgetsHelper::isContentExtendedIntoTitleBar() const
return d->isContentExtendedIntoTitleBar();
}
MicaMaterial *FramelessWidgetsHelper::micaMaterial() const
{
Q_D(const FramelessWidgetsHelper);
return d->getMicaMaterialIfAny();
}
WindowBorderPainter *FramelessWidgetsHelper::windowBorder() const
{
Q_D(const FramelessWidgetsHelper);
return d->getWindowBorderIfAny();
}
void FramelessWidgetsHelper::extendsContentIntoTitleBar(const bool value)
{
Q_D(FramelessWidgetsHelper);

View File

@ -32,6 +32,7 @@
#include <micamaterial.h>
#include <micamaterial_p.h>
#include <utils.h>
#include <windowborderpainter.h>
#ifdef Q_OS_WINDOWS
# include <winverhelper_p.h>
#endif // Q_OS_WINDOWS
@ -58,10 +59,21 @@ void WidgetsSharedHelper::setup(QWidget *widget)
if (!widget) {
return;
}
if (m_targetWidget == widget) {
if (m_targetWidget && (m_targetWidget == widget)) {
return;
}
m_targetWidget = widget;
m_borderPainter.reset(new WindowBorderPainter);
if (m_borderRepaintConnection) {
disconnect(m_borderRepaintConnection);
m_borderRepaintConnection = {};
}
m_borderRepaintConnection = connect(m_borderPainter.data(),
&WindowBorderPainter::shouldRepaint, this, [this](){
if (m_targetWidget) {
m_targetWidget->update();
}
});
m_micaMaterial = MicaMaterial::attach(m_targetWidget);
if (m_micaRedrawConnection) {
disconnect(m_micaRedrawConnection);
@ -82,7 +94,12 @@ void WidgetsSharedHelper::setup(QWidget *widget)
QScreen *screen = m_targetWidget->windowHandle()->screen();
#endif
handleScreenChanged(screen);
connect(m_targetWidget->windowHandle(), &QWindow::screenChanged, this, &WidgetsSharedHelper::handleScreenChanged);
if (m_screenChangeConnection) {
disconnect(m_screenChangeConnection);
m_screenChangeConnection = {};
}
m_screenChangeConnection = connect(m_targetWidget->windowHandle(),
&QWindow::screenChanged, this, &WidgetsSharedHelper::handleScreenChanged);
}
bool WidgetsSharedHelper::isMicaEnabled() const
@ -102,6 +119,16 @@ void WidgetsSharedHelper::setMicaEnabled(const bool value)
Q_EMIT micaEnabledChanged();
}
MicaMaterial *WidgetsSharedHelper::rawMicaMaterial() const
{
return (m_micaMaterial.isNull() ? nullptr : m_micaMaterial.data());
}
WindowBorderPainter *WidgetsSharedHelper::rawWindowBorder() const
{
return (m_borderPainter.isNull() ? nullptr : m_borderPainter.data());
}
bool WidgetsSharedHelper::eventFilter(QObject *object, QEvent *event)
{
Q_ASSERT(object);
@ -190,26 +217,10 @@ void WidgetsSharedHelper::paintEventHandler(QPaintEvent *event)
m_micaMaterial->paint(&painter, m_targetWidget->size(),
m_targetWidget->mapToGlobal(QPoint(0, 0)));
}
#ifdef Q_OS_WINDOWS
if (shouldDrawFrameBorder()) {
if (shouldDrawFrameBorder() && !m_borderPainter.isNull()) {
QPainter painter(m_targetWidget);
painter.save();
painter.setRenderHints(QPainter::TextAntialiasing | QPainter::SmoothPixmapTransform);
// We can't enable antialiasing here, because the border is only 1px height,
// it's too thin and antialiasing will break it's painting.
painter.setRenderHint(QPainter::Antialiasing, false);
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();
m_borderPainter->paint(&painter, m_targetWidget->size(), m_targetWidget->isActiveWindow());
}
#endif
// Don't eat this event here, we need Qt to keep dispatching this paint event
// otherwise the widget won't paint anything else from the user side.
}