├── .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 | ![](window.png) 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 | 2 | closebtn 3 | 4 | 5 | 6 | 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 | 2 | max1 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/maximize-button2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qtdevs/FramelessHelper/0f6c0041cfbe8dd9c045dba5456dae18693366e5/res/maximize-button2.png -------------------------------------------------------------------------------- /res/maximize-button2.svg: -------------------------------------------------------------------------------- 1 | 2 | maxbtn2 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /res/minimize-button1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qtdevs/FramelessHelper/0f6c0041cfbe8dd9c045dba5456dae18693366e5/res/minimize-button1.png -------------------------------------------------------------------------------- /res/minimize-button1.svg: -------------------------------------------------------------------------------- 1 | 2 | minbtn 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qtdevs/FramelessHelper/0f6c0041cfbe8dd9c045dba5456dae18693366e5/window.png --------------------------------------------------------------------------------