commit ab4ca0d1b8ee63d76425384f73f83ddbe2d4b3b8
Author: JS/TT
Date:   Mon Nov 13 13:38:05 2006 +0100
Branches: <Expand>

    Fixes:    Integrate the ncevent stuff into main
    Details:  Surely it won't break a thing.
    
    [git-p4: depot-paths = "//depot/qt/main/": change = 242243]


--- src/corelib/kernel/qcoreevent.h
+++ src/corelib/kernel/qcoreevent.h
@@ -204,6 +204,12 @@ public:
 
         TabletEnterProximity = 171,
         TabletLeaveProximity = 172,
+
+        NonClientAreaMouseMove = 173,
+        NonClientAreaMouseButtonPress = 174,
+        NonClientAreaMouseButtonRelease = 175,
+        NonClientAreaMouseButtonDblClick = 176,
+
         User = 1000,                            // first user event id
         MaxUser = 65535                         // last user event id
     };
--- src/gui/kernel/qapplication_mac.cpp
+++ src/gui/kernel/qapplication_mac.cpp
@@ -1370,6 +1370,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
     case kEventClassMouse:
     {
         Point where;
+        bool inNonClientArea = false;
         GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, 0,
                           sizeof(where), 0, &where);
         if(ekind == kEventMouseMoved && qt_mac_app_fullscreen &&
@@ -1490,6 +1491,27 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
                 }
             }
         }
+        if (widget && widget->isWindow() && !widget->geometry().contains(QPoint(where.h, where.v))) {
+            inNonClientArea = true;
+            switch (etype) {
+            case QEvent::MouseButtonPress:
+                etype = QEvent::NonClientAreaMouseButtonPress;
+                break;
+            case QEvent::MouseButtonRelease:
+                etype = QEvent::NonClientAreaMouseButtonRelease;
+                break;
+            case QEvent::MouseButtonDblClick:
+                etype = QEvent::NonClientAreaMouseButtonDblClick;
+                break;
+            case QEvent::MouseMove:
+                etype = QEvent::NonClientAreaMouseMove;
+                break;
+            default:
+                break;
+            }
+        }
+
+
         if(qt_mac_find_window((FrontWindow()))) { //set the cursor up
             QCursor cursor(Qt::ArrowCursor);
             QWidget *cursor_widget = widget;
@@ -1618,7 +1640,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
         switch(ekind) {
         case kEventMouseDragged:
         case kEventMouseMoved:
-            if((QWidget *)qt_mouseover != widget) {
+            if((QWidget *)qt_mouseover != widget || inNonClientArea) {
 #ifdef DEBUG_MOUSE_MAPS
                 qDebug("Entering: %p - %s (%s), Leaving %s (%s)", (QWidget*)widget,
                        widget ? widget->metaObject()->className() : "none",
@@ -1698,7 +1720,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
                 }
                 QMouseEvent qme(etype, plocal, p, buttonToSend, buttons, modifiers);
                 QApplication::sendSpontaneousEvent(widget, &qme);
-                if(!qme.isAccepted())
+                if(!qme.isAccepted() || inNonClientArea)
                     handled_event = false;
             }
 
--- src/gui/kernel/qapplication_win.cpp
+++ src/gui/kernel/qapplication_win.cpp
@@ -1081,6 +1081,15 @@ bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event)
     return QCoreApplication::sendSpontaneousEvent(receiver, event);
 }
 
+static bool qt_is_translatable_mouse_event(UINT message)
+{
+    return (message >= WM_MOUSEFIRST && message <= WM_MOUSELAST ||
+                message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK)
+            && message != WM_MOUSEWHEEL
+
+            || message >= WM_NCMOUSEMOVE && message <= WM_NCMBUTTONDBLCLK;
+}
+
 extern "C"
 LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 {
@@ -1111,7 +1120,10 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam
     msg.lParam = lParam;
     msg.pt.x = GET_X_LPARAM(lParam);
     msg.pt.y = GET_Y_LPARAM(lParam);
-    ClientToScreen(msg.hwnd, &msg.pt);         // the coords we get are client coords
+    // If it's a non-client-area message the coords are screen coords, otherwise they are
+    // client coords.
+    if (message < WM_NCMOUSEMOVE || message > WM_NCMBUTTONDBLCLK)
+        ClientToScreen(msg.hwnd, &msg.pt);
 
     /*
     // sometimes the autograb is not released, so the clickevent is sent
@@ -1254,9 +1266,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam
     if (widget->winEvent(&msg, &res))                // send through widget filter
         RETURN(res);
 
-    if ((message >= WM_MOUSEFIRST && message <= WM_MOUSELAST ||
-           message >= WM_XBUTTONDOWN && message <= WM_XBUTTONDBLCLK)
-         && message != WM_MOUSEWHEEL) {
+    if (qt_is_translatable_mouse_event(message)) {
         if (qApp->activePopupWidget() != 0) { // in popup mode
             POINT curPos = msg.pt;
             QWidget* w = QApplication::widgetAt(curPos.x, curPos.y);
@@ -1461,7 +1471,6 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam
             }
             break;
 
-#ifndef Q_OS_TEMP
         case WM_NCHITTEST:
             if (widget->isWindow()) {
                 QPoint pos = widget->mapFromGlobal(QPoint(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)));
@@ -1477,24 +1486,6 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam
 
             result = false;
             break;
-        case WM_NCMOUSEMOVE:
-            {
-                // span the application wide cursor over the
-                // non-client area.
-                QCursor *c = qt_grab_cursor();
-                if (!c)
-                    c = QApplication::overrideCursor();
-                if (c)        // application cursor defined
-                    SetCursor(c->handle());
-                else
-                    result = false;
-                // generate leave event also when the caret enters
-                // the non-client area.
-                QApplicationPrivate::dispatchEnterLeave(0, QWidget::find(curWin));
-                curWin = 0;
-            }
-            break;
-#endif
 
         case WM_SYSCOMMAND: {
 #ifndef Q_OS_TEMP
@@ -2047,6 +2038,7 @@ LRESULT CALLBACK QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam
         QEvent e(evt_type);
         result = qt_sendSpontaneousEvent(widget, &e);
     }
+
     if (result)
         RETURN(false);
 
@@ -2295,6 +2287,18 @@ static ushort mouseTbl[] = {
     WM_XBUTTONDOWN,      QEvent::MouseButtonPress,        Qt::XButton1,
     WM_XBUTTONUP,        QEvent::MouseButtonRelease,      Qt::XButton1,
     WM_XBUTTONDBLCLK,    QEvent::MouseButtonDblClick,     Qt::XButton1,
+
+    WM_NCMOUSEMOVE,      QEvent::NonClientAreaMouseMove,           0,
+    WM_NCLBUTTONDOWN,    QEvent::NonClientAreaMouseButtonPress,    Qt::LeftButton,
+    WM_NCLBUTTONUP,      QEvent::NonClientAreaMouseButtonRelease,  Qt::LeftButton,
+    WM_NCLBUTTONDBLCLK,  QEvent::NonClientAreaMouseButtonDblClick, Qt::LeftButton,
+    WM_NCRBUTTONDOWN,    QEvent::NonClientAreaMouseButtonPress,    Qt::RightButton,
+    WM_NCRBUTTONUP,      QEvent::NonClientAreaMouseButtonRelease,  Qt::RightButton,
+    WM_NCRBUTTONDBLCLK,  QEvent::NonClientAreaMouseButtonDblClick, Qt::RightButton,
+    WM_NCMBUTTONDOWN,    QEvent::NonClientAreaMouseButtonPress,    Qt::MidButton,
+    WM_NCMBUTTONUP,      QEvent::NonClientAreaMouseButtonRelease,  Qt::MidButton,
+    WM_NCMBUTTONDBLCLK,  QEvent::NonClientAreaMouseButtonDblClick, Qt::MidButton,
+
     0,                        0,                                0
 };
 
@@ -2434,7 +2438,6 @@ bool QETWidget::translateMouseEvent(const MSG &msg)
         }
     }
 
-
     for (i=0; (UINT)mouseTbl[i] != msg.message || !mouseTbl[i]; i += 3)
         ;
     if (!mouseTbl[i])
@@ -2452,24 +2455,33 @@ bool QETWidget::translateMouseEvent(const MSG &msg)
         }
     }
     state  = translateButtonState(msg.wParam, type, button); // button state
-    if (type == QEvent::MouseMove) {
+
+    if (type == QEvent::MouseMove || type == QEvent::NonClientAreaMouseMove) {
         if (!(state & Qt::MouseButtonMask))
             qt_button_down = 0;
+        
         QCursor *c = qt_grab_cursor();
         if (!c)
             c = QApplication::overrideCursor();
         if (c)                                // application cursor defined
             SetCursor(c->handle());
-        else {
+        else if (type != QEvent::NonClientAreaMouseMove) {
             QWidget *w = this; // use  widget cursor if widget is enabled
             while (!w->isWindow() && !w->isEnabled())
                 w = w->parentWidget();
             SetCursor(w->cursor().handle());
         }
-        if (curWin != internalWinId()) {                // new current window
-            QApplicationPrivate::dispatchEnterLeave(this, QWidget::find(curWin));
-            curWin = internalWinId();
+
+        HWND id = internalWinId();
+        if (type == QEvent::NonClientAreaMouseMove)
+            id = 0;
+
+        if (curWin != id) {                // new current window
+            QApplicationPrivate::dispatchEnterLeave(id == 0 ? 0 : this, QWidget::find(curWin));
+            curWin = id;
 #ifndef Q_OS_TEMP
+
+            if (curWin != 0) {
                 static bool trackMouseEventLookup = false;
                 typedef BOOL (WINAPI *PtrTrackMouseEvent)(LPTRACKMOUSEEVENT);
                 static PtrTrackMouseEvent ptrTrackMouseEvent = 0;
@@ -2487,6 +2499,7 @@ bool QETWidget::translateMouseEvent(const MSG &msg)
                     tme.dwHoverTime = (DWORD)-1; // HOVER_DEFAULT
                     ptrTrackMouseEvent(&tme);
                 }
+            }
 #endif // Q_OS_TEMP
         }
 
@@ -2515,7 +2528,14 @@ bool QETWidget::translateMouseEvent(const MSG &msg)
 
     bool res = false;
 
+    bool nonClientAreaEvent = type >= QEvent::NonClientAreaMouseMove
+                                && type <= QEvent::NonClientAreaMouseButtonDblClick;
+
     if (qApp->d_func()->inPopupMode()) {                        // in popup mode
+
+        if (nonClientAreaEvent)
+            return false;
+
         replayPopupMouseEvent = false;
         QWidget* activePopupWidget = qApp->activePopupWidget();
         QWidget *target = activePopupWidget;
@@ -2616,13 +2636,13 @@ bool QETWidget::translateMouseEvent(const MSG &msg)
              (state & Qt::MouseButtonMask) == 0) {
             qt_button_down = 0;
         }
-
         QMouseEvent e(type, pos, QPoint(gpos.x,gpos.y),
                       Qt::MouseButton(button),
                       Qt::MouseButtons(state & Qt::MouseButtonMask),
                       Qt::KeyboardModifiers(state & Qt::KeyboardModifierMask));
         res = QApplication::sendSpontaneousEvent(widget, &e);
-        res = res && e.isAccepted();
+        // non client area events are only informational, you cannot "handle" them
+        res = res && e.isAccepted() && !nonClientAreaEvent;
         if (type == QEvent::MouseButtonRelease && button == Qt::RightButton) {
             QContextMenuEvent e2(QContextMenuEvent::Mouse, pos, QPoint(gpos.x,gpos.y));
             bool res2 = QApplication::sendSpontaneousEvent(widget, &e2);
--- src/gui/kernel/qlayoutengine.cpp
+++ src/gui/kernel/qlayoutengine.cpp
@@ -272,60 +272,67 @@ void qGeomCalc(QVector<QLayoutStruct> &chain, int start, int count,
 #endif
 }
 
-Q_GUI_EXPORT QSize qSmartMinSize(const QWidgetItem *i)
+Q_GUI_EXPORT QSize qSmartMinSize(const QSize &sizeHint, const QSize &minSizeHint,
+                                 const QSize &minSize, const QSize &maxSize,
+                                 const QSizePolicy &sizePolicy)
 {
-    QWidget *w = ((QWidgetItem *)i)->widget();
-
     QSize s(0, 0);
-    QSize msh(w->minimumSizeHint());
-    QSize sh(w->sizeHint());
 
-    if (w->sizePolicy().horizontalPolicy() != QSizePolicy::Ignored) {
-        if (w->sizePolicy().horizontalPolicy() & QSizePolicy::ShrinkFlag)
-            s.setWidth(msh.width());
+    if (sizePolicy.horizontalPolicy() != QSizePolicy::Ignored) {
+        if (sizePolicy.horizontalPolicy() & QSizePolicy::ShrinkFlag)
+            s.setWidth(minSizeHint.width());
         else
-            s.setWidth(qMax(sh.width(), msh.width()));
+            s.setWidth(qMax(sizeHint.width(), minSizeHint.width()));
     }
 
-    if (w->sizePolicy().verticalPolicy() != QSizePolicy::Ignored) {
-        if (w->sizePolicy().verticalPolicy() & QSizePolicy::ShrinkFlag) {
-            s.setHeight(msh.height());
+    if (sizePolicy.verticalPolicy() != QSizePolicy::Ignored) {
+        if (sizePolicy.verticalPolicy() & QSizePolicy::ShrinkFlag) {
+            s.setHeight(minSizeHint.height());
         } else {
-            s.setHeight(qMax(sh.height(), msh.height()));
+            s.setHeight(qMax(sizeHint.height(), minSizeHint.height()));
         }
     }
 
-    s = s.boundedTo(w->maximumSize());
-    QSize min = w->minimumSize();
-    if (min.width() > 0)
-        s.setWidth(min.width());
-    if (min.height() > 0)
-        s.setHeight(min.height());
+    s = s.boundedTo(maxSize);
+    if (minSize.width() > 0)
+        s.setWidth(minSize.width());
+    if (minSize.height() > 0)
+        s.setHeight(minSize.height());
 
     return s.expandedTo(QSize(0,0));
 }
 
+Q_GUI_EXPORT QSize qSmartMinSize(const QWidgetItem *i)
+{
+    QWidget *w = ((QWidgetItem *)i)->widget();
+    return qSmartMinSize(w->sizeHint(), w->minimumSizeHint(),
+                            w->minimumSize(), w->maximumSize(),
+                            w->sizePolicy());
+}
+
 Q_GUI_EXPORT QSize qSmartMinSize(const QWidget *w)
 {
-    QWidgetItem item(const_cast<QWidget *>(w));
-    return qSmartMinSize(&item);
+    return qSmartMinSize(w->sizeHint(), w->minimumSizeHint(),
+                            w->minimumSize(), w->maximumSize(),
+                            w->sizePolicy());
 }
 
-Q_GUI_EXPORT QSize qSmartMaxSize(const QWidgetItem *i, Qt::Alignment align)
+Q_GUI_EXPORT QSize qSmartMaxSize(const QSize &sizeHint,
+                                 const QSize &minSize, const QSize &maxSize,
+                                 const QSizePolicy &sizePolicy, Qt::Alignment align)
 {
-    QWidget *w = ((QWidgetItem*)i)->widget();
     if (align & Qt::AlignHorizontal_Mask && align & Qt::AlignVertical_Mask)
         return QSize(QLAYOUTSIZE_MAX, QLAYOUTSIZE_MAX);
-    QSize s = w->maximumSize();
+    QSize s = maxSize;
     if (s.width() == QWIDGETSIZE_MAX && !(align & Qt::AlignHorizontal_Mask))
-        if (!(w->sizePolicy().horizontalPolicy() & QSizePolicy::GrowFlag))
-            s.setWidth(w->sizeHint().width());
+        if (!(sizePolicy.horizontalPolicy() & QSizePolicy::GrowFlag))
+            s.setWidth(sizeHint.width());
 
     if (s.height() == QWIDGETSIZE_MAX && !(align & Qt::AlignVertical_Mask))
-        if (!(w->sizePolicy().verticalPolicy() & QSizePolicy::GrowFlag))
-            s.setHeight(w->sizeHint().height());
+        if (!(sizePolicy.verticalPolicy() & QSizePolicy::GrowFlag))
+            s.setHeight(sizeHint.height());
 
-    s = s.expandedTo(w->minimumSize());
+    s = s.expandedTo(minSize);
 
     if (align & Qt::AlignHorizontal_Mask)
         s.setWidth(QLAYOUTSIZE_MAX);
@@ -334,9 +341,17 @@ Q_GUI_EXPORT QSize qSmartMaxSize(const QWidgetItem *i, Qt::Alignment align)
     return s;
 }
 
+Q_GUI_EXPORT QSize qSmartMaxSize(const QWidgetItem *i, Qt::Alignment align)
+{
+    QWidget *w = ((QWidgetItem*)i)->widget();
+
+    return qSmartMaxSize(w->sizeHint(), w->minimumSize(), w->maximumSize(),
+                            w->sizePolicy(), align);
+}
+
 Q_GUI_EXPORT QSize qSmartMaxSize(const QWidget *w, Qt::Alignment align)
 {
-    QWidgetItem item(const_cast<QWidget *>(w));
-    return qSmartMaxSize(&item, align);
+    return qSmartMaxSize(w->sizeHint(), w->minimumSize(), w->maximumSize(),
+                            w->sizePolicy(), align);
 }
 
--- src/gui/kernel/qlayoutengine_p.h
+++ src/gui/kernel/qlayoutengine_p.h
@@ -62,8 +62,14 @@ struct QLayoutStruct
 
 Q_GUI_EXPORT void qGeomCalc(QVector<QLayoutStruct> &chain, int start, int count,
                          int pos, int space, int spacer);
+Q_GUI_EXPORT QSize qSmartMinSize(const QSize &sizeHint, const QSize &minSizeHint,
+                                 const QSize &minSize, const QSize &maxSize,
+                                 const QSizePolicy &sizePolicy);
 Q_GUI_EXPORT QSize qSmartMinSize(const QWidgetItem *i);
 Q_GUI_EXPORT QSize qSmartMinSize(const QWidget *w);
+Q_GUI_EXPORT QSize qSmartMaxSize(const QSize &sizeHint,
+                                 const QSize &minSize, const QSize &maxSize,
+                                 const QSizePolicy &sizePolicy, Qt::Alignment align = 0);
 Q_GUI_EXPORT QSize qSmartMaxSize(const QWidgetItem *i, Qt::Alignment align = 0);
 Q_GUI_EXPORT QSize qSmartMaxSize(const QWidget *w, Qt::Alignment align = 0);
 
--- src/gui/kernel/qwidget_mac.cpp
+++ src/gui/kernel/qwidget_mac.cpp
@@ -480,7 +480,18 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event,
         }
         break; }
     case kEventClassMouse: {
+#if 0
+        return SendEventToApplication(event);
+#endif
+
         bool send_to_app = false;
+        {
+            WindowPartCode wpc;
+            if (GetEventParameter(event, kEventParamWindowPartCode, typeWindowPartCode, 0,
+                                  sizeof(wpc), 0, &wpc) == noErr && wpc != inContent)
+                send_to_app = true;
+        }
+        if(!send_to_app) {
             WindowRef window;
             if(GetEventParameter(event, kEventParamWindowRef, typeWindowRef, 0,
                                  sizeof(window), 0, &window) == noErr) {
@@ -496,6 +507,7 @@ OSStatus QWidgetPrivate::qt_window_event(EventHandlerCallRef er, EventRef event,
                     }
                 }
             }
+        }
         if(send_to_app)
             return SendEventToApplication(event);
         handled_event = false;
@@ -2336,7 +2348,8 @@ void QWidgetPrivate::setGeometry_sys_helper(int x, int y, int w, int h, bool isM
 
     if(q->isWindow()) {
         if(QWExtra *extra = extraData()) { //set constraints
-#define SF(x) qBound(0, x, 20000)
+            const float max_f(20000);
+#define SF(x) ((x > max_f) ? max_f : x)
             HISize max = CGSizeMake(SF(extra->maxw), SF(extra->maxh));
             HISize min = CGSizeMake(SF(extra->minw), SF(extra->minh));
 #undef SF
--- src/gui/widgets/qdockwidget.cpp
+++ src/gui/widgets/qdockwidget.cpp
@@ -161,32 +161,6 @@ void QDockWidgetTitleButton::paintEvent(QPaintEvent *)
 ** QDWLayout
 */
 
-class QDWLayout : public QLayout
-{
-public:
-    QDWLayout(QWidget *parent = 0);
-    void addItem(QLayoutItem *item);
-    QSize sizeHint() const;
-    void setGeometry(const QRect &r);
-    QLayoutItem *itemAt(int index) const;
-    QLayoutItem *takeAt(int index);
-    QSize minimumSize() const;
-    int count() const;
-
-    enum Role { Content, CloseButton, FloatButton, RoleCount };
-    QWidget *widget(Role r);
-    void setWidget(Role r, QWidget *w);
-
-    QRect titleArea() const { return _titleArea; }
-
-private:
-    QVector<QLayoutItem*> item_list;
-    QRect _titleArea;
-
-    int minimumTitleWidth() const;
-    int titleHeight() const;
-};
-
 void QDWLayout::addItem(QLayoutItem*)
 {
     qWarning() << "QDWLayout::addItem(): please use QDWLayout::setWidget()";
@@ -231,6 +205,44 @@ int QDWLayout::count() const
 
 QSize QDWLayout::sizeHint() const
 {
+    QSize result(-1, -1);
+
+#ifndef Q_WS_X11
+    QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
+    if (w->isFloating()) {
+        if (item_list[Content] != 0)
+            result = item_list[Content]->sizeHint();
+    } else {
+#endif
+        result = dockedSizeHint();
+#ifndef Q_WS_X11
+    }
+#endif
+
+    return result;
+}
+
+QSize QDWLayout::minimumSize() const
+{
+    QSize result(0, 0);
+
+#ifndef Q_WS_X11
+    QDockWidget *w = qobject_cast<QDockWidget*>(parentWidget());
+    if (w->isFloating()) {
+        if (item_list[Content] != 0)
+            result = item_list[Content]->sizeHint();
+    } else {
+#endif
+        result = dockedMinimumSize();
+#ifndef Q_WS_X11
+    }
+#endif
+
+    return result;
+}
+
+QSize QDWLayout::dockedSizeHint() const
+{
     QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
 
     int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
@@ -245,7 +257,7 @@ QSize QDWLayout::sizeHint() const
     return QSize(w, h);
 }
 
-QSize QDWLayout::minimumSize() const
+QSize QDWLayout::dockedMinimumSize() const
 {
     QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
 
@@ -334,6 +346,12 @@ void QDWLayout::setGeometry(const QRect &geometry)
 {
     QDockWidget *q = qobject_cast<QDockWidget*>(parentWidget());
 
+#ifndef Q_WS_X11
+    if (q->isFloating()) {
+        if (QLayoutItem *item = item_list[Content])
+            item->setGeometry(geometry);
+    } else {
+#endif
         int fw = 0;
         if (q->isFloating())
             fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
@@ -342,19 +360,6 @@ void QDWLayout::setGeometry(const QRect &geometry)
         _titleArea = QRect(QPoint(fw, fw),
                             QSize(geometry.width() - (fw * 2), titleHeight));
 
-#if 0
-    QPoint buttonOffset(0, 0);
-#ifdef Q_OS_WIN
-    // ### Qt 4.3: Fix this properly
-    if (q->style()->inherits("QWindowsXPStyle")) {
-        if(q->isFloating())
-            buttonOffset = QPoint(2, -1);
-        else
-            buttonOffset = QPoint(0, 1);
-    }
-#endif
-#endif
-
         QStyleOptionDockWidget opt;
         q->initStyleOption(&opt);
 
@@ -376,6 +381,9 @@ void QDWLayout::setGeometry(const QRect &geometry)
             r.adjust(fw, 0, -fw, -fw);
             item->setGeometry(r);
         }
+#ifndef Q_WS_X11
+    }
+#endif
 }
 
 /******************************************************************************
@@ -396,9 +404,11 @@ void QDockWidgetPrivate::init()
     QObject::connect(button, SIGNAL(clicked()), q, SLOT(close()));
     layout->setWidget(QDWLayout::CloseButton, button);
 
+#ifdef Q_WS_X11
     resizer = new QWidgetResizeHandler(q);
     resizer->setMovingEnabled(false);
     resizer->setActive(false);
+#endif
 
 #ifndef QT_NO_ACTION
     toggleViewAction = new QAction(q);
@@ -453,20 +463,23 @@ void QDockWidgetPrivate::updateButtons()
 
     bool canClose = hasFeature(q, QDockWidget::DockWidgetClosable);
     bool canFloat = hasFeature(q, QDockWidget::DockWidgetFloatable);
+    bool nonX11Floating = false;
+#ifndef Q_WS_X11
+    nonX11Floating = q->isFloating(); // we use native window deocrations
+#endif
 
     QAbstractButton *button
         = qobject_cast<QAbstractButton*>(layout->widget(QDWLayout::FloatButton));
-    button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton,
-                                                &opt, q));
-    button->setVisible(canFloat);
+    button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarNormalButton));
+    button->setVisible(canFloat && !nonX11Floating);
 
     button
         = qobject_cast <QAbstractButton*>(layout->widget(QDWLayout::CloseButton));
-    button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton,
-                                                &opt, q));
-    button->setVisible(canClose);
+    button->setIcon(q->style()->standardIcon(QStyle::SP_TitleBarCloseButton));
+    button->setVisible(canClose && !nonX11Floating);
+
+    q->setAttribute(Qt::WA_ContentsPropagated, (canFloat || canClose) && !nonX11Floating);
 
-    q->setAttribute(Qt::WA_ContentsPropagated, canFloat || canClose);
     layout->update();
 }
 
@@ -507,17 +520,83 @@ QMainWindow *QDockWidgetPrivate::findMainWindow(QWidget *widget) const
     return mainwindow;
 }
 
+void QDockWidgetPrivate::initDrag(const QPoint &pos, bool nca)
+{
+    Q_ASSERT(state == 0);
+
+    state = new QDockWidgetPrivate::DragState;
+    state->pressPos = pos;
+    state->dragging = false;
+    state->widgetItem = 0;
+    state->ownWidgetItem = false;
+    state->nca = nca;
+}
+
+void QDockWidgetPrivate::startDrag()
+{
+    Q_Q(QDockWidget);
+
+    Q_ASSERT(state != 0);
+    if (state->dragging)
+        return;
+
+    QMainWindowLayout *layout
+        = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
+    Q_ASSERT(layout != 0);
+
+    state->widgetItem = layout->unplug(q);
+    if (state->widgetItem == 0) {
+        /* I have a QMainWindow parent, but I was never inserted with
+            QMainWindow::addDockWidget, so the QMainWindowLayout has no
+            widget item for me. :( I have to create it myself, and then
+            delete it if I don't get dropped into a dock area. */
+        state->widgetItem = new QWidgetItem(q);
+        state->ownWidgetItem = true;
+    }
+
+    state->dragging = true;
+}
+
+void QDockWidgetPrivate::endDrag()
+{
+    Q_Q(QDockWidget);
+    Q_ASSERT(state != 0);
+
+    if (state->dragging) {
+        QMainWindowLayout *layout =
+            qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
+        Q_ASSERT(layout != 0);
+
+        if (!state->pathToGap.isEmpty()) {
+            layout->plug(state->widgetItem, state->pathToGap);
+        } else {
+            layout->restore();
+
+            if (state->ownWidgetItem)
+                delete state->widgetItem;
+#ifdef Q_WS_X11
+            setWindowState(true); // gets rid of the X11BypassWindowManager window flag
+#endif
+        }
+    }
+    delete state;
+    state = 0;
+}
+
 void QDockWidgetPrivate::mousePressEvent(QMouseEvent *event)
 {
 #if !defined(QT_NO_MAINWINDOW)
     Q_Q(QDockWidget);
 
+#ifndef Q_WS_X11
+    if (!q->isFloating()) {
+#endif
+
         QDWLayout *layout = qobject_cast<QDWLayout*>(q->layout());
         QRect titleArea = layout->titleArea();
 
         if (event->button() != Qt::LeftButton)
             return;
-
         if (!titleArea.contains(event->pos()))
             return;
         // check if the tool window is movable... do nothing if it is not
@@ -533,12 +612,12 @@ void QDockWidgetPrivate::mousePressEvent(QMouseEvent *event)
         if (state != 0)
             return;
 
-    state = new QDockWidgetPrivate::DragState;
+        initDrag(event->pos(), false);
+
+#ifndef Q_WS_X11
+    }
+#endif
 
-    state->pressPos = event->pos();
-    state->dragging = false;
-    state->widgetItem = 0;
-    state->ownWidgetItem = false;
 #endif // !defined(QT_NO_MAINWINDOW)
 }
 
@@ -546,6 +625,10 @@ void QDockWidgetPrivate::mouseDoubleClickEvent(QMouseEvent *event)
 {
     Q_Q(QDockWidget);
 
+#ifndef Q_WS_X11
+    if (!q->isFloating()) {
+#endif
+
         QDWLayout *layout = qobject_cast<QDWLayout*>(q->layout());
         QRect titleArea = layout->titleArea();
 
@@ -556,6 +639,11 @@ void QDockWidgetPrivate::mouseDoubleClickEvent(QMouseEvent *event)
         if (!::hasFeature(q, QDockWidget::DockWidgetFloatable))
             return;
         _q_toggleTopLevel();
+
+#ifndef Q_WS_X11
+    }
+#endif
+
 }
 
 void QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
@@ -570,98 +658,180 @@ void QDockWidgetPrivate::mouseMoveEvent(QMouseEvent *event)
         = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
     Q_ASSERT(layout != 0);
 
+#ifndef Q_WS_X11
+    if (!q->isFloating()) {
+#endif
         if (!state->dragging
             && layout->pluggingWidget == 0
             && (event->pos() - state->pressPos).manhattanLength() > QApplication::startDragDistance()) {
-        state->widgetItem = layout->unplug(q);
-        if (state->widgetItem == 0) {
-            /* I have a QMainWindow parent, but I was never inserted with QMainWindow::addDockWidget,
-               so the QMainWindowLayout has no widget item for me. :(
-               I have to create it myself, and then delete it if I don't get dropped into a
-               dock area. */
-            state->widgetItem = new QWidgetItem(q);
-            state->ownWidgetItem = true;
-        }
+            startDrag();
             q->grabMouse();
-        state->dragging = true;
         }
 
-    if (state->dragging) {
-        q->move(event->globalPos() - state->pressPos);
+#ifndef Q_WS_X11
+    }
+#endif
+
+    if (state->dragging && !state->nca) {
+        QPoint pos = event->globalPos() - state->pressPos;
+        q->move(pos);
 
         if (!(event->modifiers() & Qt::ControlModifier))
             state->pathToGap = layout->hover(state->widgetItem, event->globalPos());
     }
+
 #endif // !defined(QT_NO_MAINWINDOW)
 }
 
 void QDockWidgetPrivate::mouseReleaseEvent(QMouseEvent *event)
 {
-#if !defined(QT_NO_MAINWINDOW)
     Q_Q(QDockWidget);
+#if !defined(QT_NO_MAINWINDOW)
+
+    q->releaseMouse();
+
     if (event->button() != Qt::LeftButton)
         return;
     if (!state)
         return;
+    if (state->nca)
+        return;
 
-    if (state->dragging) {
-        QMainWindowLayout *layout =
-            qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
-        Q_ASSERT(layout != 0);
+    endDrag();
 
-        q->releaseMouse();
+#endif // !defined(QT_NO_MAINWINDOW)
+}
 
-        if (!(event->modifiers() & Qt::ControlModifier) && !state->pathToGap.isEmpty()) {
-            layout->plug(state->widgetItem, state->pathToGap);
-        } else {
-            layout->restore();
+void QDockWidgetPrivate::nonClientAreaMouseEvent(QMouseEvent *event)
+{
+    Q_Q(QDockWidget);
 
-            if (state->ownWidgetItem)
-                delete state->widgetItem;
+    int fw = q->style()->pixelMetric(QStyle::PM_DockWidgetFrameWidth, 0, q);
 
-            q->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
-            updateButtons();
-            resizer->setActive(QWidgetResizeHandler::Resize, true);
-            q->show();
+    QRect geo = q->geometry();
+    QRect titleRect = q->frameGeometry();
+    titleRect.setLeft(geo.left());
+    titleRect.setRight(geo.right());
+    titleRect.setBottom(geo.top() - 1);
+    titleRect.adjust(0, fw, 0, 0);
+
+    switch (event->type()) {
+        case QEvent::NonClientAreaMouseButtonPress:
+            qDebug() << "ncaevent: ncapress";
+
+            if (!titleRect.contains(event->globalPos()))
+                break;
+            if (state != 0)
+                break;
+            initDrag(event->pos(), true);
+            startDrag();
+            break;
+        case QEvent::NonClientAreaMouseMove:
+        	qDebug() << "ncaevent: ncamove";
+            if (state == 0 || !state->dragging)
+                break;
+			if (state->nca) {
+            	endDrag();
+			}
+#ifdef Q_OS_MAC
+			else { // workaround for lack of mouse-grab on Mac
+			    QMainWindowLayout *layout
+			        = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
+			    Q_ASSERT(layout != 0);
+
+	        	q->move(event->globalPos() - state->pressPos);
+	        	if (!(event->modifiers() & Qt::ControlModifier))
+	            	state->pathToGap = layout->hover(state->widgetItem, event->globalPos());
             }
+#endif
+			break;
+        case QEvent::NonClientAreaMouseButtonRelease:
+    	    qDebug() << "ncaevent: ncarelease";
+#ifdef Q_OS_MAC
+			if (state)
+				endDrag();
+#endif
+			break;
+        case QEvent::NonClientAreaMouseButtonDblClick:
+            _q_toggleTopLevel();
+            break;
+        default:
+            break;
     }
+}
 
-    delete state;
-    state = 0;
-#endif // !defined(QT_NO_MAINWINDOW)
+void QDockWidgetPrivate::moveEvent(QMoveEvent *event)
+{
+    Q_Q(QDockWidget);
+
+    event->ignore();
+
+    if (state == 0 || !state->dragging || !state->nca)
+        return;
+
+    // When the native window frame is being dragged, all we get is these mouse
+    // move events.
+
+    QMainWindowLayout *layout
+        = qobject_cast<QMainWindowLayout *>(q->parentWidget()->layout());
+    Q_ASSERT(layout != 0);
+
+    QPoint globalMousePos = event->pos() + state->pressPos;
+    state->pathToGap = layout->hover(state->widgetItem, globalMousePos);
 }
 
 void QDockWidgetPrivate::unplug(const QRect &rect)
 {
     Q_Q(QDockWidget);
     QRect r = rect;
-    r.moveTopLeft(q->mapToGlobal(r.topLeft()));
-    q->hide();
-    q->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool | Qt::X11BypassWindowManagerHint);
-    resizer->setActive(QWidgetResizeHandler::Resize, false);
-    q->setGeometry(r);
-    q->show();
-    updateButtons();
-    emit q->topLevelChanged(q->isWindow());
+    r.moveTopLeft(q->mapToGlobal(QPoint(0, 0)));
+#ifndef Q_WS_X11
+    QDWLayout *layout = qobject_cast<QDWLayout*>(q->layout());
+    r.adjust(0, layout->titleHeight(), 0, 0);
+#endif
+    setWindowState(true, true, r);
 }
 
 void QDockWidgetPrivate::plug(const QRect &rect)
 {
+    setWindowState(false, false, rect);
+}
+
+void QDockWidgetPrivate::setWindowState(bool floating, bool unplug, const QRect &rect)
+{
     Q_Q(QDockWidget);
+
+    bool wasFloating = q->isFloating();
+    bool visible = q->isVisible();
+
     q->hide();
 
-    q->setWindowFlags(Qt::FramelessWindowHint | Qt::Widget);
+    Qt::WindowFlags flags = floating ? Qt::Tool : Qt::Widget;
 
-    updateButtons();
-    resizer->setActive(QWidgetResizeHandler::Resize, false);
+#ifdef Q_WS_X11
+    flags |= Qt::FramelessWindowHint;
+#endif
+    if (unplug)
+        flags |= Qt::X11BypassWindowManagerHint;
+
+    q->setWindowFlags(flags);
+
+    if (!rect.isNull()) {
         q->setGeometry(rect);
-    q->show();
+    }
 
-    emit q->topLevelChanged(false);
-}
+    if (visible)
+        q->show();
 
+    updateButtons();
 
+    if (floating != wasFloating)
+        emit q->topLevelChanged(floating);
 
+#ifdef Q_WS_X11
+    resizer->setActive(QWidgetResizeHandler::Resize, !unplug && floating);
+#endif
+}
 
 /*!
     \class QDockWidget
@@ -823,27 +993,7 @@ QDockWidget::DockWidgetFeatures QDockWidget::features() const
 void QDockWidget::setFloating(bool floating)
 {
     Q_D(QDockWidget);
-    if (floating == isFloating())
-        return;
-
-    const bool visible = isVisible();
-
-    if (!floating && parentWidget() != 0) {
-        QMainWindowLayout *layout
-            = qobject_cast<QMainWindowLayout*>(parentWidget()->layout());
-        if (layout != 0)
-            layout->keepSize(this);
-    }
-
-    setWindowFlags(Qt::FramelessWindowHint | (floating ? Qt::Tool : Qt::Widget));
-
-    d->updateButtons();
-    d->resizer->setActive(QWidgetResizeHandler::Resize, floating);
-
-    if (visible)
-        show();
-
-    emit topLevelChanged(isWindow());
+    d->setWindowState(floating);
 }
 
 /*!
@@ -907,6 +1057,11 @@ void QDockWidget::closeEvent(QCloseEvent *event)
 void QDockWidget::paintEvent(QPaintEvent *event)
 {
     Q_UNUSED(event)
+
+#ifndef Q_WS_X11
+    if (!isFloating()) {
+#endif
+
         QStylePainter p(this);
         // ### Add PixelMetric to change spacers, so style may show border
         // when not floating.
@@ -921,6 +1076,10 @@ void QDockWidget::paintEvent(QPaintEvent *event)
         QStyleOptionDockWidget titleOpt;
         initStyleOption(&titleOpt);
         p.drawControl(QStyle::CE_DockWidgetTitle, titleOpt);
+
+#ifndef Q_WS_X11
+    }
+#endif
 }
 
 /*! \reimp */
@@ -978,6 +1137,15 @@ bool QDockWidget::event(QEvent *event)
     case QEvent::MouseButtonRelease:
         d->mouseReleaseEvent(static_cast<QMouseEvent *>(event));
         return true;
+    case QEvent::NonClientAreaMouseMove:
+    case QEvent::NonClientAreaMouseButtonPress:
+    case QEvent::NonClientAreaMouseButtonRelease:
+    case QEvent::NonClientAreaMouseButtonDblClick:
+        d->nonClientAreaMouseEvent(static_cast<QMouseEvent*>(event));
+        return true;
+    case QEvent::Move:
+        d->moveEvent(static_cast<QMoveEvent*>(event));
+        return true;
     default:
         break;
     }
--- src/gui/widgets/qdockwidget_p.h
+++ src/gui/widgets/qdockwidget_p.h
@@ -48,6 +48,7 @@ class QDockWidgetPrivate : public QWidgetPrivate
         QWidgetItem *widgetItem;
         QList<int> pathToGap;
         bool ownWidgetItem;
+        bool nca;
     };
 
 public:
@@ -56,7 +57,7 @@ public:
           features(QDockWidget::DockWidgetClosable
                    | QDockWidget::DockWidgetMovable
                    | QDockWidget::DockWidgetFloatable),
-          allowedAreas(Qt::AllDockWidgetAreas), resizer(0)
+          allowedAreas(Qt::AllDockWidgetAreas)
     { }
 
     void init();
@@ -69,7 +70,10 @@ public:
     QDockWidget::DockWidgetFeatures features;
     Qt::DockWidgetAreas allowedAreas;
 
+#ifdef Q_WS_X11
     QWidgetResizeHandler *resizer;
+#endif
+
 #ifndef QT_NO_ACTION
     QAction *toggleViewAction;
 #endif
@@ -80,6 +84,12 @@ public:
     void mouseDoubleClickEvent(QMouseEvent *event);
     void mouseMoveEvent(QMouseEvent *event);
     void mouseReleaseEvent(QMouseEvent *event);
+    void setWindowState(bool floating, bool unplug = false, const QRect &rect = QRect());
+    void nonClientAreaMouseEvent(QMouseEvent *event);
+    void initDrag(const QPoint &pos, bool nca);
+    void startDrag();
+    void endDrag();
+    void moveEvent(QMoveEvent *event);
 
     void unplug(const QRect &rect);
     void plug(const QRect &rect);
--- src/gui/widgets/qdockwidgetlayout.cpp
+++ src/gui/widgets/qdockwidgetlayout.cpp
@@ -167,8 +167,17 @@ bool QDockAreaLayoutItem::skip() const
 
 QSize QDockAreaLayoutItem::minimumSize() const
 {
-    if (widgetItem != 0)
+    if (widgetItem != 0) {
+        QWidget *w = widgetItem->widget();
+        if (QDWLayout *layout = qobject_cast<QDWLayout*>(w->layout())) {
+            // the dockwidget may be floating, but we want to know what size hints
+            // it will return when docked.
+            return qSmartMinSize(layout->dockedSizeHint(), layout->dockedMinimumSize(),
+                                    w->minimumSize(), w->maximumSize(),
+                                    w->sizePolicy());
+        }
         return qSmartMinSize(widgetItem);
+    }
     if (subinfo != 0)
         return subinfo->minimumSize();
     return QSize(0, 0);
@@ -176,8 +185,16 @@ QSize QDockAreaLayoutItem::minimumSize() const
 
 QSize QDockAreaLayoutItem::maximumSize() const
 {
-    if (widgetItem != 0)
+    if (widgetItem != 0) {
+        QWidget *w = widgetItem->widget();
+        if (QDWLayout *layout = qobject_cast<QDWLayout*>(w->layout())) {
+            // the dockwidget may be floating, but we want to know what size hints
+            // it will return when docked.
+            return qSmartMaxSize(layout->dockedSizeHint(), w->minimumSize(),
+                                    w->maximumSize(), w->sizePolicy());
+        }
         return qSmartMaxSize(widgetItem);
+    }
     if (subinfo != 0)
         return subinfo->maximumSize();
     return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
@@ -1045,6 +1062,19 @@ void QDockAreaLayoutInfo::setCurrentTabId(quintptr id)
 
 #endif // QT_NO_TABBAR
 
+static QRect dockedGeometry(QWidget *widget)
+{
+    int titleHeight = 0;
+#ifndef Q_WS_X11
+    QDWLayout *layout = qobject_cast<QDWLayout*>(widget->layout());
+    if (layout != 0)
+        titleHeight = layout->titleHeight();
+#endif
+    QRect result = widget->geometry();
+    result.adjust(0, -titleHeight, 0, 0);
+    return result;
+}
+
 bool QDockAreaLayoutInfo::insertGap(QList<int> path, QWidgetItem *dockWidgetItem)
 {
     Q_ASSERT(!path.isEmpty());
@@ -1070,7 +1100,7 @@ bool QDockAreaLayoutInfo::insertGap(QList<int> path, QWidgetItem *dockWidgetItem
 
             QDockAreaLayoutInfo *subinfo = item.subinfo;
             QWidgetItem *widgetItem = item.widgetItem;
-            QRect r = subinfo == 0 ? widgetItem->geometry() : subinfo->rect;
+            QRect r = subinfo == 0 ? dockedGeometry(widgetItem->widget()) : subinfo->rect;
 
             Qt::Orientation opposite = o == Qt::Horizontal ? Qt::Vertical : Qt::Horizontal;
 #ifdef QT_NO_TABBAR
@@ -1132,7 +1162,8 @@ bool QDockAreaLayoutInfo::insertGap(QList<int> path, QWidgetItem *dockWidgetItem
             gap_size = space;
             sep_size = 0;
         } else {
-            gap_size = pick(o, dockWidgetItem->geometry().size());
+            QRect r = dockedGeometry(dockWidgetItem->widget());
+            gap_size = pick(o, r.size());
             if (prev != -1 && !item_list.at(prev).gap)
                 sep_size += sep;
             if (next != -1 && !item_list.at(next).gap)
--- src/gui/widgets/qdockwidgetlayout_p.h
+++ src/gui/widgets/qdockwidgetlayout_p.h
@@ -28,7 +28,8 @@
 #include "QtCore/qlist.h"
 #include "QtCore/qrect.h"
 #include "QtCore/qpair.h"
-#include "QtGui/qsizepolicy.h"
+#include "QtCore/qlist.h"
+#include "QtGui/qlayout.h"
 
 #ifndef QT_NO_DOCKWIDGET
 
@@ -277,6 +278,37 @@ public:
     QSet<QTabBar*> usedTabBars() const;
 };
 
+// this is the layout used by QDockWidget for its contents
+class QDWLayout : public QLayout
+{
+public:
+    QDWLayout(QWidget *parent = 0);
+    void addItem(QLayoutItem *item);
+    QLayoutItem *itemAt(int index) const;
+    QLayoutItem *takeAt(int index);
+    int count() const;
+
+    QSize dockedMinimumSize() const;
+    QSize minimumSize() const;
+    QSize dockedSizeHint() const;
+    QSize sizeHint() const;
+
+    void setGeometry(const QRect &r);
+
+    enum Role { Content, CloseButton, FloatButton, RoleCount };
+    QWidget *widget(Role r);
+    void setWidget(Role r, QWidget *w);
+
+    QRect titleArea() const { return _titleArea; }
+
+    int minimumTitleWidth() const;
+    int titleHeight() const;
+
+private:
+    QVector<QLayoutItem*> item_list;
+    QRect _titleArea;
+};
+
 // void dump(QDebug debug, const QDockWidgetLayout &layout);
 
 #endif // QT_NO_MAINWINDOW
--- src/gui/widgets/qmainwindowlayout.cpp
+++ src/gui/widgets/qmainwindowlayout.cpp
@@ -1545,6 +1545,10 @@ void QMainWindowLayout::plug(QWidgetItem *dockWidgetItem, const QList<int> &path
         pluggingWidget = dockWidget;
         QRect globalRect = currentGapRect;
         globalRect.moveTopLeft(parentWidget()->mapToGlobal(globalRect.topLeft()));
+#ifndef Q_WS_X11
+        QDWLayout *layout = qobject_cast<QDWLayout*>(dockWidgetItem->widget()->layout());
+        globalRect.adjust(0, layout->titleHeight(), 0, 0);
+#endif
         widgetAnimator->animate(dockWidget, globalRect, animationEnabled);
     } else {
         dockWidget->d_func()->plug(currentGapRect);
