12#include "WidgetResizeHandler_p.h" 
   13#include "FloatingWindow_p.h" 
   14#include "TitleBar_p.h" 
   15#include "DragController_p.h" 
   17#include "Qt5Qt6Compat_p.h" 
   19#include "DockRegistry_p.h" 
   20#include "MDILayoutWidget_p.h" 
   25#include <QGuiApplication> 
   28#include <QScopedValueRollback> 
   31#include <QtGui/private/qhighdpiscaling_p.h> 
   36#pragma comment(lib, "Dwmapi.lib") 
   37#pragma comment(lib, "User32.lib") 
   43bool WidgetResizeHandler::s_disableAllHandlers = 
false;
 
   44WidgetResizeHandler::WidgetResizeHandler(EventFilterMode filterMode, WindowMode windowMode, 
QWidgetOrQuick *target)
 
   46    , m_usesGlobalEventFilter(filterMode == EventFilterMode::Global)
 
   47    , m_isTopLevelWindowResizer(windowMode == WindowMode::TopLevel)
 
   52WidgetResizeHandler::~WidgetResizeHandler()
 
   57void WidgetResizeHandler::setAllowedResizeSides(CursorPositions sides)
 
   59    mAllowedResizeSides = sides;
 
   62void WidgetResizeHandler::setResizeGap(
int gap)
 
   67bool WidgetResizeHandler::isMDI()
 const 
   69    auto frame = qobject_cast<Frame *>(mTarget);
 
   70    return frame && frame->isMDI();
 
   73bool WidgetResizeHandler::isResizing()
 const 
   75    return m_resizingInProgress;
 
   78int WidgetResizeHandler::widgetResizeHandlerMargin()
 
   85    if (s_disableAllHandlers)
 
   88    auto widget = qobject_cast<QWidgetOrQuick *>(o);
 
   92    auto me = mouseEvent(e);
 
   96    if (m_isTopLevelWindowResizer) {
 
   99        if (!widget->isTopLevel() || o != mTarget) {
 
  100            if (m_usesGlobalEventFilter) {
 
  104                if (!m_resizingInProgress) {
 
  105                    const QPoint globalPos = Qt5Qt6Compat::eventGlobalPos(me);
 
  106                    updateCursor(cursorPosition(globalPos));
 
  114    } 
else if (isMDI()) {
 
  126        auto frame = firstParentOfType<Frame>(widget);
 
  127        if (frame && frame->isMDIWrapper()) {
 
  129            frame = frame->mdiFrame();
 
  132        if (frame && frame != mTarget) {
 
  133            const bool areSiblings = frame->QWidgetAdapter::parentWidget() == mTarget->parentWidget();
 
  141        if (mTarget->isMaximized())
 
  145        auto cursorPos = cursorPosition(Qt5Qt6Compat::eventGlobalPos(mouseEvent));
 
  146        updateCursor(cursorPos);
 
  150        const int m = widgetResizeHandlerMargin();
 
  152        const QPoint cursorPoint = mTarget->mapFromGlobal(Qt5Qt6Compat::eventGlobalPos(mouseEvent));
 
  156        m_resizingInProgress = 
true;
 
  158            Q_EMIT DockRegistry::self()->frameInMDIResizeChanged();
 
  159        mNewPosition = Qt5Qt6Compat::eventGlobalPos(mouseEvent);
 
  160        mCursorPos = cursorPos;
 
  165        m_resizingInProgress = 
false;
 
  167            Q_EMIT DockRegistry::self()->frameInMDIResizeChanged();
 
  168            auto frame = 
static_cast<Frame *
>(mTarget);
 
  172            frame->mdiLayoutWidget()->setDockWidgetGeometry(frame, frame->QWidgetAdapter::geometry());
 
  175        auto cursorPos = cursorPosition(Qt5Qt6Compat::eventGlobalPos(mouseEvent));
 
  176        updateCursor(cursorPos);
 
  178        if (mTarget->isMaximized() || !m_resizingInProgress || mouseEvent->button() != 
Qt::LeftButton)
 
  181        mTarget->releaseMouse();
 
  182        mTarget->releaseKeyboard();
 
  188        if (mTarget->isMaximized())
 
  192            const Frame *frameBeingResized = DockRegistry::self()->frameInMDIResize();
 
  193            const bool otherFrameBeingResized = frameBeingResized && frameBeingResized != mTarget;
 
  194            if (otherFrameBeingResized) {
 
  201        m_resizingInProgress = m_resizingInProgress && (mouseEvent->buttons() & 
Qt::LeftButton);
 
  203        const bool consumed = mouseMoveEvent(mouseEvent);
 
  212bool WidgetResizeHandler::mouseMoveEvent(
QMouseEvent *e)
 
  214    const QPoint globalPos = Qt5Qt6Compat::eventGlobalPos(e);
 
  215    if (!m_resizingInProgress) {
 
  221    const QRect oldGeometry = KDDockWidgets::globalGeometry(mTarget);
 
  222    QRect newGeometry = oldGeometry;
 
  224    QRect parentGeometry;
 
  225    if (!mTarget->isTopLevel()) {
 
  226        auto parent = KDDockWidgets::Private::parentWidget(mTarget);
 
  227        parentGeometry = KDDockWidgets::globalGeometry(parent);
 
  236        switch (mCursorPos) {
 
  240            parentGeometry = parentGeometry.
adjusted(m_resizeGap, 0, 0, 0);
 
  241            deltaWidth = oldGeometry.
left() - globalPos.
x();
 
  242            newWidth = qBound(minWidth, mTarget->width() + deltaWidth, maxWidth);
 
  243            deltaWidth = newWidth - mTarget->width();
 
  244            if (deltaWidth != 0) {
 
  245                newGeometry.
setLeft(newGeometry.
left() - deltaWidth);
 
  254            parentGeometry = parentGeometry.
adjusted(0, 0, -m_resizeGap, 0);
 
  255            deltaWidth = globalPos.
x() - newGeometry.
right();
 
  256            newWidth = qBound(minWidth, mTarget->width() + deltaWidth, maxWidth);
 
  257            deltaWidth = newWidth - mTarget->width();
 
  258            if (deltaWidth != 0) {
 
  273        switch (mCursorPos) {
 
  277            parentGeometry = parentGeometry.
adjusted(0, m_resizeGap, 0, 0);
 
  278            deltaHeight = oldGeometry.
top() - globalPos.
y();
 
  279            newHeight = qBound(minHeight, mTarget->height() + deltaHeight, maxHeight);
 
  280            deltaHeight = newHeight - mTarget->height();
 
  281            if (deltaHeight != 0) {
 
  282                newGeometry.
setTop(newGeometry.
top() - deltaHeight);
 
  291            parentGeometry = parentGeometry.
adjusted(0, 0, 0, -m_resizeGap);
 
  292            deltaHeight = globalPos.
y() - newGeometry.
bottom();
 
  293            newHeight = qBound(minHeight, mTarget->height() + deltaHeight, maxHeight);
 
  294            deltaHeight = newHeight - mTarget->height();
 
  295            if (deltaHeight != 0) {
 
  305    if (newGeometry == mTarget->geometry()) {
 
  310    if (!mTarget->isTopLevel()) {
 
  313        newGeometry = newGeometry.
intersected(parentGeometry);
 
  316        newGeometry.
moveTopLeft(mTarget->mapFromGlobal(newGeometry.
topLeft()) + mTarget->pos());
 
  319    mTarget->setGeometry(newGeometry);
 
  326bool WidgetResizeHandler::handleWindowsNativeEvent(FloatingWindow *fw, 
const QByteArray &eventType,
 
  327                                                   void *message, Qt5Qt6Compat::qintptr *result)
 
  329    if (eventType != 
"windows_generic_MSG")
 
  332    auto msg = 
static_cast<MSG *
>(message);
 
  333    if (msg->message == WM_NCHITTEST) {
 
  334        if (DragController::instance()->isInClientDrag()) {
 
  340        const QRect htCaptionRect = fw->dragRect();
 
  341        const bool ret = handleWindowsNativeEvent(fw->windowHandle(), msg, result, htCaptionRect);
 
  343        fw->setLastHitTest(*result);
 
  345    } 
else if (msg->message == WM_NCLBUTTONDBLCLK) {
 
  347            return handleWindowsNativeEvent(fw->windowHandle(), msg, result, {});
 
  350            if (TitleBar *titleBar = fw->titleBar()) {
 
  351                if (titleBar->isVisible()) { 
 
  352                    titleBar->onDoubleClicked();
 
  360    return handleWindowsNativeEvent(fw->windowHandle(), msg, result, {});
 
  363bool WidgetResizeHandler::handleWindowsNativeEvent(
QWindow *w, MSG *msg,
 
  364                                                   Qt5Qt6Compat::qintptr *result,
 
  365                                                   const NativeFeatures &features)
 
  367    if (msg->message == WM_NCCALCSIZE && features.hasShadow()) {
 
  370    } 
else if (msg->message == WM_NCHITTEST && (features.hasResize() || features.hasDrag())) {
 
  371        const int borderWidth = 8;
 
  374        const bool hasFixedWidthOrHeight = hasFixedWidth || hasFixedHeight;
 
  377        const int xPos = GET_X_LPARAM(msg->lParam);
 
  378        const int yPos = GET_Y_LPARAM(msg->lParam);
 
  380        GetWindowRect(
reinterpret_cast<HWND
>(w->
winId()), &rect);
 
  382        if (!hasFixedWidthOrHeight && xPos >= rect.left && xPos <= rect.left + borderWidth && yPos <= rect.bottom && yPos >= rect.bottom - borderWidth && features.hasResize()) {
 
  383            *result = HTBOTTOMLEFT;
 
  384        } 
else if (!hasFixedWidthOrHeight && xPos < rect.right && xPos >= rect.right - borderWidth && yPos <= rect.bottom && yPos >= rect.bottom - borderWidth && features.hasResize()) {
 
  385            *result = HTBOTTOMRIGHT;
 
  386        } 
else if (!hasFixedWidthOrHeight && xPos >= rect.left && xPos <= rect.left + borderWidth && yPos >= rect.top && yPos <= rect.top + borderWidth && features.hasResize()) {
 
  388        } 
else if (!hasFixedWidthOrHeight && xPos <= rect.right && xPos >= rect.right - borderWidth && yPos >= rect.top && yPos < rect.top + borderWidth && features.hasResize()) {
 
  389            *result = HTTOPRIGHT;
 
  390        } 
else if (!hasFixedWidth && xPos >= rect.left && xPos <= rect.left + borderWidth && features.hasResize()) {
 
  392        } 
else if (!hasFixedHeight && yPos >= rect.top && yPos <= rect.top + borderWidth && features.hasResize()) {
 
  394        } 
else if (!hasFixedHeight && yPos <= rect.bottom && yPos >= rect.bottom - borderWidth && features.hasResize()) {
 
  396        } 
else if (!hasFixedWidth && xPos <= rect.right && xPos >= rect.right - borderWidth && features.hasResize()) {
 
  398        } 
else if (features.hasDrag()) {
 
  399            const QPoint globalPosQt = QHighDpi::fromNativePixels(
QPoint(xPos, yPos), w);
 
  401            const QRect htCaptionRect = features.htCaptionRect;
 
  402            if (globalPosQt.
y() >= htCaptionRect.
top() && globalPosQt.
y() <= htCaptionRect.
bottom() && globalPosQt.
x() >= htCaptionRect.
left() && globalPosQt.
x() <= htCaptionRect.
right()) {
 
  403                if (!KDDockWidgets::inDisallowDragWidget(globalPosQt)) { 
 
  410    } 
else if (msg->message == WM_NCLBUTTONDBLCLK && features.hasMaximize()) {
 
  416    } 
else if (msg->message == WM_GETMINMAXINFO) {
 
  423        if (!screen || w->
screen() != screen) {
 
  427        DefWindowProc(msg->hwnd, msg->message, msg->wParam, msg->lParam);
 
  431        auto mmi = 
reinterpret_cast<MINMAXINFO *
>(msg->lParam);
 
  434        mmi->ptMaxSize.y = int(availableGeometry.
height() * dpr);
 
  435        mmi->ptMaxSize.x = int(availableGeometry.
width() * dpr) - 1; 
 
  436        mmi->ptMaxPosition.x = availableGeometry.
x();
 
  437        mmi->ptMaxPosition.y = availableGeometry.
y();
 
  456        if (m_usesGlobalEventFilter) {
 
  457            qApp->installEventFilter(
this);
 
  459            mTarget->installEventFilter(
this);
 
  462        qWarning() << 
"Target widget is null!";
 
  468#ifdef KDDOCKWIDGETS_QTWIDGETS 
  470    const QObjectList children = mTarget->children();
 
  471    for (
int i = 0, total = children.size(); i < total; ++i) {
 
  472        if (
auto child = qobject_cast<WidgetType *>(children.at(i))) {
 
  499        restoreMouseCursor();
 
  511    if (m_usesGlobalEventFilter) {
 
  512        if (m_overrideCursorSet) {
 
  513            qApp->changeOverrideCursor(cursor);
 
  515            qApp->setOverrideCursor(cursor);
 
  516            m_overrideCursorSet = 
true;
 
  519        mTarget->setCursor(cursor);
 
  523void WidgetResizeHandler::restoreMouseCursor()
 
  525    if (m_usesGlobalEventFilter) {
 
  526        if (m_overrideCursorSet) {
 
  527            qApp->restoreOverrideCursor();
 
  528            m_overrideCursorSet = 
false;
 
  540#ifdef KDDOCKWIDGETS_QTQUICK 
  544        return CursorPosition(mTarget->property(
"cursorPosition").toInt());
 
  548    QPoint pos = mTarget->mapFromGlobal(globalPos);
 
  550    const int x = pos.
x();
 
  551    const int y = pos.
y();
 
  552    const int margin = widgetResizeHandlerMargin();
 
  556    if (y >= -margin && y <= mTarget->height() + margin) {
 
  557        if (qAbs(x) <= margin)
 
  559        else if (qAbs(x - (mTarget->width() - margin)) <= margin)
 
  563    if (x >= -margin && x <= mTarget->width() + margin) {
 
  564        if (qAbs(y) <= margin)
 
  566        else if (qAbs(y - (mTarget->height() - margin)) <= margin)
 
  571    result = result & mAllowedResizeSides;
 
  577void WidgetResizeHandler::setupWindow(
QWindow *window)
 
  583    if (KDDockWidgets::usesAeroSnapWithCustomDecos()) {
 
  584        const auto wid = HWND(window->
winId());
 
  590            SetWindowPos(wid, 0, 0, 0, 0, 0,
 
  591                         SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
 
  594        const bool usesTransparentFloatingWindow =
 
  596        if (!usesTransparentFloatingWindow) {
 
  600            MARGINS margins = { 0, 0, 0, 1 }; 
 
  601            DwmExtendFrameIntoClientArea(wid, &margins);
 
  610bool WidgetResizeHandler::isInterestingNativeEvent(
unsigned int nativeEvent)
 
  612    switch (nativeEvent) {
 
  615    case WM_NCLBUTTONDBLCLK:
 
  616    case WM_GETMINMAXINFO:
 
  624#if defined(Q_OS_WIN) && defined(KDDOCKWIDGETS_QTWIDGETS) 
  625bool NCHITTESTEventFilter::nativeEventFilter(
const QByteArray &eventType, 
void *message,
 
  626                                             Qt5Qt6Compat::qintptr *result)
 
  629    if (eventType != 
"windows_generic_MSG" || !m_floatingWindow)
 
  632    auto msg = 
static_cast<MSG *
>(message);
 
  633    if (msg->message != WM_NCHITTEST)
 
  635    const WId wid = WId(msg->hwnd);
 
  638    if (!child || child->
window() != m_floatingWindow)
 
  640    const bool isThisWindow = child == m_floatingWindow;
 
  643        *result = HTTRANSPARENT;
 
  652CustomFrameHelper::CustomFrameHelper(ShouldUseCustomFrame func, 
QObject *parent)
 
  655    , m_shouldUseCustomFrameFunc(func)
 
  658    qApp->installNativeEventFilter(
this);
 
  662CustomFrameHelper::~CustomFrameHelper()
 
  667void CustomFrameHelper::applyCustomFrame(
QWindow *window)
 
  670    WidgetResizeHandler::setupWindow(window);
 
  673    qWarning() << Q_FUNC_INFO << 
"Not implemented on this platform";
 
  677bool CustomFrameHelper::nativeEventFilter(
const QByteArray &eventType, 
void *message,
 
  678                                          Qt5Qt6Compat::qintptr *result)
 
  680    if (m_shouldUseCustomFrameFunc == 
nullptr || m_recursionGuard)
 
  686    if (m_inDtor || !KDDockWidgets::usesAeroSnapWithCustomDecos())
 
  689    if (eventType != 
"windows_generic_MSG")
 
  692    auto msg = 
static_cast<MSG *
>(message);
 
  693    if (!WidgetResizeHandler::isInterestingNativeEvent(msg->message)) {
 
  698    QWindow *window = DockRegistry::self()->windowForHandle(WId(msg->hwnd));
 
  702    const WidgetResizeHandler::NativeFeatures features = m_shouldUseCustomFrameFunc(window);
 
  703    if (!features.hasFeatures()) {
 
  708    const char *propertyName = 
"kddw_customframe_setup_ran";
 
  712        WidgetResizeHandler::setupWindow(window);
 
  716    return WidgetResizeHandler::handleWindowsNativeEvent(window, msg, result, features);
 
Application-wide config to tune certain behaviours of the framework.
QEvent::Type type() const const
QVariant property(const char *name) const const
bool setProperty(const char *name, const QVariant &value)
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const const
bool contains(const QRect &rectangle, bool proper) const const
QRect intersected(const QRect &rectangle) const const
QRect marginsAdded(const QMargins &margins) const const
void moveTopLeft(const QPoint &position)
QPoint topLeft() const const
bool toBool() const const
QScreen * screen() const const
void screenChanged(QScreen *screen)