KDDockWidgets API Documentation 2.0
Loading...
Searching...
No Matches
WidgetResizeHandler.cpp
Go to the documentation of this file.
1/*
2 This file is part of KDDockWidgets.
3
4 SPDX-FileCopyrightText: 2019 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 "DragController_p.h"
14#include "Config.h"
15#include "Utils_p.h"
16#include "View_p.h"
17#include "Logging_p.h"
18#include "DockRegistry_p.h"
19
20#include "kddockwidgets/core/DockRegistry.h"
21#include "kddockwidgets/core/MDILayout.h"
22#include "kddockwidgets/core/TitleBar.h"
23#include "kddockwidgets/core/FloatingWindow.h"
24#include "kddockwidgets/core/Platform.h"
25#include "core/ScopedValueRollback_p.h"
26
27#include <cstdlib>
28
29#if defined(Q_OS_WIN)
30#if defined(KDDW_FRONTEND_QTWIDGETS)
31#include "../qtcommon/Platform.h"
32#include <QWidget>
33#endif
34
35#if defined(KDDW_FRONTEND_QT)
36#include "../qtcommon/Window_p.h"
37#include <QGuiApplication>
38#include <QtGui/private/qhighdpiscaling_p.h>
39#endif
40
41#endif
42
43#if defined(Q_OS_WIN)
44
45#include <windowsx.h>
46#include <dwmapi.h>
47#if defined(Q_CC_MSVC)
48#pragma comment(lib, "Dwmapi.lib")
49#pragma comment(lib, "User32.lib")
50#endif
51#endif
52
53using namespace KDDockWidgets;
54using namespace KDDockWidgets::Core;
55
56#if defined(KDDW_FRONTEND_QTQUICK)
57#include "qtcommon/View.h"
58#endif
59
60bool WidgetResizeHandler::s_disableAllHandlers = false;
61WidgetResizeHandler::WidgetResizeHandler(EventFilterMode filterMode, WindowMode windowMode,
62 View *target)
63 : m_usesGlobalEventFilter(filterMode == EventFilterMode::Global)
64 , m_isTopLevelWindowResizer(windowMode == WindowMode::TopLevel)
65{
66 setTarget(target);
67}
68
69WidgetResizeHandler::~WidgetResizeHandler()
70{
71 if (m_usesGlobalEventFilter) {
73 } else if (mTargetGuard) {
74 mTarget->removeViewEventFilter(this);
75 }
76
77 restoreMouseCursor();
78}
79
80void WidgetResizeHandler::setAllowedResizeSides(CursorPositions sides)
81{
82 mAllowedResizeSides = sides;
83}
84
85void WidgetResizeHandler::setResizeGap(int gap)
86{
87 m_resizeGap = gap;
88}
89
90bool WidgetResizeHandler::isMDI() const
91{
92 Core::Group *group = mTarget->asGroupController();
93 return group && group->isMDI();
94}
95
96bool WidgetResizeHandler::isResizing() const
97{
98 return m_resizingInProgress;
99}
100
101int WidgetResizeHandler::widgetResizeHandlerMargin()
102{
103 return 4; // pixels
104}
105
106bool WidgetResizeHandler::onMouseEvent(View *widget, MouseEvent *e)
107{
108 if (s_disableAllHandlers || !widget || !mTargetGuard)
109 return false;
110
111 if (e->type() != Event::MouseButtonPress && e->type() != Event::MouseButtonRelease
112 && e->type() != Event::MouseMove)
113 return false;
114
115 auto me = mouseEvent(e);
116 if (!me)
117 return false;
118
119 if (m_isTopLevelWindowResizer) {
120 // Case #1.0: Resizing FloatingWindow
121
122 if (!widget->isRootView() || !widget->equals(mTarget)) {
123 if (m_usesGlobalEventFilter) {
124 // Case #1.1: FloatingWindows on EGLFS
125 // EGLFS doesn't support storing mouse cursor shape per window, so we need to use
126 // global filter do detect mouse leaving the window
127 if (!m_resizingInProgress) {
128 const Point globalPos = Qt5Qt6Compat::eventGlobalPos(me);
129 updateCursor(cursorPosition(globalPos));
130 }
131 }
132
133 // Case #1.2: FloatingWindows on all other platforms
134 // Not needed to mess with the cursor, it gets set when moving over another window.
135 return false;
136 }
137 } else if (isMDI()) {
138 // Case #2: Resizing an embedded MDI "Window"
139
140 // Each Frame has a WidgetResizeHandler instance.
141 // mTarget is the Frame we want to resize.
142 // but 'o' might not be mTarget, because we're using a global event filter.
143 // The global event filter is required because we allow the cursor to be outside the group,
144 // a few pixels so we have a nice resize margin. Here we deal with the case where our
145 // mTarget, let's say "Frame 1" is on top of "Frame 2" but cursor is near "Frame 2"'s
146 // margins, and would show resize cursor. We only want to continue if the cursor is near the
147 // margins of our own group (mTarget)
148
149 auto f = widget->d->firstParentOfType(ViewType::Frame);
150 auto group = f ? f->view()->asGroupController() : nullptr;
151 if (group && group->isMDIWrapper()) {
152 // We don't care about the inner Option_MDINestable helper group
153 group = group->mdiFrame();
154 }
155
156 if (group && !group->view()->equals(mTarget)) {
157 auto groupParent =
158 group->view()->d->aboutToBeDestroyed() ? nullptr : group->view()->parentView();
159 auto targetParent = mTarget->d->aboutToBeDestroyed() ? nullptr : mTarget->parentView();
160 const bool areSiblings = groupParent && groupParent->equals(targetParent);
161 if (areSiblings)
162 return false;
163 }
164 }
165
166 switch (e->type()) {
167 case Event::MouseButtonPress: {
168 if (mTarget->isMaximized())
169 break;
170
171 auto cursorPos = cursorPosition(Qt5Qt6Compat::eventGlobalPos(e));
172 updateCursor(cursorPos);
173 if (cursorPos == CursorPosition_Undefined)
174 return false;
175
176 const int m = widgetResizeHandlerMargin();
177 const Rect widgetRect = mTarget->rect().marginsAdded(Margins(m, m, m, m));
178 const Point cursorPoint = mTarget->mapFromGlobal(Qt5Qt6Compat::eventGlobalPos(e));
179 if (!widgetRect.contains(cursorPoint) || e->button() != Qt::LeftButton)
180 return false;
181
182 m_resizingInProgress = true;
183 if (isMDI())
184 DockRegistry::self()->dptr()->groupInMDIResizeChanged.emit();
185 mNewPosition = Qt5Qt6Compat::eventGlobalPos(e);
186 mCursorPos = cursorPos;
187
188 return true;
189 }
190 case Event::MouseButtonRelease: {
191 m_resizingInProgress = false;
192 if (isMDI()) {
193 DockRegistry::self()->dptr()->groupInMDIResizeChanged.emit();
194 // Usually in KDDW all geometry changes are done in the layout items, which propagate to
195 // the widgets When resizing a MDI however, we're resizing the widget directly. So
196 // update the corresponding layout item when we're finished.
197 auto group = mTarget->asGroupController();
198 group->mdiLayout()->setDockWidgetGeometry(group, group->geometry());
199 }
200 updateCursor(CursorPosition_Undefined);
201 auto cursorPos = cursorPosition(Qt5Qt6Compat::eventGlobalPos(e));
202 updateCursor(cursorPos);
203 if (mTarget->isMaximized() || !m_resizingInProgress || e->button() != Qt::LeftButton)
204 break;
205
206 mTarget->releaseMouse();
207 mTarget->releaseKeyboard();
208 return true;
209
210 break;
211 }
212 case Event::MouseMove: {
213 if (mTarget->isMaximized())
214 break;
215
216 if (isMDI()) {
217 const Core::Group *groupBeingResized = DockRegistry::self()->groupInMDIResize();
218 const bool otherGroupBeingResized =
219 groupBeingResized && groupBeingResized->view() != mTarget;
220 if (otherGroupBeingResized) {
221 // only one at a time!
222 return false;
223 }
224 }
225
226 m_resizingInProgress = m_resizingInProgress && (e->buttons() & Qt::LeftButton);
227 const bool consumed = mouseMoveEvent(e);
228 return consumed;
229 }
230 default:
231 break;
232 }
233 return false;
234}
235
236bool WidgetResizeHandler::mouseMoveEvent(MouseEvent *e)
237{
238 const Point globalPos = Qt5Qt6Compat::eventGlobalPos(e);
239 if (!m_resizingInProgress) {
240 const CursorPosition pos = cursorPosition(globalPos);
241 updateCursor(pos);
242 return pos != CursorPosition_Undefined;
243 }
244
245 const Rect oldGeometry = mTarget->d->globalGeometry();
246 Rect newGeometry = oldGeometry;
247
248 Rect parentGeometry;
249 if (!mTarget->isRootView()) {
250 auto parent = mTarget->parentView();
251 parentGeometry = parent->d->globalGeometry();
252 }
253
254 {
255 int deltaWidth = 0;
256 int newWidth = 0;
257 const int maxWidth = mTarget->maxSizeHint().width();
258 const int minWidth = mTarget->minSize().width();
259
260 switch (mCursorPos) {
264 parentGeometry = parentGeometry.adjusted(m_resizeGap, 0, 0, 0);
265 deltaWidth = oldGeometry.left() - globalPos.x();
266 newWidth = bound(minWidth, mTarget->width() + deltaWidth, maxWidth);
267 deltaWidth = newWidth - mTarget->width();
268 if (deltaWidth != 0) {
269 newGeometry.setLeft(newGeometry.left() - deltaWidth);
270 }
271
272 break;
273 }
274
278 parentGeometry = parentGeometry.adjusted(0, 0, -m_resizeGap, 0);
279 deltaWidth = globalPos.x() - newGeometry.right();
280 newWidth = bound(minWidth, mTarget->width() + deltaWidth, maxWidth);
281 deltaWidth = newWidth - mTarget->width();
282 if (deltaWidth != 0) {
283 newGeometry.setRight(oldGeometry.right() + deltaWidth);
284 }
285 break;
286 }
287 default:
288 break;
289 }
290 }
291
292 {
293 const int maxHeight = mTarget->maxSizeHint().height();
294 const int minHeight = mTarget->minSize().height();
295 int deltaHeight = 0;
296 int newHeight = 0;
297 switch (mCursorPos) {
301 parentGeometry = parentGeometry.adjusted(0, m_resizeGap, 0, 0);
302 deltaHeight = oldGeometry.top() - globalPos.y();
303 newHeight = bound(minHeight, mTarget->height() + deltaHeight, maxHeight);
304 deltaHeight = newHeight - mTarget->height();
305 if (deltaHeight != 0) {
306 newGeometry.setTop(newGeometry.top() - deltaHeight);
307 }
308
309 break;
310 }
311
315 parentGeometry = parentGeometry.adjusted(0, 0, 0, -m_resizeGap);
316 deltaHeight = globalPos.y() - newGeometry.bottom();
317 newHeight = bound(minHeight, mTarget->height() + deltaHeight, maxHeight);
318 deltaHeight = newHeight - mTarget->height();
319 if (deltaHeight != 0) {
320 newGeometry.setBottom(oldGeometry.bottom() + deltaHeight);
321 }
322 break;
323 }
324 default:
325 break;
326 }
327 }
328
329 if (newGeometry == mTarget->geometry()) {
330 // Nothing to do.
331 return true;
332 }
333
334 if (!mTarget->isRootView()) {
335
336 // Clip to parent's geometry.
337 newGeometry = newGeometry.intersected(parentGeometry);
338
339 // Back to local.
340 newGeometry.moveTopLeft(mTarget->mapFromGlobal(newGeometry.topLeft()) + mTarget->pos());
341 }
342
343 mTarget->setGeometry(newGeometry);
344 return true;
345}
346
347#ifdef KDDW_FRONTEND_QT_WINDOWS
348
350bool WidgetResizeHandler::handleWindowsNativeEvent(Core::FloatingWindow *fw,
351 const QByteArray &eventType, void *message,
352 Qt5Qt6Compat::qintptr *result)
353{
354 if (eventType != "windows_generic_MSG")
355 return false;
356
357 auto msg = static_cast<MSG *>(message);
358 if (msg->message == WM_NCHITTEST) {
359 if (DragController::instance()->isInClientDrag()) {
360 // There's a non-native drag going on.
361 *result = 0;
362 return false;
363 }
364
365 const Rect htCaptionRect = fw->dragRect();
366 const bool ret = handleWindowsNativeEvent(fw->view()->window(), msg, result, htCaptionRect);
367
368 fw->setLastHitTest(*result);
369 return ret;
370 } else if (msg->message == WM_NCLBUTTONDBLCLK) {
372 return handleWindowsNativeEvent(fw->view()->window(), msg, result, {});
373 } else {
374 // Let the title bar handle it. It will re-dock the window.
375 if (Core::TitleBar *titleBar = fw->titleBar()) {
376 if (titleBar->isVisible()) { // can't be invisible afaik
377 titleBar->onDoubleClicked();
378 }
379 }
380
381 return true;
382 }
383 }
384
385 return handleWindowsNativeEvent(fw->view()->window(), msg, result, {});
386}
387
388bool WidgetResizeHandler::handleWindowsNativeEvent(Core::Window::Ptr w, MSG *msg,
389 Qt5Qt6Compat::qintptr *result,
390 const NativeFeatures &features)
391{
392 if (msg->message == WM_NCCALCSIZE && features.hasShadow()) {
393 *result = 0;
394 return true;
395 } else if (msg->message == WM_NCHITTEST && (features.hasResize() || features.hasDrag())) {
396 const int borderWidth = 8;
397 const bool hasFixedWidth = w->minWidth() == w->maxWidth();
398 const bool hasFixedHeight = w->minHeight() == w->maxHeight();
399 const bool hasFixedWidthOrHeight = hasFixedWidth || hasFixedHeight;
400
401 *result = 0;
402 const int xPos = GET_X_LPARAM(msg->lParam);
403 const int yPos = GET_Y_LPARAM(msg->lParam);
404 RECT rect;
405 GetWindowRect(reinterpret_cast<HWND>(w->handle()), &rect);
406
407 if (!hasFixedWidthOrHeight && xPos >= rect.left && xPos <= rect.left + borderWidth && yPos <= rect.bottom
408 && yPos >= rect.bottom - borderWidth && features.hasResize()) {
409 *result = HTBOTTOMLEFT;
410 } else if (!hasFixedWidthOrHeight && xPos < rect.right && xPos >= rect.right - borderWidth && yPos <= rect.bottom
411 && yPos >= rect.bottom - borderWidth && features.hasResize()) {
412 *result = HTBOTTOMRIGHT;
413 } else if (!hasFixedWidthOrHeight && xPos >= rect.left && xPos <= rect.left + borderWidth && yPos >= rect.top
414 && yPos <= rect.top + borderWidth && features.hasResize()) {
415 *result = HTTOPLEFT;
416 } else if (!hasFixedWidthOrHeight && xPos <= rect.right && xPos >= rect.right - borderWidth && yPos >= rect.top
417 && yPos < rect.top + borderWidth && features.hasResize()) {
418 *result = HTTOPRIGHT;
419 } else if (!hasFixedWidth && xPos >= rect.left && xPos <= rect.left + borderWidth
420 && features.hasResize()) {
421 *result = HTLEFT;
422 } else if (!hasFixedHeight && yPos >= rect.top && yPos <= rect.top + borderWidth
423 && features.hasResize()) {
424 *result = HTTOP;
425 } else if (!hasFixedHeight && yPos <= rect.bottom && yPos >= rect.bottom - borderWidth
426 && features.hasResize()) {
427 *result = HTBOTTOM;
428 } else if (!hasFixedWidth && xPos <= rect.right && xPos >= rect.right - borderWidth
429 && features.hasResize()) {
430 *result = HTRIGHT;
431 } else if (features.hasDrag()) {
432 const Point globalPosQt = w->fromNativePixels(Point(xPos, yPos));
433 // htCaptionRect is the rect on which we allow for Windows to do a native drag
434 const Rect htCaptionRect = features.htCaptionRect;
435 if (globalPosQt.y() >= htCaptionRect.top() && globalPosQt.y() <= htCaptionRect.bottom()
436 && globalPosQt.x() >= htCaptionRect.left()
437 && globalPosQt.x() <= htCaptionRect.right()) {
438 if (!Platform::instance()->inDisallowedDragView(
439 globalPosQt)) { // Just makes sure the mouse isn't over the close button, we
440 // don't allow drag in that case.
441 *result = HTCAPTION;
442 }
443 }
444 }
445
446 return *result != 0;
447 } else if (msg->message == WM_NCLBUTTONDBLCLK && features.hasMaximize()) {
448 // By returning false we accept Windows native action, a maximize.
449 // We could also call titleBar->onDoubleClicked(); here which will maximize if
450 // Flag_DoubleClickMaximizes is set, but there's a bug in QWidget::showMaximized() on
451 // Windows when we're covering the native title bar, the window is maximized with an offset.
452 // So instead, use a native maximize which works well
453 return false;
454 } else if (msg->message == WM_GETMINMAXINFO) {
455 // Qt doesn't work well with windows that don't have title bar but have native frames.
456 // When maximized they go out of bounds and the title bar is clipped, so catch
457 // WM_GETMINMAXINFO and patch the size
458
459 // According to microsoft docs it only works for the primary screen, but extrapolates for
460 // the others
461 auto screen = Platform::instance()->primaryScreen();
462 if (!screen || w->screen() != screen) {
463 return false;
464 }
465
466 DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
467
468 const Rect availableGeometry = screen->availableGeometry();
469
470 auto mmi = reinterpret_cast<MINMAXINFO *>(msg->lParam);
471 const double dpr = screen->devicePixelRatio();
472
473 mmi->ptMaxSize.y = int(availableGeometry.height() * dpr);
474 mmi->ptMaxSize.x =
475 int(availableGeometry.width() * dpr) - 1; // -1 otherwise it gets bogus size
476 mmi->ptMaxPosition.x = availableGeometry.x();
477 mmi->ptMaxPosition.y = availableGeometry.y();
478
479 mmi->ptMinTrackSize.x = int(w->minWidth() * dpr);
480 mmi->ptMinTrackSize.y = int(w->minHeight() * dpr);
481
482 *result = 0;
483 return true;
484 }
485
486 return false;
487}
488
489#endif
490
491void WidgetResizeHandler::setTarget(View *w)
492{
493 if (w) {
494 mTarget = w;
495 mTargetGuard = w;
496 mTarget->setMouseTracking(true);
497 if (m_usesGlobalEventFilter) {
499 } else {
500 mTarget->installViewEventFilter(this);
501 }
502 } else {
503 KDDW_ERROR("Target widget is null!");
504 }
505}
506
507void WidgetResizeHandler::updateCursor(CursorPosition m)
508{
509 if (!mTargetGuard) {
510 // Our target was destroyed while we're processing mouse events, it's fine.
511 restoreMouseCursor();
512 return;
513 }
514
515 if (Platform::instance()->isQtWidgets()) {
516 // Need for updating cursor when we change child widget
517 const auto childViews = mTarget->childViews();
518 for (const auto &child : childViews) {
519 if (!child->hasAttribute(Qt::WA_SetCursor)) {
520 child->setCursor(Qt::ArrowCursor);
521 }
522 }
523 }
524 switch (m) {
527 setMouseCursor(Qt::SizeFDiagCursor);
528 break;
531 setMouseCursor(Qt::SizeBDiagCursor);
532 break;
535 setMouseCursor(Qt::SizeVerCursor);
536 break;
539 setMouseCursor(Qt::SizeHorCursor);
540 break;
542 restoreMouseCursor();
543 break;
547 // Doesn't happen
548 break;
549 }
550}
551
552void WidgetResizeHandler::setMouseCursor(Qt::CursorShape cursor)
553{
554 if (m_usesGlobalEventFilter) {
555 Platform::instance()->setMouseCursor(cursor, /*discardLast=*/m_overrideCursorSet);
556 m_overrideCursorSet = true;
557 } else if (mTargetGuard) {
558 mTarget->setCursor(cursor);
559 }
560}
561
562void WidgetResizeHandler::restoreMouseCursor()
563{
564 if (m_usesGlobalEventFilter) {
565 if (m_overrideCursorSet) {
567 m_overrideCursorSet = false;
568 }
569 } else if (mTargetGuard) {
570 mTarget->setCursor(Qt::ArrowCursor);
571 }
572}
573
574CursorPosition WidgetResizeHandler::cursorPosition(Point globalPos) const
575{
576 if (!mTargetGuard)
578
579#ifdef KDDW_FRONTEND_QTQUICK
580 if (Platform::instance()->isQtQuick() && isMDI()) {
581 // Special case for QtQuick. The MouseAreas are driving it and know better what's the
582 // cursor position
583 auto qtview = static_cast<KDDockWidgets::QtCommon::View_qt *>(mTarget);
584 const QVariant v = qtview->viewProperty("cursorPosition");
585 if (v.isValid())
586 return CursorPosition(v.toInt());
587 }
588#endif
589
590 Point pos = mTarget->mapFromGlobal(globalPos);
591
592 const int x = pos.x();
593 const int y = pos.y();
594 const int margin = widgetResizeHandlerMargin();
595
597 if (y >= -margin && y <= mTarget->height() + margin) {
598 if (std::abs(x) <= margin)
599 result |= CursorPosition_Left;
600 else if (std::abs(x - (mTarget->width() - margin)) <= margin)
601 result |= CursorPosition_Right;
602 }
603
604 if (x >= -margin && x <= mTarget->width() + margin) {
605 if (std::abs(y) <= margin)
606 result |= CursorPosition_Top;
607 else if (std::abs(y - (mTarget->height() - margin)) <= margin)
608 result |= CursorPosition_Bottom;
609 }
610
611 // Filter out sides we don't allow
612 result = result & mAllowedResizeSides;
613
614 return static_cast<CursorPosition>(result);
615}
616
618void WidgetResizeHandler::setupWindow(Core::Window::Ptr window)
619{
620 // Does some minor setup on our QWindow.
621 // Like adding the drop shadow on Windows and two other workarounds.
622
623#ifdef KDDW_FRONTEND_QT_WINDOWS
624 if (KDDockWidgets::usesAeroSnapWithCustomDecos()) {
625 const auto wid = HWND(window->handle());
626 window->onScreenChanged(nullptr, [](QObject *, Window::Ptr win) {
627 // Qt honors our frame hijacking usually... but when screen changes we must give it a
628 // nudge. Otherwise what Qt thinks is the client area is not what Windows knows it is.
629 // SetWindowPos() will trigger an NCCALCSIZE message, which Qt will intercept and take
630 // note of the margins we're using.
631 const auto winId = HWND(win->handle());
632 SetWindowPos(winId, 0, 0, 0, 0, 0,
633 SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
634 });
635
636 const bool usesTransparentFloatingWindow =
638 if (!usesTransparentFloatingWindow) {
639 // This enables the native drop shadow.
640 // Doesn't work well if the floating window has transparent round corners (shows weird
641 // white line).
642
643 MARGINS margins = { 0, 0, 0, 1 }; // arbitrary, just needs to be > 0 it seems
644 DwmExtendFrameIntoClientArea(wid, &margins);
645 }
646 }
647#else
648 KDDW_UNUSED(window);
649#endif // Q_OS_WIN
650}
651
652#ifdef KDDW_FRONTEND_QT_WINDOWS
653bool WidgetResizeHandler::isInterestingNativeEvent(unsigned int nativeEvent)
654{
655 switch (nativeEvent) {
656 case WM_NCHITTEST:
657 case WM_NCCALCSIZE:
658 case WM_NCLBUTTONDBLCLK:
659 case WM_GETMINMAXINFO:
660 return true;
661 default:
662 return false;
663 }
664}
665#endif
666
667#if defined(Q_OS_WIN) && defined(KDDW_FRONTEND_QTWIDGETS)
668bool NCHITTESTEventFilter::nativeEventFilter(const QByteArray &eventType, void *message,
669 Qt5Qt6Compat::qintptr *result)
670
671{
672 if (eventType != "windows_generic_MSG" || !m_guard)
673 return false;
674
675 auto msg = static_cast<MSG *>(message);
676 if (msg->message != WM_NCHITTEST)
677 return false;
678 const WId wid = WId(msg->hwnd);
679
681
682 if (!child || !m_floatingWindow->equals(child->rootView()))
683 return false;
684 const bool isThisWindow = m_floatingWindow->equals(child);
685
686 if (!isThisWindow) {
687 *result = HTTRANSPARENT;
688 return true;
689 }
690
691 return false;
692}
693#endif
Application-wide config to tune certain behaviours of the framework.
#define KDDW_UNUSED(name)
InternalFlags internalFlags() const
Definition Config.cpp:270
@ InternalFlag_UseTransparentFloatingWindow
Definition Config.h:164
static Config & self()
returns the singleton Config instance
Definition Config.cpp:87
View * view() const
Returns the view associated with this controller, if any.
Core::TitleBar * titleBar() const
Returns the title bar.
bool isMDI() const
Returns whether this group is in a MDI layout Usually no, unless you're using an MDI main window.
bool isMDIWrapper() const
Returns whether this group was created automatically just for the purpose of supporting DockWidget::O...
Group * mdiFrame() const
If this group is an MDI wrapper, returns the MDI group. That is the group you actually drag inside th...
MDILayout * mdiLayout() const
Returns the MDI layout. Or nullptr if this group isn't in a MDI layout.
void setDockWidgetGeometry(Core::Group *group, Rect)
sets the size and position of the dock widget group
virtual void setMouseCursor(Qt::CursorShape, bool discardLast=false)=0
Sets the mouse cursor to the specified shape, this has an application-wide effect Call restoreMouseCu...
virtual void restoreMouseCursor()=0
Undoes the call to setMouseCursor()
virtual std::shared_ptr< Screen > primaryScreen() const =0
static Platform * instance()
Returns the platform singleton.
void removeGlobalEventFilter(EventFilterInterface *)
Removes a global event filter.
void installGlobalEventFilter(EventFilterInterface *)
Installs a global event filter Events will be forwarded to the specified EventFilterInterface.
bool equals(const View *other) const
Returns whether this view represents the same GUI element as the other.
virtual void setMouseTracking(bool)=0
virtual bool isRootView() const =0
virtual std::shared_ptr< View > parentView() const =0
Returns the gui element's parent. Like QWidget::parentWidget()
Core::Group * asGroupController() const
virtual std::shared_ptr< Core::Window > window() const =0
Returns the window this view is inside For the Qt frontend, this wraps a QWindow. Like QWidget::windo...
Core::Group * groupInMDIResize() const
Returns the Group which is being resized in a MDI layout. nullptr if none.
static DockRegistry * self()
virtual std::shared_ptr< Core::View > qobjectAsView(QObject *) const =0
Returns the specified QObject casted to View Nullptr if it's not a view.
Class to abstract QAction, so code still works with QtQuick and Flutter.
T bound(T minVal, T value, T maxVal)
ArrowCursor
LeftButton
WA_SetCursor
bool isValid() const const
int toInt(bool *ok) const const
QWidget * find(WId id)

© 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 by doxygen 1.9.8