diff --git a/src/FloatingDockContainer.cpp b/src/FloatingDockContainer.cpp index 18e7bfa..fa2510b 100644 --- a/src/FloatingDockContainer.cpp +++ b/src/FloatingDockContainer.cpp @@ -46,6 +46,9 @@ #include "DockWidget.h" #include "DockOverlay.h" +#ifdef Q_OS_WIN +#include +#endif #ifdef Q_OS_LINUX #include "linux/FloatingWidgetTitleBar.h" #include @@ -53,6 +56,302 @@ namespace ads { +#ifdef Q_OS_WIN +/** + * Just for debuging to convert windows message identifiers to strings + */ +static const char* windowsMessageString(int MessageId) +{ + switch (MessageId) + { + case 0: return "WM_NULL"; + case 1: return "WM_CREATE"; + case 2: return "WM_DESTROY"; + case 3: return "WM_MOVE"; + case 5: return "WM_SIZE"; + case 6: return "WM_ACTIVATE"; + case 7: return "WM_SETFOCUS"; + case 8: return "WM_KILLFOCUS"; + case 10: return "WM_ENABLE"; + case 11: return "WM_SETREDRAW"; + case 12: return "WM_SETTEXT"; + case 13: return "WM_GETTEXT"; + case 14: return "WM_GETTEXTLENGTH"; + case 15: return "WM_PAINT"; + case 16: return "WM_CLOSE"; + case 17: return "WM_QUERYENDSESSION"; + case 18: return "WM_QUIT"; + case 19: return "WM_QUERYOPEN"; + case 20: return "WM_ERASEBKGND"; + case 21: return "WM_SYSCOLORCHANGE"; + case 22: return "WM_ENDSESSION"; + case 24: return "WM_SHOWWINDOW"; + case 25: return "WM_CTLCOLOR"; + case 26: return "WM_WININICHANGE"; + case 27: return "WM_DEVMODECHANGE"; + case 28: return "WM_ACTIVATEAPP"; + case 29: return "WM_FONTCHANGE"; + case 30: return "WM_TIMECHANGE"; + case 31: return "WM_CANCELMODE"; + case 32: return "WM_SETCURSOR"; + case 33: return "WM_MOUSEACTIVATE"; + case 34: return "WM_CHILDACTIVATE"; + case 35: return "WM_QUEUESYNC"; + case 36: return "WM_GETMINMAXINFO"; + case 38: return "WM_PAINTICON"; + case 39: return "WM_ICONERASEBKGND"; + case 40: return "WM_NEXTDLGCTL"; + case 42: return "WM_SPOOLERSTATUS"; + case 43: return "WM_DRAWITEM"; + case 44: return "WM_MEASUREITEM"; + case 45: return "WM_DELETEITEM"; + case 46: return "WM_VKEYTOITEM"; + case 47: return "WM_CHARTOITEM"; + case 48: return "WM_SETFONT"; + case 49: return "WM_GETFONT"; + case 50: return "WM_SETHOTKEY"; + case 51: return "WM_GETHOTKEY"; + case 55: return "WM_QUERYDRAGICON"; + case 57: return "WM_COMPAREITEM"; + case 61: return "WM_GETOBJECT"; + case 65: return "WM_COMPACTING"; + case 68: return "WM_COMMNOTIFY"; + case 70: return "WM_WINDOWPOSCHANGING"; + case 71: return "WM_WINDOWPOSCHANGED"; + case 72: return "WM_POWER"; + case 73: return "WM_COPYGLOBALDATA"; + case 74: return "WM_COPYDATA"; + case 75: return "WM_CANCELJOURNAL"; + case 78: return "WM_NOTIFY"; + case 80: return "WM_INPUTLANGCHANGEREQUEST"; + case 81: return "WM_INPUTLANGCHANGE"; + case 82: return "WM_TCARD"; + case 83: return "WM_HELP"; + case 84: return "WM_USERCHANGED"; + case 85: return "WM_NOTIFYFORMAT"; + case 123: return "WM_CONTEXTMENU"; + case 124: return "WM_STYLECHANGING"; + case 125: return "WM_STYLECHANGED"; + case 126: return "WM_DISPLAYCHANGE"; + case 127: return "WM_GETICON"; + case 128: return "WM_SETICON"; + case 129: return "WM_NCCREATE"; + case 130: return "WM_NCDESTROY"; + case 131: return "WM_NCCALCSIZE"; + case 132: return "WM_NCHITTEST"; + case 133: return "WM_NCPAINT"; + case 134: return "WM_NCACTIVATE"; + case 135: return "WM_GETDLGCODE"; + case 136: return "WM_SYNCPAINT"; + case 160: return "WM_NCMOUSEMOVE"; + case 161: return "WM_NCLBUTTONDOWN"; + case 162: return "WM_NCLBUTTONUP"; + case 163: return "WM_NCLBUTTONDBLCLK"; + case 164: return "WM_NCRBUTTONDOWN"; + case 165: return "WM_NCRBUTTONUP"; + case 166: return "WM_NCRBUTTONDBLCLK"; + case 167: return "WM_NCMBUTTONDOWN"; + case 168: return "WM_NCMBUTTONUP"; + case 169: return "WM_NCMBUTTONDBLCLK"; + case 171: return "WM_NCXBUTTONDOWN"; + case 172: return "WM_NCXBUTTONUP"; + case 173: return "WM_NCXBUTTONDBLCLK"; + case 176: return "EM_GETSEL"; + case 177: return "EM_SETSEL"; + case 178: return "EM_GETRECT"; + case 179: return "EM_SETRECT"; + case 180: return "EM_SETRECTNP"; + case 181: return "EM_SCROLL"; + case 182: return "EM_LINESCROLL"; + case 183: return "EM_SCROLLCARET"; + case 185: return "EM_GETMODIFY"; + case 187: return "EM_SETMODIFY"; + case 188: return "EM_GETLINECOUNT"; + case 189: return "EM_LINEINDEX"; + case 190: return "EM_SETHANDLE"; + case 191: return "EM_GETHANDLE"; + case 192: return "EM_GETTHUMB"; + case 193: return "EM_LINELENGTH"; + case 194: return "EM_REPLACESEL"; + case 195: return "EM_SETFONT"; + case 196: return "EM_GETLINE"; + case 197: return "EM_LIMITTEXT / EM_SETLIMITTEXT"; + case 198: return "EM_CANUNDO"; + case 199: return "EM_UNDO"; + case 200: return "EM_FMTLINES"; + case 201: return "EM_LINEFROMCHAR"; + case 202: return "EM_SETWORDBREAK"; + case 203: return "EM_SETTABSTOPS"; + case 204: return "EM_SETPASSWORDCHAR"; + case 205: return "EM_EMPTYUNDOBUFFER"; + case 206: return "EM_GETFIRSTVISIBLELINE"; + case 207: return "EM_SETREADONLY"; + case 209: return "EM_SETWORDBREAKPROC / EM_GETWORDBREAKPROC"; + case 210: return "EM_GETPASSWORDCHAR"; + case 211: return "EM_SETMARGINS"; + case 212: return "EM_GETMARGINS"; + case 213: return "EM_GETLIMITTEXT"; + case 214: return "EM_POSFROMCHAR"; + case 215: return "EM_CHARFROMPOS"; + case 216: return "EM_SETIMESTATUS"; + case 217: return "EM_GETIMESTATUS"; + case 224: return "SBM_SETPOS"; + case 225: return "SBM_GETPOS"; + case 226: return "SBM_SETRANGE"; + case 227: return "SBM_GETRANGE"; + case 228: return "SBM_ENABLE_ARROWS"; + case 230: return "SBM_SETRANGEREDRAW"; + case 233: return "SBM_SETSCROLLINFO"; + case 234: return "SBM_GETSCROLLINFO"; + case 235: return "SBM_GETSCROLLBARINFO"; + case 240: return "BM_GETCHECK"; + case 241: return "BM_SETCHECK"; + case 242: return "BM_GETSTATE"; + case 243: return "BM_SETSTATE"; + case 244: return "BM_SETSTYLE"; + case 245: return "BM_CLICK"; + case 246: return "BM_GETIMAGE"; + case 247: return "BM_SETIMAGE"; + case 248: return "BM_SETDONTCLICK"; + case 255: return "WM_INPUT"; + case 256: return "WM_KEYDOWN"; + case 257: return "WM_KEYUP"; + case 258: return "WM_CHAR"; + case 259: return "WM_DEADCHAR"; + case 260: return "WM_SYSKEYDOWN"; + case 261: return "WM_SYSKEYUP"; + case 262: return "WM_SYSCHAR"; + case 263: return "WM_SYSDEADCHAR"; + case 265: return "WM_UNICHAR / WM_WNT_CONVERTREQUESTEX"; + case 266: return "WM_CONVERTREQUEST"; + case 267: return "WM_CONVERTRESULT"; + case 268: return "WM_INTERIM"; + case 269: return "WM_IME_STARTCOMPOSITION"; + case 270: return "WM_IME_ENDCOMPOSITION"; + case 272: return "WM_INITDIALOG"; + case 273: return "WM_COMMAND"; + case 274: return "WM_SYSCOMMAND"; + case 275: return "WM_TIMER"; + case 276: return "WM_HSCROLL"; + case 277: return "WM_VSCROLL"; + case 278: return "WM_INITMENU"; + case 279: return "WM_INITMENUPOPUP"; + case 280: return "WM_SYSTIMER"; + case 287: return "WM_MENUSELECT"; + case 288: return "WM_MENUCHAR"; + case 289: return "WM_ENTERIDLE"; + case 290: return "WM_MENURBUTTONUP"; + case 291: return "WM_MENUDRAG"; + case 292: return "WM_MENUGETOBJECT"; + case 293: return "WM_UNINITMENUPOPUP"; + case 294: return "WM_MENUCOMMAND"; + case 295: return "WM_CHANGEUISTATE"; + case 296: return "WM_UPDATEUISTATE"; + case 297: return "WM_QUERYUISTATE"; + case 306: return "WM_CTLCOLORMSGBOX"; + case 307: return "WM_CTLCOLOREDIT"; + case 308: return "WM_CTLCOLORLISTBOX"; + case 309: return "WM_CTLCOLORBTN"; + case 310: return "WM_CTLCOLORDLG"; + case 311: return "WM_CTLCOLORSCROLLBAR"; + case 312: return "WM_CTLCOLORSTATIC"; + case 512: return "WM_MOUSEMOVE"; + case 513: return "WM_LBUTTONDOWN"; + case 514: return "WM_LBUTTONUP"; + case 515: return "WM_LBUTTONDBLCLK"; + case 516: return "WM_RBUTTONDOWN"; + case 517: return "WM_RBUTTONUP"; + case 518: return "WM_RBUTTONDBLCLK"; + case 519: return "WM_MBUTTONDOWN"; + case 520: return "WM_MBUTTONUP"; + case 521: return "WM_MBUTTONDBLCLK"; + case 522: return "WM_MOUSEWHEEL"; + case 523: return "WM_XBUTTONDOWN"; + case 524: return "WM_XBUTTONUP"; + case 525: return "WM_XBUTTONDBLCLK"; + case 528: return "WM_PARENTNOTIFY"; + case 529: return "WM_ENTERMENULOOP"; + case 530: return "WM_EXITMENULOOP"; + case 531: return "WM_NEXTMENU"; + case 532: return "WM_SIZING"; + case 533: return "WM_CAPTURECHANGED"; + case 534: return "WM_MOVING"; + case 536: return "WM_POWERBROADCAST"; + case 537: return "WM_DEVICECHANGE"; + case 544: return "WM_MDICREATE"; + case 545: return "WM_MDIDESTROY"; + case 546: return "WM_MDIACTIVATE"; + case 547: return "WM_MDIRESTORE"; + case 548: return "WM_MDINEXT"; + case 549: return "WM_MDIMAXIMIZE"; + case 550: return "WM_MDITILE"; + case 551: return "WM_MDICASCADE"; + case 552: return "WM_MDIICONARRANGE"; + case 553: return "WM_MDIGETACTIVE"; + case 560: return "WM_MDISETMENU"; + case 561: return "WM_ENTERSIZEMOVE"; + case 562: return "WM_EXITSIZEMOVE"; + case 563: return "WM_DROPFILES"; + case 564: return "WM_MDIREFRESHMENU"; + case 640: return "WM_IME_REPORT"; + case 641: return "WM_IME_SETCONTEXT"; + case 642: return "WM_IME_NOTIFY"; + case 643: return "WM_IME_CONTROL"; + case 644: return "WM_IME_COMPOSITIONFULL"; + case 645: return "WM_IME_SELECT"; + case 646: return "WM_IME_CHAR"; + case 648: return "WM_IME_REQUEST"; + case 656: return "WM_IME_KEYDOWN"; + case 657: return "WM_IME_KEYUP"; + case 672: return "WM_NCMOUSEHOVER"; + case 673: return "WM_MOUSEHOVER"; + case 674: return "WM_NCMOUSELEAVE"; + case 675: return "WM_MOUSELEAVE"; + case 768: return "WM_CUT"; + case 769: return "WM_COPY"; + case 770: return "WM_PASTE"; + case 771: return "WM_CLEAR"; + case 772: return "WM_UNDO"; + case 773: return "WM_RENDERFORMAT"; + case 774: return "WM_RENDERALLFORMATS"; + case 775: return "WM_DESTROYCLIPBOARD"; + case 776: return "WM_DRAWCLIPBOARD"; + case 777: return "WM_PAINTCLIPBOARD"; + case 778: return "WM_VSCROLLCLIPBOARD"; + case 779: return "WM_SIZECLIPBOARD"; + case 780: return "WM_ASKCBFORMATNAME"; + case 781: return "WM_CHANGECBCHAIN"; + case 782: return "WM_HSCROLLCLIPBOARD"; + case 783: return "WM_QUERYNEWPALETTE"; + case 784: return "WM_PALETTEISCHANGING"; + case 785: return "WM_PALETTECHANGED"; + case 786: return "WM_HOTKEY"; + case 791: return "WM_PRINT"; + case 792: return "WM_PRINTCLIENT"; + case 793: return "WM_APPCOMMAND"; + case 856: return "WM_HANDHELDFIRST"; + case 863: return "WM_HANDHELDLAST"; + case 864: return "WM_AFXFIRST"; + case 895: return "WM_AFXLAST"; + case 896: return "WM_PENWINFIRST"; + case 897: return "WM_RCRESULT"; + case 898: return "WM_HOOKRCRESULT"; + case 899: return "WM_GLOBALRCCHANGE / WM_PENMISCINFO"; + case 900: return "WM_SKB"; + case 901: return "WM_HEDITCTL / WM_PENCTL"; + case 902: return "WM_PENMISC"; + case 903: return "WM_CTLINIT"; + case 904: return "WM_PENEVENT"; + case 911: return "WM_PENWINLAST"; + default: + return "unknown WM_ message"; + } + + return "unknown WM_ message"; +} +#endif + + static unsigned int zOrderCounter = 0; /** * Private data class of CFloatingDockContainer class (pimpl) @@ -379,36 +678,59 @@ void CFloatingDockContainer::changeEvent(QEvent *event) } } -//============================================================================ -void CFloatingDockContainer::moveEvent(QMoveEvent *event) -{ - QWidget::moveEvent(event); - switch (d->DraggingState) - { - case DraggingMousePressed: + #ifdef Q_OS_WIN - qApp->installEventFilter(this); -#endif - d->setState(DraggingFloatingWidget); - d->updateDropOverlays(QCursor::pos()); +//============================================================================ +bool CFloatingDockContainer::nativeEvent(const QByteArray &eventType, void *message, long *result) +{ + QWidget::nativeEvent(eventType, message, result); + MSG *msg = static_cast(message); + switch (msg->message) + { + case WM_MOVING: + { + if (d->isState(DraggingFloatingWidget)) + { + d->updateDropOverlays(QCursor::pos()); + } + } break; - case DraggingFloatingWidget: - d->updateDropOverlays(QCursor::pos()); -#ifdef Q_OS_MACOS - // In OSX when hiding the DockAreaOverlay the application would set - // the main window as the active window for some reason. This fixes - // that by resetting the active window to the floating widget after - // updating the overlays. - QApplication::setActiveWindow(this); -#endif - break; - default: - break; + case WM_NCLBUTTONDOWN: + if (msg->wParam == HTCAPTION && d->isState(DraggingInactive)) + { + ADS_PRINT("CFloatingDockContainer::nativeEvent WM_NCLBUTTONDOWN" << e->type()); + d->DragStartPos = pos(); + d->setState(DraggingMousePressed); + } + break; + + case WM_NCLBUTTONDBLCLK: + d->setState(DraggingInactive); + break; + + case WM_ENTERSIZEMOVE: + if (d->isState(DraggingMousePressed)) + { + ADS_PRINT("CFloatingDockContainer::nativeEvent WM_ENTERSIZEMOVE" << e->type()); + qApp->installEventFilter(this); + d->setState(DraggingFloatingWidget); + d->updateDropOverlays(QCursor::pos()); + } + break; + + case WM_EXITSIZEMOVE: + if (d->isState(DraggingFloatingWidget)) + { + ADS_PRINT("CFloatingDockContainer::nativeEvent WM_EXITSIZEMOVE" << e->type());; + d->titleMouseReleaseEvent(); + } + break; } - - + return false; } +#endif + //============================================================================ void CFloatingDockContainer::closeEvent(QCloseEvent *event) @@ -474,80 +796,6 @@ void CFloatingDockContainer::showEvent(QShowEvent *event) } -//============================================================================ -bool CFloatingDockContainer::event(QEvent *e) -{ - switch (d->DraggingState) - { - case DraggingInactive: - { - // Normally we would check here, if the left mouse button is pressed. - // But from QT version 5.12.2 on the mouse events from - // QEvent::NonClientAreaMouseButtonPress return the wrong mouse button - // The event always returns Qt::RightButton even if the left button - // is clicked. - // It is really great to work around the whole NonClientMouseArea - // bugs -#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 2)) - if (e->type() == QEvent::NonClientAreaMouseButtonPress /*&& QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)*/) -#else - if (e->type() == QEvent::NonClientAreaMouseButtonPress && QGuiApplication::mouseButtons().testFlag(Qt::LeftButton)) -#endif - { - ADS_PRINT("FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type()); - d->DragStartPos = pos(); - d->setState(DraggingMousePressed); - } - } - break; - - case DraggingMousePressed: - switch (e->type()) - { - case QEvent::NonClientAreaMouseButtonDblClick: - ADS_PRINT("FloatingWidget::event QEvent::NonClientAreaMouseButtonDblClick"); - d->setState(DraggingInactive); - break; - - case QEvent::Resize: - // If the first event after the mouse press is a resize event, then - // the user resizes the window instead of dragging it around. - // But there is one exception. If the window is maximized, - // then dragging the window via title bar will cause the widget to - // leave the maximized state. This in turn will trigger a resize event. - // To know, if the resize event was triggered by user via moving a - // corner of the window frame or if it was caused by a windows state - // change, we check, if we are not in maximized state. - if (!isMaximized()) - { - d->setState(DraggingInactive); - } - break; - - default: - break; - } - break; - - case DraggingFloatingWidget: - if (e->type() == QEvent::NonClientAreaMouseButtonRelease) - { - ADS_PRINT("FloatingWidget::event QEvent::NonClientAreaMouseButtonRelease"); - d->titleMouseReleaseEvent(); - } - break; - - default: - break; - } - -#if (ADS_DEBUG_LEVEL > 0) - qDebug() << QTime::currentTime() << "CFloatingDockContainer::event " << e->type(); -#endif - return QWidget::event(e); -} - - //============================================================================ bool CFloatingDockContainer::eventFilter(QObject *watched, QEvent *e) { @@ -617,6 +865,27 @@ void CFloatingDockContainer::moveFloating() const QPoint moveToPos = QCursor::pos() - d->DragStartMousePosition - QPoint(BorderSize, 0); move(moveToPos); + + switch (d->DraggingState) + { + case DraggingMousePressed: + d->setState(DraggingFloatingWidget); + d->updateDropOverlays(QCursor::pos()); + break; + + case DraggingFloatingWidget: + d->updateDropOverlays(QCursor::pos()); +#ifdef Q_OS_MACOS + // In OSX when hiding the DockAreaOverlay the application would set + // the main window as the active window for some reason. This fixes + // that by resetting the active window to the floating widget after + // updating the overlays. + QApplication::setActiveWindow(this); +#endif + break; + default: + break; + } } //============================================================================ diff --git a/src/FloatingDockContainer.h b/src/FloatingDockContainer.h index fc92f7d..5800a33 100644 --- a/src/FloatingDockContainer.h +++ b/src/FloatingDockContainer.h @@ -176,13 +176,19 @@ protected: protected: // reimplements QWidget virtual void changeEvent(QEvent *event) override; - virtual void moveEvent(QMoveEvent *event) override; - virtual bool event(QEvent *e) override; virtual void closeEvent(QCloseEvent *event) override; virtual void hideEvent(QHideEvent *event) override; virtual void showEvent(QShowEvent *event) override; virtual bool eventFilter(QObject *watched, QEvent *event) override; +#ifdef Q_OS_WIN + /** + * Native event filter for handling WM_MOVING messages on Windows + */ + virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override; +#endif + + public: using Super = QWidget; diff --git a/src/FloatingDragPreview.cpp b/src/FloatingDragPreview.cpp index 61acbd1..8f24a86 100644 --- a/src/FloatingDragPreview.cpp +++ b/src/FloatingDragPreview.cpp @@ -297,6 +297,7 @@ void CFloatingDragPreview::moveFloating() const QPoint moveToPos = QCursor::pos() - d->DragStartMousePosition - QPoint(BorderSize, 0); move(moveToPos); + d->updateDropOverlays(QCursor::pos()); } @@ -314,14 +315,6 @@ void CFloatingDragPreview::startFloating(const QPoint &DragStartMousePos, } -//============================================================================ -void CFloatingDragPreview::moveEvent(QMoveEvent *event) -{ - QWidget::moveEvent(event); - d->updateDropOverlays(QCursor::pos()); -} - - //============================================================================ void CFloatingDragPreview::finishDragging() { diff --git a/src/FloatingDragPreview.h b/src/FloatingDragPreview.h index dca7083..d8c14b1 100644 --- a/src/FloatingDragPreview.h +++ b/src/FloatingDragPreview.h @@ -39,11 +39,6 @@ private slots: void onApplicationStateChanged(Qt::ApplicationState state); protected: - /** - * Updates the drop overlays - */ - virtual void moveEvent(QMoveEvent *event) override; - /** * Cares about painting the */