├── .gitignore
├── FramelessHelper.pro
├── FramelessHelper.qrc
├── FramelessHelper
├── FramelessHelper.cpp
├── FramelessHelper.h
├── FramelessHelper.pri
├── FramelessHelper_p.h
├── Kernels
│ ├── NativeWindowFilter.cpp
│ ├── NativeWindowFilter.h
│ ├── NativeWindowFilter_p.h
│ ├── NativeWindowHelper.cpp
│ ├── NativeWindowHelper.h
│ └── NativeWindowHelper_p.h
├── WindowFramelessHelper.cpp
├── WindowFramelessHelper.h
└── WindowFramelessHelper_p.h
├── LICENSE
├── MainWindow.cpp
├── MainWindow.h
├── MainWindow.ui
├── README.md
├── main.cpp
├── qml
├── CloseButton.qml
├── CustomTitleBar.qml
├── MaximizeButton.qml
├── MinimizeButton.qml
├── ThreeButtons.qml
├── WindowBorder.qml
└── main.qml
├── res
├── background.png
├── close-button1.png
├── close-button1.svg
├── close-button2.png
├── maximize-button1.png
├── maximize-button1.svg
├── maximize-button2.png
├── maximize-button2.svg
├── minimize-button1.png
└── minimize-button1.svg
└── window.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # C++ objects and libs
2 |
3 | *.slo
4 | *.lo
5 | *.o
6 | *.a
7 | *.la
8 | *.lai
9 | *.so
10 | *.dll
11 | *.dylib
12 |
13 | # Qt-es
14 |
15 | /.qmake.cache
16 | /.qmake.stash
17 | *.pro.user
18 | *.pro.user.*
19 | *.qbs.user
20 | *.qbs.user.*
21 | *.moc
22 | moc_*.cpp
23 | moc_*.h
24 | qrc_*.cpp
25 | ui_*.h
26 | Makefile*
27 | *build-*
28 |
29 | # QtCreator
30 |
31 | *.autosave
32 |
33 | # QtCtreator Qml
34 | *.qmlproject.user
35 | *.qmlproject.user.*
36 |
37 | # QtCtreator CMake
38 | CMakeLists.txt.user*
39 |
40 |
--------------------------------------------------------------------------------
/FramelessHelper.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2017-08-22T16:25:35
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += qml quick widgets
8 |
9 | TARGET = StyledWindow
10 | TEMPLATE = app
11 |
12 | DEFINES += QT_DEPRECATED_WARNINGS
13 | DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000
14 |
15 | include(FramelessHelper/FramelessHelper.pri)
16 |
17 | SOURCES += \
18 | main.cpp
19 |
20 | HEADERS += \
21 | MainWindow.h
22 | FORMS += \
23 | MainWindow.ui
24 | SOURCES += \
25 | MainWindow.cpp
26 | RESOURCES += \
27 | FramelessHelper.qrc
28 |
--------------------------------------------------------------------------------
/FramelessHelper.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | res/background.png
4 | qml/main.qml
5 | qml/CloseButton.qml
6 | qml/MaximizeButton.qml
7 | qml/MinimizeButton.qml
8 | res/close-button1.svg
9 | res/maximize-button1.svg
10 | res/maximize-button2.svg
11 | res/minimize-button1.svg
12 | qml/CustomTitleBar.qml
13 | qml/ThreeButtons.qml
14 | qml/WindowBorder.qml
15 | res/close-button1.png
16 | res/close-button2.png
17 | res/maximize-button1.png
18 | res/maximize-button2.png
19 | res/minimize-button1.png
20 |
21 |
22 |
--------------------------------------------------------------------------------
/FramelessHelper/FramelessHelper.cpp:
--------------------------------------------------------------------------------
1 | #include "FramelessHelper.h"
2 | #include "FramelessHelper_p.h"
3 |
4 | #include
5 |
6 | // class FramelessHelper
7 |
8 | FramelessHelper::FramelessHelper(QWidget *parent)
9 | : QObject(parent)
10 | , d_ptr(new FramelessHelperPrivate())
11 | {
12 | Q_D(FramelessHelper);
13 | d->window = parent;
14 | Q_CHECK_PTR(parent);
15 |
16 | if (d->window)
17 | d->window->installEventFilter(this);
18 | }
19 |
20 | FramelessHelper::~FramelessHelper()
21 | {
22 | }
23 |
24 | void FramelessHelper::setDraggableMargins(int left, int top, int right, int bottom)
25 | {
26 | Q_D(FramelessHelper);
27 |
28 | d->priDraggableMargins = QMargins(left, top, right, bottom);
29 | }
30 |
31 | void FramelessHelper::setMaximizedMargins(int left, int top, int right, int bottom)
32 | {
33 | Q_D(FramelessHelper);
34 |
35 | d->priMaximizedMargins = QMargins(left, top, right, bottom);
36 | }
37 |
38 | void FramelessHelper::setDraggableMargins(const QMargins &margins)
39 | {
40 | Q_D(FramelessHelper);
41 |
42 | d->priDraggableMargins = margins;
43 | }
44 |
45 | void FramelessHelper::setMaximizedMargins(const QMargins &margins)
46 | {
47 | Q_D(FramelessHelper);
48 |
49 | d->priMaximizedMargins = margins;
50 | }
51 |
52 | QMargins FramelessHelper::draggableMargins() const
53 | {
54 | Q_D(const FramelessHelper);
55 |
56 | return d->priDraggableMargins;
57 | }
58 |
59 | QMargins FramelessHelper::maximizedMargins() const
60 | {
61 | Q_D(const FramelessHelper);
62 |
63 | return d->priMaximizedMargins;
64 | }
65 |
66 | void FramelessHelper::addIncludeItem(QWidget *item)
67 | {
68 | Q_D(FramelessHelper);
69 |
70 | d->includeItems.insert(item);
71 | }
72 |
73 | void FramelessHelper::removeIncludeItem(QWidget *item)
74 | {
75 | Q_D(FramelessHelper);
76 |
77 | d->includeItems.remove(item);
78 | }
79 |
80 | void FramelessHelper::addExcludeItem(QWidget *item)
81 | {
82 | Q_D(FramelessHelper);
83 |
84 | d->excludeItems.insert(item);
85 | }
86 |
87 | void FramelessHelper::removeExcludeItem(QWidget *item)
88 | {
89 | Q_D(FramelessHelper);
90 |
91 | d->excludeItems.remove(item);
92 | }
93 |
94 | void FramelessHelper::setTitleBarHeight(int value)
95 | {
96 | Q_D(FramelessHelper);
97 |
98 | if (value != d->titleBarHeight) {
99 | d->titleBarHeight = value;
100 | emit titleBarHeightChanged(value);
101 | }
102 | }
103 |
104 | int FramelessHelper::titleBarHeight() const
105 | {
106 | Q_D(const FramelessHelper);
107 |
108 | return d->titleBarHeight;
109 | }
110 |
111 | qreal FramelessHelper::scaleFactor() const
112 | {
113 | Q_D(const FramelessHelper);
114 |
115 | return d->helper ? d->helper->scaleFactor() : 1.0;
116 | }
117 |
118 | bool FramelessHelper::isMaximized() const
119 | {
120 | Q_D(const FramelessHelper);
121 |
122 | return d->maximized;
123 | }
124 |
125 | void FramelessHelper::triggerMinimizeButtonAction()
126 | {
127 | Q_D(FramelessHelper);
128 |
129 | if (d->window) {
130 | d->window->showMinimized();
131 | }
132 | }
133 |
134 | void FramelessHelper::triggerMaximizeButtonAction()
135 | {
136 | Q_D(FramelessHelper);
137 |
138 | if (d->window) {
139 | if (d->window->windowState() & Qt::WindowMaximized) {
140 | d->window->showNormal();
141 | } else {
142 | d->window->showMaximized();
143 | }
144 | }
145 | }
146 |
147 | void FramelessHelper::triggerCloseButtonAction()
148 | {
149 | Q_D(FramelessHelper);
150 |
151 | if (d->window) {
152 | d->window->close();
153 | }
154 | }
155 |
156 | bool FramelessHelper::eventFilter(QObject *obj, QEvent *ev)
157 | {
158 | Q_D(FramelessHelper);
159 |
160 | if (ev->type() == QEvent::WindowStateChange) {
161 | bool maximized = d->window->windowState() & Qt::WindowMaximized;
162 | if (maximized != d->maximized) {
163 | d->maximized = maximized;
164 | emit maximizedChanged(maximized);
165 | }
166 | } else if (ev->type() == QEvent::WinIdChange) {
167 | if (nullptr == d->helper) {
168 | auto w = d->window->windowHandle();
169 |
170 | d->helper = new NativeWindowHelper(w, d);
171 | connect(d->helper, &NativeWindowHelper::scaleFactorChanged,
172 | this, &FramelessHelper::scaleFactorChanged);
173 | if (!qFuzzyCompare(d->helper->scaleFactor(), 1.0)) {
174 | emit scaleFactorChanged(d->helper->scaleFactor());
175 | }
176 | }
177 | }
178 |
179 | #if QT_VERSION < QT_VERSION_CHECK(5, 9, 0)
180 | if ((ev->type() == QEvent::Resize) || (ev->type() == QEvent::WindowStateChange)) {
181 | if (d->window->windowState() & Qt::WindowMaximized) {
182 | const QMargins &m = d->priMaximizedMargins;
183 | int r = GetSystemMetrics(SM_CXFRAME) * 2 - m.left() - m.right();
184 | int b = GetSystemMetrics(SM_CYFRAME) * 2 - m.top() - m.bottom();
185 |
186 | d->window->setContentsMargins(0, 0, r, b);
187 | } else {
188 | d->window->setContentsMargins(0 ,0, 0, 0);
189 | }
190 | }
191 | #endif
192 |
193 | return QObject::eventFilter(obj, ev);
194 | }
195 |
196 | // class FramelessHelperPrivate
197 |
198 | FramelessHelperPrivate::FramelessHelperPrivate()
199 | : window(nullptr)
200 | , helper(nullptr)
201 | , titleBarHeight(0)
202 | , maximized(false)
203 | {
204 | }
205 |
206 | FramelessHelperPrivate::~FramelessHelperPrivate()
207 | {
208 | }
209 |
210 | QMargins FramelessHelperPrivate::draggableMargins() const
211 | {
212 | return priDraggableMargins;
213 | }
214 |
215 | QMargins FramelessHelperPrivate::maximizedMargins() const
216 | {
217 | return priMaximizedMargins;
218 | }
219 |
220 | bool FramelessHelperPrivate::hitTest(const QPoint &pos) const
221 | {
222 | int scaledTitleBarHeight = titleBarHeight * helper->scaleFactor();
223 |
224 | if (!window)
225 | return false;
226 | else if (scaledTitleBarHeight == 0)
227 | return false;
228 | else if ((scaledTitleBarHeight > 0)
229 | && (pos.y() >= scaledTitleBarHeight))
230 | return false;
231 |
232 | int currentIndex = -1;
233 | QWidget *items[32] = {0};
234 | auto child = window;
235 | QPoint p = pos;
236 |
237 | while (child && (currentIndex < 31)) {
238 | items[++currentIndex] = child;
239 | auto grandchild = child->childAt(p);
240 | if (nullptr == grandchild) {
241 | break;
242 | }
243 |
244 | p = grandchild->mapFrom(child, p);
245 | child = grandchild;
246 | }
247 |
248 | while (currentIndex > 0) {
249 | child = items[currentIndex];
250 | --currentIndex;
251 |
252 | if (includeItems.contains(child)) {
253 | break;
254 | } else if (excludeItems.contains(child)) {
255 | return false;
256 | } else if (window == child) {
257 | break;
258 | }
259 | }
260 |
261 | return true;
262 | }
263 |
--------------------------------------------------------------------------------
/FramelessHelper/FramelessHelper.h:
--------------------------------------------------------------------------------
1 | #ifndef FRAMELESSHELPER_H
2 | #define FRAMELESSHELPER_H
3 |
4 | #include
5 |
6 | class FramelessHelperPrivate;
7 | class FramelessHelper : public QObject
8 | {
9 | Q_OBJECT
10 | Q_DECLARE_PRIVATE(FramelessHelper)
11 |
12 | public:
13 | explicit FramelessHelper(QWidget *parent = nullptr);
14 | virtual ~FramelessHelper();
15 |
16 | public:
17 | void setDraggableMargins(int left, int top, int right, int bottom);
18 | void setMaximizedMargins(int left, int top, int right, int bottom);
19 | public:
20 | void setDraggableMargins(const QMargins &margins);
21 | void setMaximizedMargins(const QMargins &margins);
22 | public:
23 | QMargins draggableMargins() const;
24 | QMargins maximizedMargins() const;
25 |
26 | public:
27 | void addIncludeItem(QWidget *item);
28 | void removeIncludeItem(QWidget *item);
29 | public:
30 | void addExcludeItem(QWidget *item);
31 | void removeExcludeItem(QWidget *item);
32 |
33 | signals:
34 | void titleBarHeightChanged(int newValue);
35 | public slots:
36 | void setTitleBarHeight(int value);
37 | public:
38 | int titleBarHeight() const;
39 |
40 | signals:
41 | void scaleFactorChanged(qreal factor);
42 | public:
43 | qreal scaleFactor() const;
44 |
45 | signals:
46 | void maximizedChanged(bool maximized);
47 | public:
48 | bool isMaximized() const;
49 |
50 | public slots:
51 | void triggerMinimizeButtonAction();
52 | void triggerMaximizeButtonAction();
53 | void triggerCloseButtonAction();
54 |
55 | protected:
56 | bool eventFilter(QObject *obj, QEvent *ev) final;
57 | protected:
58 | QScopedPointer d_ptr;
59 | };
60 |
61 | #endif // FRAMELESSHELPER_H
62 |
--------------------------------------------------------------------------------
/FramelessHelper/FramelessHelper.pri:
--------------------------------------------------------------------------------
1 | QT += winextras
2 |
3 | INCLUDEPATH += $$PWD
4 | LIBS += -lUser32
5 |
6 | HEADERS += \
7 | $$PWD/FramelessHelper.h \
8 | $$PWD/FramelessHelper_p.h \
9 | $$PWD/WindowFramelessHelper.h \
10 | $$PWD/WindowFramelessHelper_p.h
11 | SOURCES += \
12 | $$PWD/FramelessHelper.cpp \
13 | $$PWD/WindowFramelessHelper.cpp
14 |
15 | HEADERS += \
16 | $$PWD/Kernels/NativeWindowFilter.h \
17 | $$PWD/Kernels/NativeWindowFilter_p.h \
18 | $$PWD/Kernels/NativeWindowHelper.h \
19 | $$PWD/Kernels/NativeWindowHelper_p.h
20 | SOURCES += \
21 | $$PWD/Kernels/NativeWindowFilter.cpp \
22 | $$PWD/Kernels/NativeWindowHelper.cpp
23 |
--------------------------------------------------------------------------------
/FramelessHelper/FramelessHelper_p.h:
--------------------------------------------------------------------------------
1 | #ifndef STYLEDHELPER_P_H
2 | #define STYLEDHELPER_P_H
3 |
4 | #include
5 |
6 | #include "FramelessHelper.h"
7 |
8 | #include "Kernels/NativeWindowHelper.h"
9 |
10 | class FramelessHelperPrivate : public NativeWindowTester
11 | {
12 | public:
13 | FramelessHelperPrivate();
14 | virtual ~FramelessHelperPrivate();
15 |
16 | public:
17 | QMargins draggableMargins() const final;
18 | QMargins maximizedMargins() const final;
19 |
20 | bool hitTest(const QPoint &pos) const final;
21 |
22 | public:
23 | QWidget *window;
24 | NativeWindowHelper *helper;
25 | public:
26 | QMargins priDraggableMargins;
27 | QMargins priMaximizedMargins;
28 | public:
29 | QSet extraTitleBars;
30 | int titleBarHeight;
31 | public:
32 | QSet includeItems;
33 | QSet excludeItems;
34 |
35 | public:
36 | bool maximized;
37 | };
38 |
39 | #endif // STYLEDHELPER_P_H
40 |
--------------------------------------------------------------------------------
/FramelessHelper/Kernels/NativeWindowFilter.cpp:
--------------------------------------------------------------------------------
1 | #include "NativeWindowFilter.h"
2 | #include "NativeWindowFilter_p.h"
3 |
4 | #include
5 | #include
6 | #include "NativeWindowHelper_p.h"
7 |
8 | // class NativeWindowFilter
9 |
10 | void NativeWindowFilter::deliver(QWindow *window, NativeWindowHelper *helper)
11 | {
12 | Q_CHECK_PTR(window);
13 |
14 | if (!NativeWindowFilterPrivate::instance) {
15 | QCoreApplication *appc = QCoreApplication::instance();
16 | if (appc) {
17 | auto filter = new NativeWindowFilter();
18 | NativeWindowFilterPrivate::instance.reset(filter);
19 | appc->installNativeEventFilter(filter);
20 | }
21 | }
22 |
23 | if (helper) {
24 | WId newId = window->winId();
25 | WId oldId = NativeWindowFilterPrivate::windows.value(helper);
26 | if (newId != oldId) {
27 | NativeWindowFilterPrivate::helpers.insert(newId, helper);
28 | NativeWindowFilterPrivate::helpers.remove(oldId);
29 | NativeWindowFilterPrivate::windows.insert(helper, newId);
30 |
31 | NativeWindowFilterPrivate::winIds.insert(window, newId);
32 | }
33 | } else {
34 | WId oldId = NativeWindowFilterPrivate::winIds.take(window);
35 | NativeWindowHelper *helper = NativeWindowFilterPrivate::helpers.take(oldId);
36 | NativeWindowFilterPrivate::windows.remove(helper);
37 | }
38 | }
39 |
40 | bool NativeWindowFilter::nativeEventFilter(const QByteArray &eventType,
41 | void *message, long *result)
42 | {
43 | Q_UNUSED(eventType);
44 |
45 | LPMSG msg = reinterpret_cast(message);
46 | if (auto h = NativeWindowFilterPrivate::helpers.value(reinterpret_cast(msg->hwnd)))
47 | return h->nativeEventFilter(msg, result);
48 |
49 | return false;
50 | }
51 |
52 | // class NativeWindowFilterPrivate
53 |
54 | QScopedPointer NativeWindowFilterPrivate::instance;
55 |
56 | QHash NativeWindowFilterPrivate::windows;
57 | QHash NativeWindowFilterPrivate::winIds;
58 | QHash NativeWindowFilterPrivate::helpers;
59 |
--------------------------------------------------------------------------------
/FramelessHelper/Kernels/NativeWindowFilter.h:
--------------------------------------------------------------------------------
1 | #ifndef NATIVEWINDOWFILTER_H
2 | #define NATIVEWINDOWFILTER_H
3 |
4 | #include
5 |
6 | class QWindow;
7 | class NativeWindowHelper;
8 |
9 | class NativeWindowFilter : public QAbstractNativeEventFilter
10 | {
11 | public:
12 | static void deliver(QWindow *window, NativeWindowHelper *helper);
13 | protected:
14 | bool nativeEventFilter(const QByteArray &eventType,
15 | void *message, long *result) final;
16 | };
17 |
18 | #endif // NATIVEWINDOWFILTER_H
19 |
--------------------------------------------------------------------------------
/FramelessHelper/Kernels/NativeWindowFilter_p.h:
--------------------------------------------------------------------------------
1 | #ifndef NATIVEWINDOWFILTER_P_H
2 | #define NATIVEWINDOWFILTER_P_H
3 |
4 | #include
5 | #include
6 |
7 | #include "NativeWindowFilter.h"
8 |
9 | class NativeWindowFilterPrivate
10 | {
11 | public:
12 | static QScopedPointer instance;
13 |
14 | static QHash windows;
15 | static QHash winIds;
16 | static QHash helpers;
17 | };
18 |
19 | #endif // NATIVEWINDOWFILTER_P_H
20 |
--------------------------------------------------------------------------------
/FramelessHelper/Kernels/NativeWindowHelper.cpp:
--------------------------------------------------------------------------------
1 | #include "NativeWindowHelper.h"
2 | #include "NativeWindowHelper_p.h"
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 | #include
10 | #include
11 |
12 | #include
13 |
14 | #include "NativeWindowFilter.h"
15 |
16 | #if defined(__GNUC__)
17 | //我电脑上的mingw报错,说没定义,那咋就给它定义一个
18 | //make mingw happy
19 | #define WM_DPICHANGED 0x02E0
20 | #endif
21 |
22 | // class NativeWindowHelper
23 |
24 | NativeWindowHelper::NativeWindowHelper(QWindow *window, NativeWindowTester *tester)
25 | : QObject(window)
26 | , d_ptr(new NativeWindowHelperPrivate())
27 | {
28 | d_ptr->q_ptr = this;
29 |
30 | Q_D(NativeWindowHelper);
31 |
32 | Q_CHECK_PTR(window);
33 | Q_CHECK_PTR(tester);
34 |
35 | d->window = window;
36 | d->tester = tester;
37 |
38 | if (d->window) {
39 | d->scaleFactor = d->window->screen()->devicePixelRatio();
40 |
41 | if (d->window->flags() & Qt::FramelessWindowHint) {
42 | d->window->installEventFilter(this);
43 | d->updateWindowStyle();
44 | }
45 | }
46 | }
47 |
48 | NativeWindowHelper::NativeWindowHelper(QWindow *window)
49 | : QObject(window)
50 | , d_ptr(new NativeWindowHelperPrivate())
51 | {
52 | d_ptr->q_ptr = this;
53 |
54 | Q_D(NativeWindowHelper);
55 |
56 | Q_CHECK_PTR(window);
57 | d->window = window;
58 |
59 | if (d->window) {
60 | d->scaleFactor = d->window->screen()->devicePixelRatio();
61 |
62 | if (d->window->flags() & Qt::FramelessWindowHint) {
63 | d->window->installEventFilter(this);
64 | d->updateWindowStyle();
65 | }
66 | }
67 | }
68 |
69 | NativeWindowHelper::~NativeWindowHelper()
70 | {
71 | }
72 |
73 | bool NativeWindowHelper::nativeEventFilter(void *msg, long *result)
74 | {
75 | Q_D(NativeWindowHelper);
76 |
77 | Q_CHECK_PTR(d->window);
78 |
79 | LPMSG lpMsg = reinterpret_cast(msg);
80 | WPARAM wParam = lpMsg->wParam;
81 | LPARAM lParam = lpMsg->lParam;
82 |
83 | if (WM_NCHITTEST == lpMsg->message) {
84 | *result = d->hitTest(GET_X_LPARAM(lParam),
85 | GET_Y_LPARAM(lParam));
86 | return true;
87 | } else if (WM_NCACTIVATE == lpMsg->message) {
88 | if (!QtWin::isCompositionEnabled()) {
89 | if (result) *result = 1;
90 | return true;
91 | }
92 | } else if (WM_NCCALCSIZE == lpMsg->message) {
93 | if (TRUE == wParam) {
94 | if (d->isMaximized()) {
95 | NCCALCSIZE_PARAMS ¶ms = *reinterpret_cast(lParam);
96 |
97 | QRect g = d->availableGeometry();
98 | QMargins m = d->maximizedMargins();
99 |
100 | params.rgrc[0].top = g.top() - m.top();
101 | params.rgrc[0].left = g.left() - m.left();
102 | params.rgrc[0].right = g.right() + m.right() + 1;
103 | params.rgrc[0].bottom = g.bottom() + m.bottom() + 1;
104 | }
105 |
106 | if (result) *result = 0;
107 | return true;
108 | }
109 | } else if (WM_GETMINMAXINFO == lpMsg->message) {
110 | LPMINMAXINFO lpMinMaxInfo = reinterpret_cast(lParam);
111 |
112 | QRect g = d->availableGeometry();
113 | QMargins m = d->maximizedMargins();
114 |
115 | lpMinMaxInfo->ptMaxPosition.x = - m.left();
116 | lpMinMaxInfo->ptMaxPosition.y = - m.top();
117 | lpMinMaxInfo->ptMaxSize.x = g.right() - g.left() + 1 + m.left() + m.right();
118 | lpMinMaxInfo->ptMaxSize.y = g.bottom() - g.top() + 1 + m.top() + m.bottom();
119 |
120 | lpMinMaxInfo->ptMinTrackSize.x = d->window->minimumWidth();
121 | lpMinMaxInfo->ptMinTrackSize.y = d->window->minimumHeight();
122 | lpMinMaxInfo->ptMaxTrackSize.x = d->window->maximumWidth();
123 | lpMinMaxInfo->ptMaxTrackSize.y = d->window->maximumHeight();
124 |
125 | if (result) *result = 0;
126 | return true;
127 | } else if (WM_NCLBUTTONDBLCLK == lpMsg->message) {
128 | auto minimumSize = d->window->minimumSize();
129 | auto maximumSize = d->window->maximumSize();
130 | if ((minimumSize.width() >= maximumSize.width())
131 | || (minimumSize.height() >= maximumSize.height())) {
132 | if (result) *result = 0;
133 | return true;
134 | }
135 | } else if (WM_DPICHANGED == lpMsg->message) {
136 | qreal old = d->scaleFactor;
137 | if (HIWORD(wParam) < 144) {
138 | d->scaleFactor = 1.0;
139 | } else {
140 | d->scaleFactor = 2.0;
141 | }
142 |
143 | if (!qFuzzyCompare(old, d->scaleFactor)) {
144 | emit scaleFactorChanged(d->scaleFactor);
145 | }
146 |
147 | auto hWnd = reinterpret_cast(d->window->winId());
148 | auto rect = reinterpret_cast(lParam);
149 | SetWindowPos(hWnd,
150 | NULL,
151 | rect->left,
152 | rect->top,
153 | rect->right - rect->left,
154 | rect->bottom - rect->top,
155 | SWP_NOZORDER | SWP_NOACTIVATE);
156 | }
157 |
158 | return false;
159 | }
160 |
161 | bool NativeWindowHelper::eventFilter(QObject *obj, QEvent *ev)
162 | {
163 | Q_D(NativeWindowHelper);
164 |
165 | if (ev->type() == QEvent::WinIdChange) {
166 | d->updateWindowStyle();
167 | } else if (ev->type() == QEvent::Show) {
168 | d->updateWindowStyle();
169 | }
170 |
171 | return QObject::eventFilter(obj, ev);
172 | }
173 |
174 | qreal NativeWindowHelper::scaleFactor() const
175 | {
176 | Q_D(const NativeWindowHelper);
177 |
178 | return d->scaleFactor;
179 | }
180 |
181 | // class NativeWindowHelperPrivate
182 |
183 | NativeWindowHelperPrivate::NativeWindowHelperPrivate()
184 | : q_ptr(nullptr)
185 | , window(nullptr)
186 | , tester(nullptr)
187 | , oldWindow(NULL)
188 | , scaleFactor(1.0)
189 | {
190 | }
191 |
192 | NativeWindowHelperPrivate::~NativeWindowHelperPrivate()
193 | {
194 | if (window)
195 | NativeWindowFilter::deliver(window, nullptr);
196 | }
197 |
198 | void NativeWindowHelperPrivate::updateWindowStyle()
199 | {
200 | Q_Q(NativeWindowHelper);
201 |
202 | Q_CHECK_PTR(window);
203 |
204 | HWND hWnd = reinterpret_cast(window->winId());
205 | if (NULL == hWnd)
206 | return;
207 | else if (oldWindow == hWnd) {
208 | return;
209 | }
210 | oldWindow = hWnd;
211 |
212 | NativeWindowFilter::deliver(window, q);
213 |
214 | QOperatingSystemVersion currentVersion = QOperatingSystemVersion::current();
215 | if (currentVersion < QOperatingSystemVersion::Windows8) {
216 | return;
217 | }
218 |
219 | LONG oldStyle = WS_OVERLAPPEDWINDOW | WS_THICKFRAME
220 | | WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX;;
221 | LONG newStyle = WS_POPUP | WS_THICKFRAME;
222 |
223 | if (QtWin::isCompositionEnabled())
224 | newStyle |= WS_CAPTION;
225 |
226 | if (window->flags() & Qt::CustomizeWindowHint) {
227 | if (window->flags() & Qt::WindowSystemMenuHint)
228 | newStyle |= WS_SYSMENU;
229 | if (window->flags() & Qt::WindowMinimizeButtonHint)
230 | newStyle |= WS_MINIMIZEBOX;
231 | if (window->flags() & Qt::WindowMaximizeButtonHint)
232 | newStyle |= WS_MAXIMIZEBOX;
233 | } else {
234 | newStyle |= WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
235 | }
236 |
237 | LONG currentStyle = GetWindowLong(hWnd, GWL_STYLE);
238 | SetWindowLong(hWnd, GWL_STYLE, (currentStyle & ~oldStyle) | newStyle);
239 |
240 | SetWindowPos(hWnd, NULL, 0, 0, 0 , 0,
241 | SWP_NOOWNERZORDER | SWP_NOZORDER |
242 | SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE);
243 |
244 | if (QtWin::isCompositionEnabled())
245 | QtWin::extendFrameIntoClientArea(window, 1, 1, 1, 1);
246 | }
247 |
248 | int NativeWindowHelperPrivate::hitTest(int x, int y) const
249 | {
250 | Q_CHECK_PTR(window);
251 |
252 | x = x / window->devicePixelRatio();
253 | y = y / window->devicePixelRatio();
254 |
255 | enum RegionMask {
256 | Client = 0x0000,
257 | Top = 0x0001,
258 | Left = 0x0010,
259 | Right = 0x0100,
260 | Bottom = 0x1000,
261 | };
262 |
263 | auto wfg = window->frameGeometry();
264 | QMargins draggableMargins
265 | = this->draggableMargins();
266 |
267 | int top = draggableMargins.top();
268 | int left = draggableMargins.left();
269 | int right = draggableMargins.right();
270 | int bottom = draggableMargins.bottom();
271 |
272 | if (top <= 0)
273 | top = GetSystemMetrics(SM_CYFRAME);
274 | if (left <= 0)
275 | left = GetSystemMetrics(SM_CXFRAME);
276 | if (right <= 0)
277 | right = GetSystemMetrics(SM_CXFRAME);
278 | if (bottom <= 0)
279 | bottom = GetSystemMetrics(SM_CYFRAME);
280 |
281 | auto result =
282 | (Top * (y < (wfg.top() + top))) |
283 | (Left * (x < (wfg.left() + left))) |
284 | (Right * (x > (wfg.right() - right))) |
285 | (Bottom * (y > (wfg.bottom() - bottom)));
286 |
287 | bool wResizable = window->minimumWidth() < window->maximumWidth();
288 | bool hResizable = window->minimumHeight() < window->maximumHeight();
289 |
290 | switch (result) {
291 | case Top | Left : return wResizable && hResizable ? HTTOPLEFT : HTCLIENT;
292 | case Top : return hResizable ? HTTOP : HTCLIENT;
293 | case Top | Right : return wResizable && hResizable ? HTTOPRIGHT : HTCLIENT;
294 | case Right : return wResizable ? HTRIGHT : HTCLIENT;
295 | case Bottom | Right: return wResizable && hResizable ? HTBOTTOMRIGHT : HTCLIENT;
296 | case Bottom : return hResizable ? HTBOTTOM : HTCLIENT;
297 | case Bottom | Left : return wResizable && hResizable ? HTBOTTOMLEFT : HTCLIENT;
298 | case Left : return wResizable ? HTLEFT : HTCLIENT;
299 | }
300 |
301 | auto pos = window->mapFromGlobal(QPoint(x, y));
302 | return ((nullptr != tester) && !tester->hitTest(pos)) ? HTCLIENT : HTCAPTION;
303 | }
304 |
305 | bool NativeWindowHelperPrivate::isMaximized() const
306 | {
307 | Q_CHECK_PTR(window);
308 |
309 | HWND hWnd = reinterpret_cast(window->winId());
310 | if (NULL == hWnd)
311 | return false;
312 |
313 | WINDOWPLACEMENT windowPlacement;
314 | if (!GetWindowPlacement(hWnd, &windowPlacement))
315 | return false;
316 |
317 | return (SW_MAXIMIZE == windowPlacement.showCmd);
318 | }
319 |
320 | QMargins NativeWindowHelperPrivate::draggableMargins() const
321 | {
322 | return tester ? tester->draggableMargins() * scaleFactor : QMargins();
323 | }
324 |
325 | QMargins NativeWindowHelperPrivate::maximizedMargins() const
326 | {
327 | return tester ? tester->maximizedMargins() * scaleFactor : QMargins();
328 | }
329 |
330 | QRect NativeWindowHelperPrivate::availableGeometry() const
331 | {
332 | MONITORINFO mi{0};
333 | mi.cbSize = sizeof(MONITORINFO);
334 |
335 | auto hWnd = reinterpret_cast(window->winId());
336 | auto hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
337 | if (!hMonitor || !GetMonitorInfoW(hMonitor, &mi)) {
338 | Q_ASSERT(NULL != hMonitor);
339 | return window->screen()->availableGeometry();
340 | }
341 |
342 | return QRect(mi.rcWork.left, mi.rcWork.top, mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top);
343 | }
344 |
--------------------------------------------------------------------------------
/FramelessHelper/Kernels/NativeWindowHelper.h:
--------------------------------------------------------------------------------
1 | #ifndef NATIVEWINDOWHELPER_H
2 | #define NATIVEWINDOWHELPER_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | class NativeWindowTester
9 | {
10 | public:
11 | virtual QMargins draggableMargins() const = 0;
12 | virtual QMargins maximizedMargins() const = 0;
13 |
14 | virtual bool hitTest(const QPoint &pos) const = 0;
15 | };
16 |
17 | class NativeWindowHelperPrivate;
18 | class NativeWindowHelper : public QObject
19 | {
20 | Q_OBJECT
21 | Q_DECLARE_PRIVATE(NativeWindowHelper)
22 |
23 | public:
24 | NativeWindowHelper(QWindow *window, NativeWindowTester *tester);
25 | explicit NativeWindowHelper(QWindow *window);
26 | ~NativeWindowHelper();
27 |
28 | public:
29 | bool nativeEventFilter(void *msg, long *result);
30 | protected:
31 | bool eventFilter(QObject *obj, QEvent *ev) final;
32 | protected:
33 | QScopedPointer d_ptr;
34 |
35 | signals:
36 | void scaleFactorChanged(qreal factor);
37 | public:
38 | qreal scaleFactor() const;
39 | };
40 |
41 | #endif // NATIVEWINDOWHELPER_H
42 |
--------------------------------------------------------------------------------
/FramelessHelper/Kernels/NativeWindowHelper_p.h:
--------------------------------------------------------------------------------
1 | #ifndef NATIVEWINDOWHELPER_P_H
2 | #define NATIVEWINDOWHELPER_P_H
3 |
4 | #include "NativeWindowHelper.h"
5 |
6 | class NativeWindowHelperPrivate
7 | {
8 | Q_DECLARE_PUBLIC(NativeWindowHelper)
9 |
10 | public:
11 | NativeWindowHelperPrivate();
12 | virtual ~NativeWindowHelperPrivate();
13 | protected:
14 | NativeWindowHelper *q_ptr;
15 |
16 | public:
17 | void updateWindowStyle();
18 | int hitTest(int x, int y) const;
19 | bool isMaximized() const;
20 |
21 | public:
22 | QMargins draggableMargins() const;
23 | QMargins maximizedMargins() const;
24 | public:
25 | QWindow *window;
26 | NativeWindowTester *tester;
27 | public:
28 | HWND oldWindow;
29 |
30 | public:
31 | QRect availableGeometry() const;
32 | public:
33 | qreal scaleFactor;
34 | };
35 |
36 | #endif // NATIVEWINDOWHELPER_P_H
37 |
--------------------------------------------------------------------------------
/FramelessHelper/WindowFramelessHelper.cpp:
--------------------------------------------------------------------------------
1 | #include "WindowFramelessHelper.h"
2 | #include "WindowFramelessHelper_p.h"
3 |
4 | #include
5 |
6 | // class WindowFramelessHelper
7 |
8 | WindowFramelessHelper::WindowFramelessHelper(QObject *parent)
9 | : QObject(parent)
10 | , d_ptr(new WindowFramelessHelperPrivate())
11 | {
12 | }
13 |
14 | WindowFramelessHelper::~WindowFramelessHelper()
15 | {
16 | }
17 |
18 | void WindowFramelessHelper::classBegin()
19 | {
20 | }
21 |
22 | void WindowFramelessHelper::componentComplete()
23 | {
24 | Q_D(WindowFramelessHelper);
25 |
26 | auto obj = parent();
27 | while (nullptr != obj) {
28 | if (obj->inherits("QQuickRootItem")) {
29 | if (auto rootItem = qobject_cast(obj)) {
30 | if (auto window = rootItem->window()) {
31 | d->window = window;
32 |
33 | d->helper = new NativeWindowHelper(window, d);
34 | connect(d->helper, &NativeWindowHelper::scaleFactorChanged,
35 | this, &WindowFramelessHelper::scaleFactorChanged);
36 | if (!qFuzzyCompare(d->helper->scaleFactor(), 1.0)) {
37 | emit scaleFactorChanged();
38 | }
39 | }
40 |
41 | break;
42 | }
43 | }
44 |
45 | obj = obj->parent();
46 | }
47 | }
48 |
49 | void WindowFramelessHelper::setTopDraggableMargin(int dm)
50 | {
51 | Q_D(WindowFramelessHelper);
52 |
53 | if (dm != d->priDraggableMargins.top()) {
54 | d->priDraggableMargins.setTop(dm);
55 | emit topDraggableMarginChanged();
56 | }
57 | }
58 |
59 | void WindowFramelessHelper::setLeftDraggableMargin(int dm)
60 | {
61 | Q_D(WindowFramelessHelper);
62 |
63 | if (dm != d->priDraggableMargins.left()) {
64 | d->priDraggableMargins.setLeft(dm);
65 | emit leftDraggableMarginChanged();
66 | }
67 | }
68 |
69 | void WindowFramelessHelper::setRightDraggableMargin(int dm)
70 | {
71 | Q_D(WindowFramelessHelper);
72 |
73 | if (dm != d->priDraggableMargins.right()) {
74 | d->priDraggableMargins.setRight(dm);
75 | emit rightDraggableMarginChanged();
76 | }
77 | }
78 |
79 | void WindowFramelessHelper::setBottomDraggableMargin(int dm)
80 | {
81 | Q_D(WindowFramelessHelper);
82 |
83 | if (dm != d->priDraggableMargins.bottom()) {
84 | d->priDraggableMargins.setBottom(dm);
85 | emit bottomDraggableMarginChanged();
86 | }
87 | }
88 |
89 | int WindowFramelessHelper::topDraggableMargin() const
90 | {
91 | Q_D(const WindowFramelessHelper);
92 |
93 | return d->priDraggableMargins.top();
94 | }
95 |
96 | int WindowFramelessHelper::leftDraggableMargin() const
97 | {
98 | Q_D(const WindowFramelessHelper);
99 |
100 | return d->priDraggableMargins.left();
101 | }
102 |
103 | int WindowFramelessHelper::rightDraggableMargin() const
104 | {
105 | Q_D(const WindowFramelessHelper);
106 |
107 | return d->priDraggableMargins.right();
108 | }
109 |
110 | int WindowFramelessHelper::bottomDraggableMargin() const
111 | {
112 | Q_D(const WindowFramelessHelper);
113 |
114 | return d->priDraggableMargins.bottom();
115 | }
116 |
117 | void WindowFramelessHelper::setTopMaximizedMargin(int dm)
118 | {
119 | Q_D(WindowFramelessHelper);
120 |
121 | if (dm != d->priMaximizedMargins.top()) {
122 | d->priMaximizedMargins.setTop(dm);
123 | emit topMaximizedMarginChanged();
124 | }
125 | }
126 |
127 | void WindowFramelessHelper::setLeftMaximizedMargin(int dm)
128 | {
129 | Q_D(WindowFramelessHelper);
130 |
131 | if (dm != d->priMaximizedMargins.left()) {
132 | d->priMaximizedMargins.setLeft(dm);
133 | emit leftMaximizedMarginChanged();
134 | }
135 | }
136 |
137 | void WindowFramelessHelper::setRightMaximizedMargin(int dm)
138 | {
139 | Q_D(WindowFramelessHelper);
140 |
141 | if (dm != d->priMaximizedMargins.right()) {
142 | d->priMaximizedMargins.setRight(dm);
143 | emit rightMaximizedMarginChanged();
144 | }
145 | }
146 |
147 | void WindowFramelessHelper::setBottomMaximizedMargin(int dm)
148 | {
149 | Q_D(WindowFramelessHelper);
150 |
151 | if (dm != d->priMaximizedMargins.bottom()) {
152 | d->priMaximizedMargins.setBottom(dm);
153 | emit bottomMaximizedMarginChanged();
154 | }
155 | }
156 |
157 | int WindowFramelessHelper::topMaximizedMargin() const
158 | {
159 | Q_D(const WindowFramelessHelper);
160 |
161 | return d->priMaximizedMargins.top();
162 | }
163 |
164 | int WindowFramelessHelper::leftMaximizedMargin() const
165 | {
166 | Q_D(const WindowFramelessHelper);
167 |
168 | return d->priMaximizedMargins.left();
169 | }
170 |
171 | int WindowFramelessHelper::rightMaximizedMargin() const
172 | {
173 | Q_D(const WindowFramelessHelper);
174 |
175 | return d->priMaximizedMargins.right();
176 | }
177 |
178 | int WindowFramelessHelper::bottomMaximizedMargin() const
179 | {
180 | Q_D(const WindowFramelessHelper);
181 |
182 | return d->priMaximizedMargins.bottom();
183 | }
184 |
185 | void WindowFramelessHelper::addIncludeItem(QQuickItem *item)
186 | {
187 | Q_D(WindowFramelessHelper);
188 |
189 | d->includeItems.insert(item);
190 | }
191 |
192 | void WindowFramelessHelper::removeIncludeItem(QQuickItem *item)
193 | {
194 | Q_D(WindowFramelessHelper);
195 |
196 | d->includeItems.remove(item);
197 | }
198 |
199 | void WindowFramelessHelper::addExcludeItem(QQuickItem *item)
200 | {
201 | Q_D(WindowFramelessHelper);
202 |
203 | d->excludeItems.insert(item);
204 | }
205 |
206 | void WindowFramelessHelper::removeExcludeItem(QQuickItem *item)
207 | {
208 | Q_D(WindowFramelessHelper);
209 |
210 | d->excludeItems.remove(item);
211 | }
212 |
213 | void WindowFramelessHelper::setTitleBarHeight(int value)
214 | {
215 | Q_D(WindowFramelessHelper);
216 |
217 | if (value != d->titleBarHeight) {
218 | d->titleBarHeight = value;
219 | emit titleBarHeightChanged();
220 | }
221 | }
222 |
223 | int WindowFramelessHelper::titleBarHeight() const
224 | {
225 | Q_D(const WindowFramelessHelper);
226 |
227 | return d->titleBarHeight;
228 | }
229 |
230 | qreal WindowFramelessHelper::scaleFactor() const
231 | {
232 | Q_D(const WindowFramelessHelper);
233 |
234 | return d->helper ? d->helper->scaleFactor() : 1.0;
235 | }
236 |
237 | void WindowFramelessHelper::triggerMinimizeButtonAction()
238 | {
239 | Q_D(WindowFramelessHelper);
240 |
241 | if (d->window) {
242 | auto oldStates = d->window->windowStates();
243 | d->window->setWindowStates((oldStates & ~Qt::WindowActive) | Qt::WindowMinimized);
244 | }
245 | }
246 |
247 | void WindowFramelessHelper::triggerMaximizeButtonAction()
248 | {
249 | Q_D(WindowFramelessHelper);
250 |
251 | if (d->window) {
252 | if (QWindow::Maximized == d->window->visibility()) {
253 | d->window->showNormal();
254 | } else {
255 | d->window->showMaximized();
256 | }
257 | }
258 | }
259 |
260 | void WindowFramelessHelper::triggerCloseButtonAction()
261 | {
262 | Q_D(WindowFramelessHelper);
263 |
264 | if (d->window) {
265 | d->window->close();
266 | }
267 | }
268 |
269 | // class WindowFramelessHelperPrivate
270 |
271 | WindowFramelessHelperPrivate::WindowFramelessHelperPrivate()
272 | : window(nullptr)
273 | , helper(nullptr)
274 | , titleBarHeight(0)
275 | {
276 | }
277 |
278 | WindowFramelessHelperPrivate::~WindowFramelessHelperPrivate()
279 | {
280 | }
281 |
282 | QMargins WindowFramelessHelperPrivate::draggableMargins() const
283 | {
284 | return priDraggableMargins;
285 | }
286 |
287 | QMargins WindowFramelessHelperPrivate::maximizedMargins() const
288 | {
289 | return priMaximizedMargins;
290 | }
291 |
292 | bool WindowFramelessHelperPrivate::hitTest(const QPoint &pos) const
293 | {
294 | int scaledTitleBarHeight = titleBarHeight * helper->scaleFactor();
295 |
296 | if (!window)
297 | return false;
298 | else if (scaledTitleBarHeight == 0)
299 | return false;
300 | else if ((scaledTitleBarHeight > 0)
301 | && (pos.y() >= scaledTitleBarHeight))
302 | return false;
303 |
304 | auto rootItem = window->contentItem();
305 | if (nullptr == rootItem) {
306 | return false;
307 | }
308 |
309 | int currentIndex = -1;
310 | QQuickItem *items[32] = {0};
311 | auto child = rootItem;
312 | QPointF p = pos;
313 |
314 | while (child && (currentIndex < 31)) {
315 | items[++currentIndex] = child;
316 | auto grandchild = child->childAt(p.x(), p.y());
317 | if (nullptr == grandchild) {
318 | break;
319 | }
320 |
321 | p = child->mapToItem(grandchild, p);
322 | child = grandchild;
323 | }
324 |
325 | while (currentIndex > 0) {
326 | child = items[currentIndex];
327 | --currentIndex;
328 |
329 | if (includeItems.contains(child)) {
330 | break;
331 | } else if (excludeItems.contains(child)) {
332 | return false;
333 | } else if (rootItem == child) {
334 | break;
335 | }
336 | }
337 |
338 | return true;
339 | }
340 |
--------------------------------------------------------------------------------
/FramelessHelper/WindowFramelessHelper.h:
--------------------------------------------------------------------------------
1 | #ifndef WINDOWFRAMELESSHELPER_H
2 | #define WINDOWFRAMELESSHELPER_H
3 |
4 | #include
5 | #include
6 |
7 | class WindowFramelessHelperPrivate;
8 | class WindowFramelessHelper : public QObject, public QQmlParserStatus
9 | {
10 | Q_OBJECT
11 | Q_DECLARE_PRIVATE(WindowFramelessHelper)
12 |
13 | Q_PROPERTY(int topDraggableMargin READ topDraggableMargin WRITE setTopDraggableMargin NOTIFY topDraggableMarginChanged)
14 | Q_PROPERTY(int leftDraggableMargin READ leftDraggableMargin WRITE setLeftDraggableMargin NOTIFY leftDraggableMarginChanged)
15 | Q_PROPERTY(int rightDraggableMargin READ rightDraggableMargin WRITE setRightDraggableMargin NOTIFY rightDraggableMarginChanged)
16 | Q_PROPERTY(int bottomDraggableMargin READ bottomDraggableMargin WRITE setBottomDraggableMargin NOTIFY bottomDraggableMarginChanged)
17 |
18 | Q_PROPERTY(int topMaximizedMargin READ topMaximizedMargin WRITE setTopMaximizedMargin NOTIFY topMaximizedMarginChanged)
19 | Q_PROPERTY(int leftMaximizedMargin READ leftMaximizedMargin WRITE setLeftMaximizedMargin NOTIFY leftMaximizedMarginChanged)
20 | Q_PROPERTY(int rightMaximizedMargin READ rightMaximizedMargin WRITE setRightMaximizedMargin NOTIFY rightMaximizedMarginChanged)
21 | Q_PROPERTY(int bottomMaximizedMargin READ bottomMaximizedMargin WRITE setBottomMaximizedMargin NOTIFY bottomMaximizedMarginChanged)
22 |
23 | Q_PROPERTY(int titleBarHeight READ titleBarHeight WRITE setTitleBarHeight NOTIFY titleBarHeightChanged)
24 |
25 | Q_PROPERTY(qreal scaleFactor READ scaleFactor NOTIFY scaleFactorChanged)
26 |
27 | Q_INTERFACES(QQmlParserStatus)
28 |
29 | public:
30 | explicit WindowFramelessHelper(QObject *parent = nullptr);
31 | virtual ~WindowFramelessHelper();
32 |
33 | public:
34 | void classBegin() final;
35 | void componentComplete() final;
36 |
37 | signals:
38 | void topDraggableMarginChanged();
39 | void leftDraggableMarginChanged();
40 | void rightDraggableMarginChanged();
41 | void bottomDraggableMarginChanged();
42 | public:
43 | void setTopDraggableMargin(int dm);
44 | void setLeftDraggableMargin(int dm);
45 | void setRightDraggableMargin(int dm);
46 | void setBottomDraggableMargin(int dm);
47 | public:
48 | int topDraggableMargin() const;
49 | int leftDraggableMargin() const;
50 | int rightDraggableMargin() const;
51 | int bottomDraggableMargin() const;
52 |
53 | signals:
54 | void topMaximizedMarginChanged();
55 | void leftMaximizedMarginChanged();
56 | void rightMaximizedMarginChanged();
57 | void bottomMaximizedMarginChanged();
58 | public:
59 | void setTopMaximizedMargin(int dm);
60 | void setLeftMaximizedMargin(int dm);
61 | void setRightMaximizedMargin(int dm);
62 | void setBottomMaximizedMargin(int dm);
63 | public:
64 | int topMaximizedMargin() const;
65 | int leftMaximizedMargin() const;
66 | int rightMaximizedMargin() const;
67 | int bottomMaximizedMargin() const;
68 |
69 | public slots:
70 | void addIncludeItem(QQuickItem *item);
71 | void removeIncludeItem(QQuickItem *item);
72 | public slots:
73 | void addExcludeItem(QQuickItem *item);
74 | void removeExcludeItem(QQuickItem *item);
75 |
76 | signals:
77 | void titleBarHeightChanged();
78 | public slots:
79 | void setTitleBarHeight(int value);
80 | public:
81 | int titleBarHeight() const;
82 |
83 | signals:
84 | void scaleFactorChanged();
85 | public:
86 | qreal scaleFactor() const;
87 |
88 | public slots:
89 | void triggerMinimizeButtonAction();
90 | void triggerMaximizeButtonAction();
91 | void triggerCloseButtonAction();
92 |
93 | protected:
94 | QScopedPointer d_ptr;
95 | };
96 |
97 | #endif // WINDOWFRAMELESSHELPER_H
98 |
--------------------------------------------------------------------------------
/FramelessHelper/WindowFramelessHelper_p.h:
--------------------------------------------------------------------------------
1 | #ifndef QSHARKFRAMELESSHELPER_P_H
2 | #define QSHARKFRAMELESSHELPER_P_H
3 |
4 | #include
5 | #include
6 |
7 | #include "WindowFramelessHelper.h"
8 |
9 | #include "Kernels/NativeWindowHelper.h"
10 |
11 | class WindowFramelessHelperPrivate : public NativeWindowTester
12 | {
13 | public:
14 | WindowFramelessHelperPrivate();
15 | virtual ~WindowFramelessHelperPrivate();
16 |
17 | public:
18 | QMargins draggableMargins() const final;
19 | QMargins maximizedMargins() const final;
20 |
21 | bool hitTest(const QPoint &pos) const final;
22 |
23 | public:
24 | QQuickWindow *window;
25 | NativeWindowHelper *helper;
26 | public:
27 | QMargins priDraggableMargins;
28 | QMargins priMaximizedMargins;
29 | public:
30 | QSet extraTitleBars;
31 | int titleBarHeight;
32 | public:
33 | QSet includeItems;
34 | QSet excludeItems;
35 | };
36 |
37 | #endif // QSHARKFRAMELESSHELPER_P_H
38 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Qt开发者
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/MainWindow.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include "ui_mainwindow.h"
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 | #include "FramelessHelper.h"
10 |
11 | MainWindow::MainWindow(QWidget *parent)
12 | : QWidget(parent, Qt::FramelessWindowHint)
13 | , ui(new Ui::MainWindow())
14 | {
15 | ui->setupUi(this);
16 |
17 | setWindowTitle("Qt Widgets Inside");
18 |
19 | auto helper = new FramelessHelper(this);
20 | helper->setDraggableMargins(3, 3, 3, 3);
21 | helper->setMaximizedMargins(3, 3, 3, 3);
22 | helper->setTitleBarHeight(32);
23 |
24 | helper->addExcludeItem(ui->minimizeButton);
25 | helper->addExcludeItem(ui->maximizeButton);
26 | helper->addExcludeItem(ui->closeButton);
27 |
28 | connect(ui->minimizeButton, &QPushButton::clicked,
29 | helper, &FramelessHelper::triggerMinimizeButtonAction);
30 | connect(ui->maximizeButton, &QPushButton::clicked,
31 | helper, &FramelessHelper::triggerMaximizeButtonAction);
32 | connect(ui->closeButton, &QPushButton::clicked,
33 | helper, &FramelessHelper::triggerCloseButtonAction);
34 |
35 | connect(helper, &FramelessHelper::maximizedChanged,
36 | this, &MainWindow::updateMaximizeButton);
37 |
38 | ui->maximizeButton->setIcon(QIcon(QStringLiteral(":/res/maximize-button1.png")));
39 |
40 | QTimer::singleShot(100, this, &MainWindow::syncPosition);
41 | }
42 |
43 | MainWindow::~MainWindow()
44 | {
45 | delete ui;
46 | }
47 |
48 | void MainWindow::updateMaximizeButton(bool maximized)
49 | {
50 | if (maximized) {
51 | ui->maximizeButton->setIcon(QIcon(QStringLiteral(":/res/maximize-button2.png")));
52 | ui->maximizeButton->setToolTip(tr("Restore"));
53 | } else {
54 | ui->maximizeButton->setIcon(QIcon(QStringLiteral(":/res/maximize-button1.png")));
55 | ui->maximizeButton->setToolTip(tr("Maximize"));
56 | }
57 | }
58 |
59 | void MainWindow::paintEvent(QPaintEvent *event)
60 | {
61 | Q_UNUSED(event);
62 |
63 | QPainter painter(this);
64 | QImage backgroundImage(QStringLiteral(":/res/background.png"));
65 | painter.drawImage(contentsRect(), backgroundImage);
66 |
67 | /*
68 | painter.setPen(Qt::red);
69 | painter.drawRect(rect().adjusted(0, 0, -1, -1));
70 | painter.setPen(Qt::blue);
71 | painter.drawRect(rect().adjusted(4, 4, -5, -5));
72 | */
73 | }
74 |
75 | void MainWindow::syncPosition()
76 | {
77 | QWindow *window = windowHandle();
78 | QScreen *screen = window->screen();
79 |
80 | window->setX(screen->availableGeometry().width() / 2 + 10);
81 | }
82 |
--------------------------------------------------------------------------------
/MainWindow.h:
--------------------------------------------------------------------------------
1 | #ifndef MAINWINDOW_H
2 | #define MAINWINDOW_H
3 |
4 | #include
5 |
6 | namespace Ui {
7 | class MainWindow;
8 | }
9 |
10 | class MainWindow : public QWidget
11 | {
12 | Q_OBJECT
13 |
14 | public:
15 | explicit MainWindow(QWidget *parent = 0);
16 | virtual ~MainWindow();
17 |
18 | protected:
19 | void updateMaximizeButton(bool maximized);
20 | void paintEvent(QPaintEvent *event) final;
21 | private:
22 | Ui::MainWindow *ui;
23 |
24 | private:
25 | void syncPosition();
26 | };
27 |
28 | #endif // MAINWINDOW_H
29 |
--------------------------------------------------------------------------------
/MainWindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 300
11 |
12 |
13 |
14 | #minimizeButton {
15 | image: url(:/res/minimize-button1.png);
16 | }
17 |
18 | #minimizeButton, #maximizeButton {
19 | background-color: transparent;
20 | border-radius: 0px;
21 | }
22 |
23 | #minimizeButton:hover, #maximizeButton:hover {
24 | border-style: none;
25 | background-color: #80c7c7c7;
26 | }
27 |
28 | #minimizeButton:pressed, #maximizeButton:pressed {
29 | border-style: none;
30 | background-color: #80808080;
31 | }
32 |
33 | #closeButton {
34 | image: url(:/res/close-button1.png);
35 | background-color: transparent;
36 | border-radius: 0px;
37 | }
38 |
39 | #closeButton:hover {
40 | image: url(:/res/close-button2.png);
41 | border-style: none;
42 | background-color: #e81123;
43 | }
44 |
45 | #closeButton:pressed {
46 | image: url(:/res/close-button2.png);
47 | border-style: none;
48 | background-color: #8c0a15;
49 | }
50 |
51 | #label {
52 | color: "#fefefe";
53 | }
54 |
55 |
56 |
57 | 0
58 |
59 |
60 | 0
61 |
62 |
63 | 0
64 |
65 |
66 | 0
67 |
68 |
69 | 0
70 |
71 | -
72 |
73 |
74 | Qt::Horizontal
75 |
76 |
77 |
78 | 262
79 | 20
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 | 0
89 | 0
90 |
91 |
92 |
93 |
94 | 45
95 | 26
96 |
97 |
98 |
99 |
100 | 45
101 | 26
102 |
103 |
104 |
105 | Qt::NoFocus
106 |
107 |
108 | Qt::NoContextMenu
109 |
110 |
111 | Close
112 |
113 |
114 |
115 | 34
116 | 26
117 |
118 |
119 |
120 |
121 | -
122 |
123 |
124 |
125 | 0
126 | 0
127 |
128 |
129 |
130 |
131 | 45
132 | 26
133 |
134 |
135 |
136 |
137 | 45
138 | 26
139 |
140 |
141 |
142 | Qt::NoFocus
143 |
144 |
145 | Qt::NoContextMenu
146 |
147 |
148 | Maximize
149 |
150 |
151 |
152 | 34
153 | 26
154 |
155 |
156 |
157 |
158 | -
159 |
160 |
161 |
162 | 0
163 | 0
164 |
165 |
166 |
167 |
168 | 45
169 | 26
170 |
171 |
172 |
173 |
174 | 45
175 | 26
176 |
177 |
178 |
179 | Qt::NoFocus
180 |
181 |
182 | Qt::NoContextMenu
183 |
184 |
185 | Minimize
186 |
187 |
188 |
189 | 34
190 | 26
191 |
192 |
193 |
194 |
195 | -
196 |
197 |
198 |
199 | Arial
200 | 28
201 |
202 |
203 |
204 | Qt Widgets Inside
205 |
206 |
207 | Qt::AlignCenter
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FramelessHelper
2 |
3 | Qt based frameless window class, full features. Requires: Qt 5.9.6 +
4 |
5 | 
6 |
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "MainWindow.h"
6 | #include "WindowFramelessHelper.h"
7 |
8 | int main(int argc, char *argv[])
9 | {
10 | QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
11 |
12 | QApplication a(argc, argv);
13 |
14 | qmlRegisterType("QtShark.Window", 1, 0, "FramelessHelper");
15 |
16 | QQmlApplicationEngine engine;
17 | engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
18 | if (engine.rootObjects().isEmpty())
19 | return -1;
20 |
21 | MainWindow w;
22 | w.show();
23 |
24 | return a.exec();
25 | }
26 |
--------------------------------------------------------------------------------
/qml/CloseButton.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.9
2 | import QtQuick.Controls 2.2
3 | import QtQuick.Window 2.3
4 | import QtGraphicalEffects 1.0
5 |
6 | Button {
7 | id: control
8 |
9 | width: 45
10 | height: 26
11 |
12 | property string color: "black"
13 | property string colorHoverd: "white"
14 | property string colorPressed: "white"
15 | property string colorInactive: "#969696"
16 |
17 | property string bgcolorPressed: "#8c0a15"
18 | property string bgcolorHoverd: "#e81123"
19 | property string bgcolor: "transparent"
20 |
21 | property bool changeColor: true
22 | property bool active: changeColor ? Window.active : true
23 |
24 |
25 | contentItem: Item {
26 | Image {
27 | id: img
28 | width : 10
29 | height: 10
30 | visible: false
31 | anchors.centerIn: parent
32 | fillMode: Image.PreserveAspectFit
33 | source: "qrc:/res/close-button1.svg"
34 | }
35 |
36 | ColorOverlay {
37 | id: overLay
38 | anchors.fill: img
39 | source: img
40 | cached: true
41 | color: (control.down || control.hovered) ? control.colorHoverd:
42 | (control.active? control.color: control.colorInactive)
43 | }
44 | }
45 |
46 | background: Rectangle {
47 | visible: control.down || control.hovered
48 | color: control.down ? control.bgcolorPressed : (control.hovered ? control.bgcolorHoverd : control.bgcolor)
49 | }
50 |
51 |
52 | ToolTip.visible: hovered && !down
53 | ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
54 | ToolTip.text: qsTr("Close")
55 | }
56 |
57 |
58 |
--------------------------------------------------------------------------------
/qml/CustomTitleBar.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.0
2 |
3 | Item {
4 | id: titleBar
5 | anchors {
6 | top: parent.top
7 | left: parent.left
8 | right: parent.right
9 | }
10 |
11 | height: 28
12 | }
13 |
--------------------------------------------------------------------------------
/qml/MaximizeButton.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.9
2 | import QtQuick.Controls 2.2
3 | import QtQuick.Window 2.3
4 | import QtGraphicalEffects 1.0
5 |
6 | Button {
7 | id: control
8 |
9 | width: 45
10 | height: 26
11 |
12 | property string color: "black"
13 | property string colorHoverd: "white"
14 | property string colorPressed: "white"
15 | property string colorInactive: "#969696"
16 |
17 | property string bgcolorPressed: "#80808080"
18 | property string bgcolorHoverd: "#80c7c7c7"
19 | property string bgcolor: "transparent"
20 |
21 | property bool changeColor: true
22 | property bool active: changeColor ? Window.active : true
23 | property bool maximized: Window.Maximized === Window.visibility
24 |
25 | contentItem: Item {
26 | Image {
27 | id: img
28 | width : 10
29 | height: 10
30 | visible: false
31 | anchors.centerIn: parent
32 | fillMode: Image.PreserveAspectFit
33 | source: maximized ? "qrc:/res/maximize-button2.svg" : "qrc:/res/maximize-button1.svg"
34 | }
35 |
36 | ColorOverlay {
37 | id: overLay
38 | anchors.fill: img
39 | source: img
40 | cached: true
41 | color: (control.down || control.hovered) ? control.colorHoverd:
42 | (control.active? control.color: control.colorInactive)
43 |
44 | }
45 | }
46 |
47 | background: Rectangle {
48 | visible: control.down || control.hovered
49 | color: control.down ? control.bgcolorPressed : (control.hovered ? control.bgcolorHoverd : control.bgcolor)
50 | }
51 |
52 | ToolTip.visible: hovered && !down
53 | ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
54 | ToolTip.text: qsTr("Maximize")
55 | }
56 |
57 |
--------------------------------------------------------------------------------
/qml/MinimizeButton.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.9
2 | import QtQuick.Controls 2.2
3 | import QtQuick.Window 2.3
4 | import QtGraphicalEffects 1.0
5 |
6 | Button {
7 | id: control
8 |
9 | width: 45
10 | height: 26
11 |
12 | property string color: "black"
13 | property string colorHoverd: "white"
14 | property string colorPressed: "white"
15 | property string colorInactive: "#969696"
16 |
17 | property string bgcolorPressed: "#80808080"
18 | property string bgcolorHoverd: "#80c7c7c7"
19 | property string bgcolor: "transparent"
20 |
21 | property bool changeColor: true
22 | property bool active: changeColor ? Window.active : true
23 |
24 | contentItem: Item {
25 | Image {
26 | id: img
27 | width : 10
28 | height: 10
29 | visible: false
30 | anchors.centerIn: parent
31 | fillMode: Image.PreserveAspectFit
32 | source: "qrc:/res/minimize-button1.svg"
33 | }
34 |
35 | ColorOverlay {
36 | id: overLay
37 | anchors.fill: img
38 | source: img
39 | cached: true
40 | color: (control.down || control.hovered) ? control.colorHoverd:
41 | (control.active? control.color: control.colorInactive)
42 |
43 | }
44 | }
45 |
46 | background: Rectangle {
47 | visible: control.down || control.hovered
48 | color: control.down ? control.bgcolorPressed : (control.hovered ? control.bgcolorHoverd : control.bgcolor)
49 | }
50 |
51 | ToolTip.visible: hovered && !down
52 | ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
53 | ToolTip.text: qsTr("Minimize")
54 | }
55 |
--------------------------------------------------------------------------------
/qml/ThreeButtons.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.0
2 | import QtQuick.Window 2.3
3 |
4 | Row {
5 | id: control
6 |
7 | property var helper
8 | property bool active: Window.active
9 | property bool noWarning: false
10 | property string color: "black"
11 |
12 | anchors {
13 | top: parent.top
14 | right: parent.right
15 | margins: 1
16 | }
17 |
18 | MinimizeButton {
19 | color: control.color
20 | onClicked: {helper.triggerMinimizeButtonAction()}
21 | }
22 |
23 | MaximizeButton {
24 | color: control.color
25 | onClicked: {helper.triggerMaximizeButtonAction()}
26 | }
27 |
28 | CloseButton {
29 | color: control.color
30 | onClicked: {helper.triggerCloseButtonAction()}
31 | }
32 |
33 | Component.onCompleted: {
34 | if (!noWarning){
35 | var arr = parent.children
36 | if (control !== arr[arr.length-1]) {
37 | console.log("Warning: ThreeButtons is not the last element!")
38 | console.log("Note: You can disable this warning by setting noWarning to true")
39 | console.log("Warning: ThreeButtons 不是最后的一个元素, 小心它可能会被别的东西(比如图片)遮住而无法操作")
40 | console.log("Note: 可以将noWarning设为true来关掉这个警告")
41 | }
42 |
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/qml/WindowBorder.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.0
2 | import QtQuick.Window 2.3
3 |
4 | Rectangle {
5 | id: control
6 |
7 | property string foregroundColor: "#242424"
8 | property string backgroundColor: "#969696"
9 |
10 | property bool changeColor: true
11 | property bool active: changeColor?Window.active: true
12 |
13 | anchors.fill: parent
14 |
15 | border.width: 1
16 | color: "transparent"
17 | border.color: active ? foregroundColor : backgroundColor
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/qml/main.qml:
--------------------------------------------------------------------------------
1 | import QtQuick 2.9
2 | import QtQuick.Window 2.2
3 | import QtShark.Window 1.0
4 | import QtQuick.Controls 2.5
5 |
6 | Window {
7 | id: window
8 | visible: true
9 | width: 400
10 | height: 300
11 | title: qsTr("Qt Quick Inside")
12 |
13 | flags: Qt.Window | Qt.FramelessWindowHint
14 |
15 | FramelessHelper {
16 | id: framelessHelper
17 |
18 | titleBarHeight: 60
19 |
20 | Component.onCompleted: {
21 | addIncludeItem(titleBar)
22 | addExcludeItem(controls)
23 | }
24 | }
25 |
26 | Image {
27 | anchors.fill: parent
28 | source: "qrc:/res/background.png"
29 | }
30 |
31 |
32 | Text {
33 | id: txt
34 | anchors.horizontalCenter: parent.horizontalCenter
35 |
36 | anchors.verticalCenter: parent.verticalCenter
37 |
38 | text: "Qt Quick Inside"
39 | font {
40 | family: "Arial"
41 | pointSize: 28
42 | }
43 | color: "#fefefe"
44 |
45 | }
46 |
47 | Row {
48 | id: colorPicker
49 | width: parent.width
50 | anchors.top: txt.bottom
51 | anchors.topMargin: 20
52 | Slider {
53 | id: sr
54 | from: 0
55 | to: 1
56 | value: 0
57 | width: (parent.width - 20)/3
58 | }
59 | Slider {
60 | id: sg
61 | from: 0
62 | to: 1
63 | value: 0
64 | width: (parent.width - 20)/3
65 |
66 | }
67 | Slider {
68 | id: sb
69 | from: 0
70 | to: 1
71 | value: 0
72 | width: (parent.width - 20)/3
73 |
74 | }
75 |
76 | }
77 |
78 |
79 | CustomTitleBar {
80 | id: titleBar
81 | }
82 |
83 | WindowBorder {
84 | foregroundColor: Qt.rgba(sr.value,sg.value,sb.value,1)
85 | }
86 |
87 | ThreeButtons {
88 | id: controls
89 | helper: framelessHelper
90 | color: Qt.rgba(sr.value,sg.value,sb.value,1)
91 | }
92 |
93 | Component.onCompleted: {
94 | window.x = Screen.width / 2 - 410;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/res/background.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qtdevs/FramelessHelper/0f6c0041cfbe8dd9c045dba5456dae18693366e5/res/background.png
--------------------------------------------------------------------------------
/res/close-button1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qtdevs/FramelessHelper/0f6c0041cfbe8dd9c045dba5456dae18693366e5/res/close-button1.png
--------------------------------------------------------------------------------
/res/close-button1.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/res/close-button2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qtdevs/FramelessHelper/0f6c0041cfbe8dd9c045dba5456dae18693366e5/res/close-button2.png
--------------------------------------------------------------------------------
/res/maximize-button1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qtdevs/FramelessHelper/0f6c0041cfbe8dd9c045dba5456dae18693366e5/res/maximize-button1.png
--------------------------------------------------------------------------------
/res/maximize-button1.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/res/maximize-button2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qtdevs/FramelessHelper/0f6c0041cfbe8dd9c045dba5456dae18693366e5/res/maximize-button2.png
--------------------------------------------------------------------------------
/res/maximize-button2.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/res/minimize-button1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qtdevs/FramelessHelper/0f6c0041cfbe8dd9c045dba5456dae18693366e5/res/minimize-button1.png
--------------------------------------------------------------------------------
/res/minimize-button1.svg:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/window.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/qtdevs/FramelessHelper/0f6c0041cfbe8dd9c045dba5456dae18693366e5/window.png
--------------------------------------------------------------------------------