KDDockWidgets API Documentation  1.6
WidgetResizeHandler.cpp
Go to the documentation of this file.
1 /*
2  This file is part of KDDockWidgets.
3 
4  SPDX-FileCopyrightText: 2019-2022 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5  Author: SĂ©rgio Martins <sergio.martins@kdab.com>
6 
7  SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only
8 
9  Contact KDAB at <info@kdab.com> for commercial licensing options.
10 */
11 
12 #include "WidgetResizeHandler_p.h"
13 #include "FloatingWindow_p.h"
14 #include "TitleBar_p.h"
15 #include "DragController_p.h"
16 #include "Config.h"
17 #include "Qt5Qt6Compat_p.h"
18 #include "Utils_p.h"
19 #include "DockRegistry_p.h"
20 #include "MDILayoutWidget_p.h"
21 
22 #include <QEvent>
23 #include <QMouseEvent>
24 #include <QDebug>
25 #include <QGuiApplication>
26 #include <QScreen>
27 #include <QWindow>
28 #include <QScopedValueRollback>
29 
30 #if defined(Q_OS_WIN)
31 #include <QtGui/private/qhighdpiscaling_p.h>
32 #include <windowsx.h>
33 #include <windows.h>
34 #include <dwmapi.h>
35 #if defined(Q_CC_MSVC)
36 #pragma comment(lib, "Dwmapi.lib")
37 #pragma comment(lib, "User32.lib")
38 #endif
39 #endif
40 
41 using namespace KDDockWidgets;
42 
43 bool WidgetResizeHandler::s_disableAllHandlers = false;
44 WidgetResizeHandler::WidgetResizeHandler(EventFilterMode filterMode, WindowMode windowMode, QWidgetOrQuick *target)
45  : QObject(target)
46  , m_usesGlobalEventFilter(filterMode == EventFilterMode::Global)
47  , m_isTopLevelWindowResizer(windowMode == WindowMode::TopLevel)
48 {
49  setTarget(target);
50 }
51 
52 WidgetResizeHandler::~WidgetResizeHandler()
53 {
54 }
55 
56 void WidgetResizeHandler::setAllowedResizeSides(CursorPositions sides)
57 {
58  mAllowedResizeSides = sides;
59 }
60 
61 void WidgetResizeHandler::setResizeGap(int gap)
62 {
63  m_resizeGap = gap;
64 }
65 
66 bool WidgetResizeHandler::isMDI() const
67 {
68  auto frame = qobject_cast<Frame *>(mTarget);
69  return frame && frame->isMDI();
70 }
71 
72 bool WidgetResizeHandler::isResizing() const
73 {
74  return m_resizingInProgress;
75 }
76 
77 int WidgetResizeHandler::widgetResizeHandlerMargin()
78 {
79  return 4; // pixels
80 }
81 
82 bool WidgetResizeHandler::eventFilter(QObject *o, QEvent *e)
83 {
84  if (s_disableAllHandlers)
85  return false;
86 
87  auto widget = qobject_cast<QWidgetOrQuick *>(o);
88  if (!widget)
89  return false;
90 
91  auto me = mouseEvent(e);
92  if (!me)
93  return false;
94 
95  if (m_isTopLevelWindowResizer) {
96  // Case #1.0: Resizing FloatingWindow
97 
98  if (!widget->isTopLevel() || o != mTarget) {
99  if (m_usesGlobalEventFilter) {
100  // Case #1.1: FloatingWindows on EGLFS
101  // EGLFS doesn't support storing mouse cursor shape per window, so we need to use global filter
102  // do detect mouse leaving the window
103  if (!m_resizingInProgress) {
104  const QPoint globalPos = Qt5Qt6Compat::eventGlobalPos(me);
105  updateCursor(cursorPosition(globalPos));
106  }
107  }
108 
109  // Case #1.2: FloatingWindows on all other platforms
110  // Not needed to mess with the cursor, it gets set when moving over another window.
111  return false;
112  }
113  } else if (isMDI()) {
114  // Case #2: Resizing an embedded MDI "Window"
115 
116  // Each Frame has a WidgetResizeHandler instance.
117  // mTarget is the Frame we want to resize.
118  // but 'o' might not be mTarget, because we're using a global event filter.
119  // The global event filter is required because we allow the cursor to be outside the frame, a few pixels
120  // so we have a nice resize margin.
121  // Here we deal with the case where our mTarget, let's say "Frame 1" is on top of "Frame 2" but cursor
122  // is near "Frame 2"'s margins, and would show resize cursor.
123  // We only want to continue if the cursor is near the margins of our own frame (mTarget)
124 
125  auto frame = firstParentOfType<Frame>(widget);
126  if (frame && frame->isMDIWrapper()) {
127  // We don't care about the inner Option_MDINestable helper frame
128  frame = frame->mdiFrame();
129  }
130 
131  if (frame && frame != mTarget) {
132  const bool areSiblings = frame->QWidgetAdapter::parentWidget() == mTarget->parentWidget();
133  if (areSiblings)
134  return false;
135  }
136  }
137 
138  switch (e->type()) {
140  if (mTarget->isMaximized())
141  break;
142 
143  auto mouseEvent = static_cast<QMouseEvent *>(e);
144  auto cursorPos = cursorPosition(Qt5Qt6Compat::eventGlobalPos(mouseEvent));
145  updateCursor(cursorPos);
146  if (cursorPos == CursorPosition_Undefined)
147  return false;
148 
149  const int m = widgetResizeHandlerMargin();
150  const QRect widgetRect = mTarget->rect().marginsAdded(QMargins(m, m, m, m));
151  const QPoint cursorPoint = mTarget->mapFromGlobal(Qt5Qt6Compat::eventGlobalPos(mouseEvent));
152  if (!widgetRect.contains(cursorPoint) || mouseEvent->button() != Qt::LeftButton)
153  return false;
154 
155  m_resizingInProgress = true;
156  if (isMDI())
157  Q_EMIT DockRegistry::self()->frameInMDIResizeChanged();
158  mNewPosition = Qt5Qt6Compat::eventGlobalPos(mouseEvent);
159  mCursorPos = cursorPos;
160 
161  return true;
162  }
164  m_resizingInProgress = false;
165  if (isMDI()) {
166  Q_EMIT DockRegistry::self()->frameInMDIResizeChanged();
167  auto frame = static_cast<Frame *>(mTarget);
168  // Usually in KDDW all geometry changes are done in the layout items, which propagate to the widgets
169  // When resizing a MDI however, we're resizing the widget directly. So update the corresponding layout
170  // item when we're finished.
171  frame->mdiLayoutWidget()->setDockWidgetGeometry(frame, frame->QWidgetAdapter::geometry());
172  }
173  updateCursor(CursorPosition_Undefined);
174  auto mouseEvent = static_cast<QMouseEvent *>(e);
175 
176  if (mTarget->isMaximized() || !m_resizingInProgress || mouseEvent->button() != Qt::LeftButton)
177  break;
178 
179  mTarget->releaseMouse();
180  mTarget->releaseKeyboard();
181  return true;
182 
183  break;
184  }
185  case QEvent::MouseMove: {
186  if (mTarget->isMaximized())
187  break;
188 
189  if (isMDI()) {
190  const Frame *frameBeingResized = DockRegistry::self()->frameInMDIResize();
191  const bool otherFrameBeingResized = frameBeingResized && frameBeingResized != mTarget;
192  if (otherFrameBeingResized) {
193  // only one at a time!
194  return false;
195  }
196  }
197 
198  auto mouseEvent = static_cast<QMouseEvent *>(e);
199  m_resizingInProgress = m_resizingInProgress && (mouseEvent->buttons() & Qt::LeftButton);
200 
201  const bool consumed = mouseMoveEvent(mouseEvent);
202  return consumed;
203  }
204  default:
205  break;
206  }
207  return false;
208 }
209 
210 bool WidgetResizeHandler::mouseMoveEvent(QMouseEvent *e)
211 {
212  const QPoint globalPos = Qt5Qt6Compat::eventGlobalPos(e);
213  if (!m_resizingInProgress) {
214  const CursorPosition pos = cursorPosition(globalPos);
215  updateCursor(pos);
216  return pos != CursorPosition_Undefined;
217  }
218 
219  const QRect oldGeometry = KDDockWidgets::globalGeometry(mTarget);
220  QRect newGeometry = oldGeometry;
221 
222  QRect parentGeometry;
223  if (!mTarget->isTopLevel()) {
224  auto parent = KDDockWidgets::Private::parentWidget(mTarget);
225  parentGeometry = KDDockWidgets::globalGeometry(parent);
226  }
227 
228  {
229  int deltaWidth = 0;
230  int newWidth = 0;
231  const int maxWidth = Layouting::Widget::widgetMaxSize(mTarget).width();
232  const int minWidth = Layouting::Widget::widgetMinSize(mTarget).width();
233 
234  switch (mCursorPos) {
236  case CursorPosition_Left:
238  parentGeometry = parentGeometry.adjusted(0, m_resizeGap, 0, 0);
239  deltaWidth = oldGeometry.left() - globalPos.x();
240  newWidth = qBound(minWidth, mTarget->width() + deltaWidth, maxWidth);
241  deltaWidth = newWidth - mTarget->width();
242  if (deltaWidth != 0) {
243  newGeometry.setLeft(newGeometry.left() - deltaWidth);
244  }
245 
246  break;
247  }
248 
252  parentGeometry = parentGeometry.adjusted(0, 0, -m_resizeGap, 0);
253  deltaWidth = globalPos.x() - newGeometry.right();
254  newWidth = qBound(minWidth, mTarget->width() + deltaWidth, maxWidth);
255  deltaWidth = newWidth - mTarget->width();
256  if (deltaWidth != 0) {
257  newGeometry.setRight(oldGeometry.right() + deltaWidth);
258  }
259  break;
260  }
261  default:
262  break;
263  }
264  }
265 
266  {
267  const int maxHeight = Layouting::Widget::widgetMaxSize(mTarget).height();
268  const int minHeight = Layouting::Widget::widgetMinSize(mTarget).height();
269  int deltaHeight = 0;
270  int newHeight = 0;
271  switch (mCursorPos) {
273  case CursorPosition_Top:
275  parentGeometry = parentGeometry.adjusted(0, m_resizeGap, 0, 0);
276  deltaHeight = oldGeometry.top() - globalPos.y();
277  newHeight = qBound(minHeight, mTarget->height() + deltaHeight, maxHeight);
278  deltaHeight = newHeight - mTarget->height();
279  if (deltaHeight != 0) {
280  newGeometry.setTop(newGeometry.top() - deltaHeight);
281  }
282 
283  break;
284  }
285 
289  parentGeometry = parentGeometry.adjusted(0, 0, 0, -m_resizeGap);
290  deltaHeight = globalPos.y() - newGeometry.bottom();
291  newHeight = qBound(minHeight, mTarget->height() + deltaHeight, maxHeight);
292  deltaHeight = newHeight - mTarget->height();
293  if (deltaHeight != 0) {
294  newGeometry.setBottom(oldGeometry.bottom() + deltaHeight);
295  }
296  break;
297  }
298  default:
299  break;
300  }
301  }
302 
303  if (newGeometry == mTarget->geometry()) {
304  // Nothing to do.
305  return true;
306  }
307 
308  if (!mTarget->isTopLevel()) {
309 
310  // Clip to parent's geometry.
311  newGeometry = newGeometry.intersected(parentGeometry);
312 
313  // Back to local.
314  newGeometry.moveTopLeft(mTarget->mapFromGlobal(newGeometry.topLeft()) + mTarget->pos());
315  }
316 
317  mTarget->setGeometry(newGeometry);
318  return true;
319 }
320 
321 #ifdef Q_OS_WIN
322 
324 bool WidgetResizeHandler::handleWindowsNativeEvent(FloatingWindow *fw, const QByteArray &eventType,
325  void *message, Qt5Qt6Compat::qintptr *result)
326 {
327  if (eventType != "windows_generic_MSG")
328  return false;
329 
330  auto msg = static_cast<MSG *>(message);
331  if (msg->message == WM_NCHITTEST) {
332  if (DragController::instance()->isInClientDrag()) {
333  // There's a non-native drag going on.
334  *result = 0;
335  return false;
336  }
337 
338  const QRect htCaptionRect = fw->dragRect();
339  const bool ret = handleWindowsNativeEvent(fw->windowHandle(), msg, result, htCaptionRect);
340 
341  fw->setLastHitTest(*result);
342  return ret;
343  } else if (msg->message == WM_NCLBUTTONDBLCLK) {
344  if ((Config::self().flags() & Config::Flag_DoubleClickMaximizes)) {
345  return handleWindowsNativeEvent(fw->windowHandle(), msg, result, {});
346  } else {
347  // Let the title bar handle it. It will re-dock the window.
348  if (TitleBar *titleBar = fw->titleBar()) {
349  if (titleBar->isVisible()) { // can't be invisible afaik
350  titleBar->onDoubleClicked();
351  }
352  }
353 
354  return true;
355  }
356  }
357 
358  return handleWindowsNativeEvent(fw->windowHandle(), msg, result, {});
359 }
360 
361 bool WidgetResizeHandler::handleWindowsNativeEvent(QWindow *w, MSG *msg,
362  Qt5Qt6Compat::qintptr *result,
363  const NativeFeatures &features)
364 {
365  if (msg->message == WM_NCCALCSIZE && features.hasShadow()) {
366  *result = 0;
367  return true;
368  } else if (msg->message == WM_NCHITTEST && (features.hasResize() || features.hasDrag())) {
369  const int borderWidth = 8;
370  const bool hasFixedWidth = w->minimumWidth() == w->maximumWidth();
371  const bool hasFixedHeight = w->minimumHeight() == w->maximumHeight();
372 
373  *result = 0;
374  const int xPos = GET_X_LPARAM(msg->lParam);
375  const int yPos = GET_Y_LPARAM(msg->lParam);
376  RECT rect;
377  GetWindowRect(reinterpret_cast<HWND>(w->winId()), &rect);
378 
379  if (xPos >= rect.left && xPos <= rect.left + borderWidth && yPos <= rect.bottom && yPos >= rect.bottom - borderWidth && features.hasResize()) {
380  *result = HTBOTTOMLEFT;
381  } else if (xPos < rect.right && xPos >= rect.right - borderWidth && yPos <= rect.bottom && yPos >= rect.bottom - borderWidth && features.hasResize()) {
382  *result = HTBOTTOMRIGHT;
383  } else if (xPos >= rect.left && xPos <= rect.left + borderWidth && yPos >= rect.top && yPos <= rect.top + borderWidth && features.hasResize()) {
384  *result = HTTOPLEFT;
385  } else if (xPos <= rect.right && xPos >= rect.right - borderWidth && yPos >= rect.top && yPos < rect.top + borderWidth && features.hasResize()) {
386  *result = HTTOPRIGHT;
387  } else if (!hasFixedWidth && xPos >= rect.left && xPos <= rect.left + borderWidth && features.hasResize()) {
388  *result = HTLEFT;
389  } else if (!hasFixedHeight && yPos >= rect.top && yPos <= rect.top + borderWidth && features.hasResize()) {
390  *result = HTTOP;
391  } else if (!hasFixedHeight && yPos <= rect.bottom && yPos >= rect.bottom - borderWidth && features.hasResize()) {
392  *result = HTBOTTOM;
393  } else if (!hasFixedWidth && xPos <= rect.right && xPos >= rect.right - borderWidth && features.hasResize()) {
394  *result = HTRIGHT;
395  } else if (features.hasDrag()) {
396  const QPoint globalPosQt = QHighDpi::fromNativePixels(QPoint(xPos, yPos), w);
397  // htCaptionRect is the rect on which we allow for Windows to do a native drag
398  const QRect htCaptionRect = features.htCaptionRect;
399  if (globalPosQt.y() >= htCaptionRect.top() && globalPosQt.y() <= htCaptionRect.bottom() && globalPosQt.x() >= htCaptionRect.left() && globalPosQt.x() <= htCaptionRect.right()) {
400  if (!KDDockWidgets::inDisallowDragWidget(globalPosQt)) { // Just makes sure the mouse isn't over the close button, we don't allow drag in that case.
401  *result = HTCAPTION;
402  }
403  }
404  }
405 
406  return *result != 0;
407  } else if (msg->message == WM_NCLBUTTONDBLCLK && features.hasMaximize()) {
408  // By returning false we accept Windows native action, a maximize.
409  // We could also call titleBar->onDoubleClicked(); here which will maximize if Flag_DoubleClickMaximizes is set,
410  // but there's a bug in QWidget::showMaximized() on Windows when we're covering the native title bar, the window is maximized with an offset.
411  // So instead, use a native maximize which works well
412  return false;
413  } else if (msg->message == WM_GETMINMAXINFO) {
414  // Qt doesn't work well with windows that don't have title bar but have native frames.
415  // When maximized they go out of bounds and the title bar is clipped, so catch WM_GETMINMAXINFO
416  // and patch the size
417 
418  // According to microsoft docs it only works for the primary screen, but extrapolates for the others
420  if (!screen || w->screen() != screen) {
421  return false;
422  }
423 
424  DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
425 
426  const QRect availableGeometry = screen->availableGeometry();
427 
428  auto mmi = reinterpret_cast<MINMAXINFO *>(msg->lParam);
429  const qreal dpr = screen->devicePixelRatio();
430 
431  mmi->ptMaxSize.y = int(availableGeometry.height() * dpr);
432  mmi->ptMaxSize.x = int(availableGeometry.width() * dpr) - 1; // -1 otherwise it gets bogus size
433  mmi->ptMaxPosition.x = availableGeometry.x();
434  mmi->ptMaxPosition.y = availableGeometry.y();
435 
436  mmi->ptMinTrackSize.x = int(w->minimumWidth() * dpr);
437  mmi->ptMinTrackSize.y = int(w->minimumHeight() * dpr);
438 
439  *result = 0;
440  return true;
441  }
442 
443  return false;
444 }
445 
446 #endif
447 
448 void WidgetResizeHandler::setTarget(QWidgetOrQuick *w)
449 {
450  if (w) {
451  mTarget = w;
452  mTarget->setMouseTracking(true);
453  if (m_usesGlobalEventFilter) {
454  qApp->installEventFilter(this);
455  } else {
456  mTarget->installEventFilter(this);
457  }
458  } else {
459  qWarning() << "Target widget is null!";
460  }
461 }
462 
463 void WidgetResizeHandler::updateCursor(CursorPosition m)
464 {
465 #ifdef KDDOCKWIDGETS_QTWIDGETS
466  // Need for updating cursor when we change child widget
467  const QObjectList children = mTarget->children();
468  for (int i = 0, total = children.size(); i < total; ++i) {
469  if (auto child = qobject_cast<WidgetType *>(children.at(i))) {
470 
471  if (!child->testAttribute(Qt::WA_SetCursor)) {
472  child->setCursor(Qt::ArrowCursor);
473  }
474  }
475  }
476 #endif
477 
478  switch (m) {
481  setMouseCursor(Qt::SizeFDiagCursor);
482  break;
485  setMouseCursor(Qt::SizeBDiagCursor);
486  break;
487  case CursorPosition_Top:
489  setMouseCursor(Qt::SizeVerCursor);
490  break;
491  case CursorPosition_Left:
493  setMouseCursor(Qt::SizeHorCursor);
494  break;
496  restoreMouseCursor();
497  break;
498  case CursorPosition_All:
501  // Doesn't happen
502  break;
503  }
504 }
505 
506 void WidgetResizeHandler::setMouseCursor(Qt::CursorShape cursor)
507 {
508  if (m_usesGlobalEventFilter)
509  qApp->setOverrideCursor(cursor);
510  else
511  mTarget->setCursor(cursor);
512 }
513 
514 void WidgetResizeHandler::restoreMouseCursor()
515 {
516  if (m_usesGlobalEventFilter)
517  qApp->restoreOverrideCursor();
518  else
519  mTarget->setCursor(Qt::ArrowCursor);
520 }
521 
522 CursorPosition WidgetResizeHandler::cursorPosition(QPoint globalPos) const
523 {
524  if (!mTarget)
526 
527 #ifdef KDDOCKWIDGETS_QTQUICK
528  if (isMDI()) {
529  // Special case for QtQuick. The MouseAreas are driving it and know better what's the
530  // cursor position
531  return CursorPosition(mTarget->property("cursorPosition").toInt());
532  }
533 #endif
534 
535  QPoint pos = mTarget->mapFromGlobal(globalPos);
536 
537  const int x = pos.x();
538  const int y = pos.y();
539  const int margin = widgetResizeHandlerMargin();
540 
542 
543  if (y >= -margin && y <= mTarget->height() + margin) {
544  if (qAbs(x) <= margin)
545  result |= CursorPosition_Left;
546  else if (qAbs(x - (mTarget->width() - margin)) <= margin)
547  result |= CursorPosition_Right;
548  }
549 
550  if (x >= -margin && x <= mTarget->width() + margin) {
551  if (qAbs(y) <= margin)
552  result |= CursorPosition_Top;
553  else if (qAbs(y - (mTarget->height() - margin)) <= margin)
554  result |= CursorPosition_Bottom;
555  }
556 
557  // Filter out sides we don't allow
558  result = result & mAllowedResizeSides;
559 
560  return static_cast<CursorPosition>(result);
561 }
562 
564 void WidgetResizeHandler::setupWindow(QWindow *window)
565 {
566  // Does some minor setup on our QWindow.
567  // Like adding the drop shadow on Windows and two other workarounds.
568 
569 #if defined(Q_OS_WIN)
570  if (KDDockWidgets::usesAeroSnapWithCustomDecos()) {
571  const auto wid = HWND(window->winId());
572  connect(window, &QWindow::screenChanged, window, [wid] {
573  // Qt honors our frame hijacking usually... but when screen changes we must give it a
574  // nudge. Otherwise what Qt thinks is the client area is not what Windows knows it is.
575  // SetWindowPos() will trigger an NCCALCSIZE message, which Qt will intercept and take
576  // note of the margins we're using.
577  SetWindowPos(wid, 0, 0, 0, 0, 0,
578  SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
579  });
580 
581  const bool usesTransparentFloatingWindow =
582  Config::self().internalFlags() & Config::InternalFlag_UseTransparentFloatingWindow;
583  if (!usesTransparentFloatingWindow) {
584  // This enables the native drop shadow.
585  // Doesn't work well if the floating window has transparent round corners (shows weird white line).
586 
587  MARGINS margins = { 0, 0, 0, 1 }; // arbitrary, just needs to be > 0 it seems
588  DwmExtendFrameIntoClientArea(wid, &margins);
589  }
590  }
591 #else
592  Q_UNUSED(window);
593 #endif // Q_OS_WIN
594 }
595 
596 #ifdef Q_OS_WIN
597 bool WidgetResizeHandler::isInterestingNativeEvent(unsigned int nativeEvent)
598 {
599  switch (nativeEvent) {
600  case WM_NCHITTEST:
601  case WM_NCCALCSIZE:
602  case WM_NCLBUTTONDBLCLK:
603  case WM_GETMINMAXINFO:
604  return true;
605  default:
606  return false;
607  }
608 }
609 #endif
610 
611 #if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS)
612 bool NCHITTESTEventFilter::nativeEventFilter(const QByteArray &eventType, void *message,
613  Qt5Qt6Compat::qintptr *result)
614 
615 {
616  if (eventType != "windows_generic_MSG" || !m_floatingWindow)
617  return false;
618 
619  auto msg = static_cast<MSG *>(message);
620  if (msg->message != WM_NCHITTEST)
621  return false;
622  const WId wid = WId(msg->hwnd);
623 
624  QWidget *child = QWidget::find(wid);
625  if (!child || child->window() != m_floatingWindow)
626  return false;
627  const bool isThisWindow = child == m_floatingWindow;
628 
629  if (!isThisWindow) {
630  *result = HTTRANSPARENT;
631  return true;
632  }
633 
634  return false;
635 }
636 #endif
637 
638 
639 CustomFrameHelper::CustomFrameHelper(ShouldUseCustomFrame func, QObject *parent)
640  : QObject(parent)
642  , m_shouldUseCustomFrameFunc(func)
643 {
644 #ifdef Q_OS_WIN
645  qApp->installNativeEventFilter(this);
646 #endif
647 }
648 
649 CustomFrameHelper::~CustomFrameHelper()
650 {
651  m_inDtor = true;
652 }
653 
654 void CustomFrameHelper::applyCustomFrame(QWindow *window)
655 {
656 #ifdef Q_OS_WIN
657  WidgetResizeHandler::setupWindow(window);
658 #else
659  Q_UNUSED(window);
660  qWarning() << Q_FUNC_INFO << "Not implemented on this platform";
661 #endif
662 }
663 
664 bool CustomFrameHelper::nativeEventFilter(const QByteArray &eventType, void *message,
665  Qt5Qt6Compat::qintptr *result)
666 {
667  if (m_shouldUseCustomFrameFunc == nullptr || m_recursionGuard)
668  return false;
669 
670  QScopedValueRollback<bool> guard(m_recursionGuard, true);
671 
672 #ifdef Q_OS_WIN
673  if (m_inDtor || !KDDockWidgets::usesAeroSnapWithCustomDecos())
674  return false;
675 
676  if (eventType != "windows_generic_MSG")
677  return false;
678 
679  auto msg = static_cast<MSG *>(message);
680  if (!WidgetResizeHandler::isInterestingNativeEvent(msg->message)) {
681  // Save some CPU cycles
682  return false;
683  }
684 
685  QWindow *window = DockRegistry::self()->windowForHandle(WId(msg->hwnd));
686  if (!window)
687  return false;
688 
689  const WidgetResizeHandler::NativeFeatures features = m_shouldUseCustomFrameFunc(window);
690  if (!features.hasFeatures()) {
691  // No native support for is desired for this window
692  return false;
693  }
694 
695  const char *propertyName = "kddw_customframe_setup_ran";
696  const bool setupRan = window->property(propertyName).toBool();
697  if (!setupRan) {
698  // Add drop shadow
699  WidgetResizeHandler::setupWindow(window);
700  window->setProperty(propertyName, true);
701  }
702 
703  return WidgetResizeHandler::handleWindowsNativeEvent(window, msg, result, features);
704 #else
705  Q_UNUSED(eventType);
706  Q_UNUSED(message);
707  Q_UNUSED(result);
708  return false;
709 #endif
710 }
Layouting::Widget::widgetMaxSize
static QSize widgetMaxSize(const T *w)
Definition: Widget.h:164
QRect::moveTopLeft
void moveTopLeft(const QPoint &position)
QWidget::window
QWidget * window() const const
Layouting::Widget::widgetMinSize
static QSize widgetMinSize(const T *w)
Definition: Widget.h:152
QEvent::MouseButtonPress
MouseButtonPress
KDDockWidgets::CursorPosition_All
@ CursorPosition_All
Definition: KDDockWidgets.h:266
QRect::topLeft
QPoint topLeft() const const
QScreen::availableGeometry
availableGeometry
QRect
QRect::right
int right() const const
QGuiApplication::primaryScreen
primaryScreen
KDDockWidgets::CursorPosition_TopRight
@ CursorPosition_TopRight
Definition: KDDockWidgets.h:261
Layouting::Config::self
static Config & self()
returns the singleton Config instance
Definition: MultiSplitterConfig.cpp:44
QWindow
QWidget
KDDockWidgets::CursorPosition
CursorPosition
Definition: KDDockWidgets.h:254
QRect::width
int width() const const
QRect::x
int x() const const
QRect::y
int y() const const
QWindow::maximumWidth
maximumWidth
QPoint::x
int x() const const
QPoint::y
int y() const const
QSize::width
int width() const const
QRect::intersected
QRect intersected(const QRect &rectangle) const const
KDDockWidgets::CursorPosition_Left
@ CursorPosition_Left
Definition: KDDockWidgets.h:256
QRect::contains
bool contains(const QRect &rectangle, bool proper) const const
KDDockWidgets::CursorPosition_Bottom
@ CursorPosition_Bottom
Definition: KDDockWidgets.h:259
Qt::LeftButton
LeftButton
KDDockWidgets::CursorPosition_Undefined
@ CursorPosition_Undefined
Definition: KDDockWidgets.h:255
QMouseEvent
QRect::left
int left() const const
QFlags
QScreen
KDDockWidgets::CursorPosition_Vertical
@ CursorPosition_Vertical
Definition: KDDockWidgets.h:265
QRect::setRight
void setRight(int x)
KDDockWidgets::CursorPosition_TopLeft
@ CursorPosition_TopLeft
Definition: KDDockWidgets.h:260
QRect::bottom
int bottom() const const
QRect::top
int top() const const
QWindow::minimumHeight
minimumHeight
QObject
QSize::height
int height() const const
QRect::setBottom
void setBottom(int y)
KDDockWidgets::CursorPosition_Horizontal
@ CursorPosition_Horizontal
Definition: KDDockWidgets.h:264
Qt::ArrowCursor
ArrowCursor
QWindow::winId
WId winId() const const
QWidget::find
QWidget * find(WId id)
QMargins
QVariant::toBool
bool toBool() const const
QWindow::screen
QScreen * screen() const const
QWidget::setMouseTracking
void setMouseTracking(bool enable)
QScreen::devicePixelRatio
devicePixelRatio
Config.h
Application-wide config to tune certain behaviours of the framework.
QObject::setProperty
bool setProperty(const char *name, const QVariant &value)
QWindow::screenChanged
void screenChanged(QScreen *screen)
QRect::setTop
void setTop(int y)
QRect::height
int height() const const
QEvent::type
QEvent::Type type() const const
QEvent
KDDockWidgets::CursorPosition_Right
@ CursorPosition_Right
Definition: KDDockWidgets.h:257
QRect::adjusted
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const const
KDDockWidgets
Definition: Config.cpp:37
QScopedValueRollback
QWindow::maximumHeight
maximumHeight
KDDockWidgets::CursorPosition_BottomRight
@ CursorPosition_BottomRight
Definition: KDDockWidgets.h:262
QAbstractNativeEventFilter
QRect::marginsAdded
QRect marginsAdded(const QMargins &margins) const const
QRect::setLeft
void setLeft(int x)
QWindow::minimumWidth
minimumWidth
Qt::WA_SetCursor
WA_SetCursor
KDDockWidgets::CursorPosition_BottomLeft
@ CursorPosition_BottomLeft
Definition: KDDockWidgets.h:263
QPoint
QByteArray
KDDockWidgets::CursorPosition_Top
@ CursorPosition_Top
Definition: KDDockWidgets.h:258
QObject::property
QVariant property(const char *name) const const

© 2019-2022 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDDockWidgets
Advanced Dock Widget Framework for Qt
https://www.kdab.com/development-resources/qt-tools/kddockwidgets/
Generated on Thu Sep 15 2022 00:16:29 for KDDockWidgets API Documentation by doxygen 1.8.20