/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial Usage
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qworkspace.h"
#ifndef QT_NO_WORKSPACE
#include "qapplication.h"
#include "qbitmap.h"
#include "qcursor.h"
#include "qdatetime.h"
#include "qdesktopwidget.h"
#include "qevent.h"
#include "qhash.h"
#include "qicon.h"
#include "qimage.h"
#include "qlabel.h"
#include "qlayout.h"
#include "qmenubar.h"
#include "qmenu.h"
#include "qpainter.h"
#include "qpointer.h"
#include "qscrollbar.h"
#include "qstyle.h"
#include "qstyleoption.h"
#include "qtooltip.h"
#include "qdebug.h"
#include <private/qwidget_p.h>
#include <private/qwidgetresizehandler_p.h>
#include <private/qlayoutengine_p.h>

QT_BEGIN_NAMESPACE

class QWorkspaceTitleBarPrivate;


/**************************************************************
* QMDIControl
*
* Used for displaying MDI controls in a maximized MDI window
*
*/
class QMDIControl : public QWidget
{
    Q_OBJECT
signals:
    void _q_minimize();
    void _q_restore();
    void _q_close();

public:
    QMDIControl(QWidget *widget);

private:
    QSize sizeHint() const;
    void paintEvent(QPaintEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void leaveEvent(QEvent *event);
    bool event(QEvent *event);
    void initStyleOption(QStyleOptionComplex *option) const;
    QStyle::SubControl activeControl; //control locked by pressing and holding the mouse
    QStyle::SubControl hoverControl; //previously active hover control, used for tracking repaints
};

bool QMDIControl::event(QEvent *event)
{
    if (event->type() == QEvent::ToolTip) {
        QStyleOptionComplex opt;
        initStyleOption(&opt);
#ifndef QT_NO_TOOLTIP
        QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
        QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
                                                                 helpEvent->pos(), this);
        if (ctrl == QStyle::SC_MdiCloseButton)
            QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Close"), this);
        else if (ctrl == QStyle::SC_MdiMinButton)
            QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Minimize"), this);
        else if (ctrl == QStyle::SC_MdiNormalButton)
            QToolTip::showText(helpEvent->globalPos(), QWorkspace::tr("Restore Down"), this);
        else
            QToolTip::hideText();
#endif // QT_NO_TOOLTIP
    }
    return QWidget::event(event);
}

void QMDIControl::initStyleOption(QStyleOptionComplex *option) const
{
    option->initFrom(this);
    option->subControls = QStyle::SC_All;
    option->activeSubControls = QStyle::SC_None;
}

QMDIControl::QMDIControl(QWidget *widget)
    : QWidget(widget), activeControl(QStyle::SC_None),
      hoverControl(QStyle::SC_None)
{
    setObjectName(QLatin1String("qt_maxcontrols"));
    setFocusPolicy(Qt::NoFocus);
    setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
    setMouseTracking(true);
}

QSize QMDIControl::sizeHint() const
{
    ensurePolished();
    QStyleOptionComplex opt;
    initStyleOption(&opt);
    QSize size(48, 16);
    return style()->sizeFromContents(QStyle::CT_MdiControls, &opt, size, this);
}

void QMDIControl::mousePressEvent(QMouseEvent *event)
{
    if (event->button() != Qt::LeftButton) {
        event->ignore();
        return;
    }
    QStyleOptionComplex opt;
    initStyleOption(&opt);
    QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
                                                             event->pos(), this);
    activeControl = ctrl;
    update();
}

void QMDIControl::mouseReleaseEvent(QMouseEvent *event)
{
    if (event->button() != Qt::LeftButton) {
        event->ignore();
        return;
    }
    QStyleOptionTitleBar opt;
    initStyleOption(&opt);
    QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
                                                                    event->pos(), this);
    if (under_mouse == activeControl) {
        switch (activeControl) {
        case QStyle::SC_MdiCloseButton:
            emit _q_close();
            break;
        case QStyle::SC_MdiNormalButton:
            emit _q_restore();
            break;
        case QStyle::SC_MdiMinButton:
            emit _q_minimize();
            break;
        default:
            break;
        }
    }
    activeControl = QStyle::SC_None;
    update();
}

void QMDIControl::leaveEvent(QEvent * /*event*/)
{
    hoverControl = QStyle::SC_None;
    update();
}

void QMDIControl::mouseMoveEvent(QMouseEvent *event)
{
    QStyleOptionTitleBar opt;
    initStyleOption(&opt);
    QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_MdiControls, &opt,
                                                                    event->pos(), this);
    //test if hover state changes
    if (hoverControl != under_mouse) {
        hoverControl = under_mouse;
        update();
    }
}

void QMDIControl::paintEvent(QPaintEvent *)
{
    QPainter p(this);
    QStyleOptionComplex opt;
    initStyleOption(&opt);
    if (activeControl == hoverControl) {
        opt.activeSubControls = activeControl;
        opt.state |= QStyle::State_Sunken;
    } else if (hoverControl != QStyle::SC_None && (activeControl == QStyle::SC_None)) {
        opt.activeSubControls = hoverControl;
        opt.state |= QStyle::State_MouseOver;
    }
    style()->drawComplexControl(QStyle::CC_MdiControls, &opt, &p, this);
}

class QWorkspaceTitleBar : public QWidget
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(QWorkspaceTitleBar)
    Q_PROPERTY(bool autoRaise READ autoRaise WRITE setAutoRaise)
    Q_PROPERTY(bool movable READ isMovable WRITE setMovable)

public:
    QWorkspaceTitleBar (QWidget *w, QWidget *parent, Qt::WindowFlags f = 0);
    ~QWorkspaceTitleBar();

    bool isActive() const;
    bool usesActiveColor() const;

    bool isMovable() const;
    void setMovable(bool);

    bool autoRaise() const;
    void setAutoRaise(bool);

    QWidget *window() const;
    bool isTool() const;

    QSize sizeHint() const;
    void initStyleOption(QStyleOptionTitleBar *option) const;

public slots:
    void setActive(bool);

signals:
    void doActivate();
    void doNormal();
    void doClose();
    void doMaximize();
    void doMinimize();
    void doShade();
    void showOperationMenu();
    void popupOperationMenu(const QPoint&);
    void doubleClicked();

protected:
    bool event(QEvent *);
#ifndef QT_NO_CONTEXTMENU
    void contextMenuEvent(QContextMenuEvent *);
#endif
    void mousePressEvent(QMouseEvent *);
    void mouseDoubleClickEvent(QMouseEvent *);
    void mouseReleaseEvent(QMouseEvent *);
    void mouseMoveEvent(QMouseEvent *);
    void enterEvent(QEvent *e);
    void leaveEvent(QEvent *e);
    void paintEvent(QPaintEvent *p);

private:
    Q_DISABLE_COPY(QWorkspaceTitleBar)
};


class QWorkspaceTitleBarPrivate : public QWidgetPrivate
{
    Q_DECLARE_PUBLIC(QWorkspaceTitleBar)
public:
    QWorkspaceTitleBarPrivate()
        :
        lastControl(QStyle::SC_None),
#ifndef QT_NO_TOOLTIP
        toolTip(0),
#endif
        act(0), window(0), movable(1), pressed(0), autoraise(0), moving(0)
    {
    }

    Qt::WindowFlags flags;
    QStyle::SubControl buttonDown;
    QStyle::SubControl lastControl;
    QPoint moveOffset;
#ifndef QT_NO_TOOLTIP
    QToolTip *toolTip;
#endif
    bool act                    :1;
    QPointer<QWidget> window;
    bool movable            :1;
    bool pressed            :1;
    bool autoraise          :1;
    bool moving : 1;

    int titleBarState() const;
    void readColors();
};

inline int QWorkspaceTitleBarPrivate::titleBarState() const
{
    Q_Q(const QWorkspaceTitleBar);
    uint state = window ? window->windowState() : static_cast<Qt::WindowStates>(Qt::WindowNoState);
    state |= uint((act && q->isActiveWindow()) ? QStyle::State_Active : QStyle::State_None);
    return (int)state;
}

void QWorkspaceTitleBar::initStyleOption(QStyleOptionTitleBar *option) const
{
    Q_D(const QWorkspaceTitleBar);
    option->initFrom(this);
    //################
    if (d->window && (d->flags & Qt::WindowTitleHint)) {
        option->text = d->window->windowTitle();
        QIcon icon = d->window->windowIcon();
        QSize s = icon.actualSize(QSize(64, 64));
        option->icon = icon.pixmap(s);
    }
    option->subControls = QStyle::SC_All;
    option->activeSubControls = QStyle::SC_None;
    option->titleBarState = d->titleBarState();
    option->titleBarFlags = d->flags;
    option->state &= ~QStyle::State_MouseOver;
}

QWorkspaceTitleBar::QWorkspaceTitleBar(QWidget *w, QWidget *parent, Qt::WindowFlags f)
    : QWidget(*new QWorkspaceTitleBarPrivate, parent, Qt::FramelessWindowHint)
{
    Q_D(QWorkspaceTitleBar);
    if (f == 0 && w)
        f = w->windowFlags();
    d->flags = f;
    d->window = w;
    d->buttonDown = QStyle::SC_None;
    d->act = 0;
    if (w) {
        if (w->maximumSize() != QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX))
            d->flags &= ~Qt::WindowMaximizeButtonHint;
        setWindowTitle(w->windowTitle());
    }

    d->readColors();
    setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed));
    setMouseTracking(true);
    setAutoRaise(style()->styleHint(QStyle::SH_TitleBar_AutoRaise, 0, this));
}

QWorkspaceTitleBar::~QWorkspaceTitleBar()
{
}


#ifdef Q_WS_WIN
static inline QRgb colorref2qrgb(COLORREF col)
{
    return qRgb(GetRValue(col),GetGValue(col),GetBValue(col));
}
#endif

void QWorkspaceTitleBarPrivate::readColors()
{
    Q_Q(QWorkspaceTitleBar);
    QPalette pal = q->palette();

    bool colorsInitialized = false;

#ifdef Q_WS_WIN // ask system properties on windows
#ifndef SPI_GETGRADIENTCAPTIONS
#define SPI_GETGRADIENTCAPTIONS 0x1008
#endif
#ifndef COLOR_GRADIENTACTIVECAPTION
#define COLOR_GRADIENTACTIVECAPTION 27
#endif
#ifndef COLOR_GRADIENTINACTIVECAPTION
#define COLOR_GRADIENTINACTIVECAPTION 28
#endif
    if (QApplication::desktopSettingsAware()) {
        pal.setColor(QPalette::Active, QPalette::Highlight, colorref2qrgb(GetSysColor(COLOR_ACTIVECAPTION)));
        pal.setColor(QPalette::Inactive, QPalette::Highlight, colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTION)));
        pal.setColor(QPalette::Active, QPalette::HighlightedText, colorref2qrgb(GetSysColor(COLOR_CAPTIONTEXT)));
        pal.setColor(QPalette::Inactive, QPalette::HighlightedText, colorref2qrgb(GetSysColor(COLOR_INACTIVECAPTIONTEXT)));

        colorsInitialized = true;
        BOOL gradient = false;
        SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);

        if (gradient) {
            pal.setColor(QPalette::Active, QPalette::Base, colorref2qrgb(GetSysColor(COLOR_GRADIENTACTIVECAPTION)));
            pal.setColor(QPalette::Inactive, QPalette::Base, colorref2qrgb(GetSysColor(COLOR_GRADIENTINACTIVECAPTION)));
        } else {
            pal.setColor(QPalette::Active, QPalette::Base, pal.color(QPalette::Active, QPalette::Highlight));
            pal.setColor(QPalette::Inactive, QPalette::Base, pal.color(QPalette::Inactive, QPalette::Highlight));
        }
    }
#endif // Q_WS_WIN
    if (!colorsInitialized) {
        pal.setColor(QPalette::Active, QPalette::Highlight,
                      pal.color(QPalette::Active, QPalette::Highlight));
        pal.setColor(QPalette::Active, QPalette::Base,
                      pal.color(QPalette::Active, QPalette::Highlight));
        pal.setColor(QPalette::Inactive, QPalette::Highlight,
                      pal.color(QPalette::Inactive, QPalette::Dark));
        pal.setColor(QPalette::Inactive, QPalette::Base,
                      pal.color(QPalette::Inactive, QPalette::Dark));
        pal.setColor(QPalette::Inactive, QPalette::HighlightedText,
                      pal.color(QPalette::Inactive, QPalette::Window));
    }

    q->setPalette(pal);
    q->setActive(act);
}

void QWorkspaceTitleBar::mousePressEvent(QMouseEvent *e)
{
    Q_D(QWorkspaceTitleBar);
    if (!d->act)
        emit doActivate();
    if (e->button() == Qt::LeftButton) {
        if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0)
            && !rect().adjusted(5, 5, -5, 0).contains(e->pos())) {
            // propagate border events to the QWidgetResizeHandler
            e->ignore();
            return;
        }

        d->pressed = true;
        QStyleOptionTitleBar opt;
        initStyleOption(&opt);
        QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
                                                                 e->pos(), this);
        switch (ctrl) {
        case QStyle::SC_TitleBarSysMenu:
            if (d->flags & Qt::WindowSystemMenuHint) {
                d->buttonDown = QStyle::SC_None;
                static QTime *t = 0;
                static QWorkspaceTitleBar *tc = 0;
                if (!t)
                    t = new QTime;
                if (tc != this || t->elapsed() > QApplication::doubleClickInterval()) {
                    emit showOperationMenu();
                    t->start();
                    tc = this;
                } else {
                    tc = 0;
                    emit doClose();
                    return;
                }
            }
            break;

        case QStyle::SC_TitleBarShadeButton:
        case QStyle::SC_TitleBarUnshadeButton:
            if (d->flags & Qt::WindowShadeButtonHint)
                d->buttonDown = ctrl;
            break;

        case QStyle::SC_TitleBarNormalButton:
                d->buttonDown = ctrl;
            break;

        case QStyle::SC_TitleBarMinButton:
            if (d->flags & Qt::WindowMinimizeButtonHint)
                d->buttonDown = ctrl;
            break;

        case QStyle::SC_TitleBarMaxButton:
            if (d->flags & Qt::WindowMaximizeButtonHint)
                d->buttonDown = ctrl;
            break;

        case QStyle::SC_TitleBarCloseButton:
            if (d->flags & Qt::WindowSystemMenuHint)
                d->buttonDown = ctrl;
            break;

        case QStyle::SC_TitleBarLabel:
            d->buttonDown = ctrl;
            d->moveOffset = mapToParent(e->pos());
            break;

        default:
            break;
        }
        update();
    } else {
        d->pressed = false;
    }
}

#ifndef QT_NO_CONTEXTMENU
void QWorkspaceTitleBar::contextMenuEvent(QContextMenuEvent *e)
{
    QStyleOptionTitleBar opt;
    initStyleOption(&opt);
    QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(),
                                                             this);
    if(ctrl == QStyle::SC_TitleBarLabel || ctrl == QStyle::SC_TitleBarSysMenu) {
        e->accept();
        emit popupOperationMenu(e->globalPos());
    } else {
        e->ignore();
    }
}
#endif // QT_NO_CONTEXTMENU

void QWorkspaceTitleBar::mouseReleaseEvent(QMouseEvent *e)
{
    Q_D(QWorkspaceTitleBar);
    if (!d->window) {
        // could have been deleted as part of a double click event on the sysmenu
        return;
    }
    if (e->button() == Qt::LeftButton && d->pressed) {
        if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0)
            && !rect().adjusted(5, 5, -5, 0).contains(e->pos())) {
            // propagate border events to the QWidgetResizeHandler
            e->ignore();
            d->buttonDown = QStyle::SC_None;
            d->pressed = false;
            return;
        }
        e->accept();
        QStyleOptionTitleBar opt;
        initStyleOption(&opt);
        QStyle::SubControl ctrl = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
                                                                 e->pos(), this);

        if (d->pressed) {
            update();
            d->pressed = false;
            d->moving = false;
        }
        if (ctrl == d->buttonDown) {
            d->buttonDown = QStyle::SC_None;
            switch(ctrl) {
            case QStyle::SC_TitleBarShadeButton:
            case QStyle::SC_TitleBarUnshadeButton:
                if(d->flags & Qt::WindowShadeButtonHint)
                    emit doShade();
                break;

            case QStyle::SC_TitleBarNormalButton:
                if(d->flags & Qt::WindowMinMaxButtonsHint)
                    emit doNormal();
                break;

            case QStyle::SC_TitleBarMinButton:
                if(d->flags & Qt::WindowMinimizeButtonHint) {
                    if (d->window && d->window->isMinimized())
                        emit doNormal();
                    else
                        emit doMinimize();
                }
                break;

            case QStyle::SC_TitleBarMaxButton:
                if(d->flags & Qt::WindowMaximizeButtonHint) {
                    if(d->window && d->window->isMaximized())
                        emit doNormal();
                    else
                        emit doMaximize();
                }
                break;

            case QStyle::SC_TitleBarCloseButton:
                if(d->flags & Qt::WindowSystemMenuHint) {
                    d->buttonDown = QStyle::SC_None;
                    emit doClose();
                    return;
                }
                break;

            default:
                break;
            }
        }
    } else {
        e->ignore();
    }
}

void QWorkspaceTitleBar::mouseMoveEvent(QMouseEvent *e)
{
    Q_D(QWorkspaceTitleBar);
    e->ignore();
    if ((e->buttons() & Qt::LeftButton) && style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, 0)
        && !rect().adjusted(5, 5, -5, 0).contains(e->pos()) && !d->pressed) {
        // propagate border events to the QWidgetResizeHandler
        return;
    }

    QStyleOptionTitleBar opt;
    initStyleOption(&opt);
    QStyle::SubControl under_mouse = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
                                                                    e->pos(), this);
    if(under_mouse != d->lastControl) {
        d->lastControl = under_mouse;
        update();
    }

    switch (d->buttonDown) {
    case QStyle::SC_None:
        break;
    case QStyle::SC_TitleBarSysMenu:
        break;
    case QStyle::SC_TitleBarLabel:
        if (d->buttonDown == QStyle::SC_TitleBarLabel && d->movable && d->pressed) {
            if (d->moving || (d->moveOffset - mapToParent(e->pos())).manhattanLength() >= 4) {
                d->moving = true;
                QPoint p = mapFromGlobal(e->globalPos());

                QWidget *parent = d->window ? d->window->parentWidget() : 0;
                if(parent && parent->inherits("QWorkspaceChild")) {
                    QWidget *workspace = parent->parentWidget();
                    p = workspace->mapFromGlobal(e->globalPos());
                    if (!workspace->rect().contains(p)) {
                        if (p.x() < 0)
                            p.rx() = 0;
                        if (p.y() < 0)
                            p.ry() = 0;
                        if (p.x() > workspace->width())
                            p.rx() = workspace->width();
                        if (p.y() > workspace->height())
                            p.ry() = workspace->height();
                    }
                }

                QPoint pp = p - d->moveOffset;
                if (!parentWidget()->isMaximized())
                    parentWidget()->move(pp);
            }
        }
        e->accept();
        break;
    default:
        break;
    }
}

bool QWorkspaceTitleBar::isTool() const
{
    Q_D(const QWorkspaceTitleBar);
    return (d->flags & Qt::WindowType_Mask) == Qt::Tool;
}

// from qwidget.cpp
extern QString qt_setWindowTitle_helperHelper(const QString &, const QWidget*);

void QWorkspaceTitleBar::paintEvent(QPaintEvent *)
{
    Q_D(QWorkspaceTitleBar);
    QStyleOptionTitleBar opt;
    initStyleOption(&opt);
    opt.subControls = QStyle::SC_TitleBarLabel;
    opt.activeSubControls = d->buttonDown;

    if (d->window && (d->flags & Qt::WindowTitleHint)) {
        QString title = qt_setWindowTitle_helperHelper(opt.text, d->window);
        int maxw = style()->subControlRect(QStyle::CC_TitleBar, &opt, QStyle::SC_TitleBarLabel,
                                       this).width();
        opt.text = fontMetrics().elidedText(title, Qt::ElideRight, maxw);
    }

    if (d->flags & Qt::WindowSystemMenuHint) {
        opt.subControls |= QStyle::SC_TitleBarSysMenu | QStyle::SC_TitleBarCloseButton;
        if (d->window && (d->flags & Qt::WindowShadeButtonHint)) {
            if (d->window->isMinimized())
                opt.subControls |= QStyle::SC_TitleBarUnshadeButton;
            else
                opt.subControls |= QStyle::SC_TitleBarShadeButton;
        }
        if (d->window && (d->flags & Qt::WindowMinMaxButtonsHint)) {
            if(d->window && d->window->isMinimized())
                opt.subControls |= QStyle::SC_TitleBarNormalButton;
            else
                opt.subControls |= QStyle::SC_TitleBarMinButton;
        }
        if (d->window && (d->flags & Qt::WindowMaximizeButtonHint) && !d->window->isMaximized())
            opt.subControls |= QStyle::SC_TitleBarMaxButton;
    }

    QStyle::SubControl under_mouse = QStyle::SC_None;
    under_mouse = style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt,
                                                     mapFromGlobal(QCursor::pos()), this);
    if ((d->buttonDown == under_mouse) && d->pressed) {
        opt.state |= QStyle::State_Sunken;
    } else if( autoRaise() && under_mouse != QStyle::SC_None && !d->pressed) {
        opt.activeSubControls = under_mouse;
        opt.state |= QStyle::State_MouseOver;
    }
    opt.palette.setCurrentColorGroup(usesActiveColor() ? QPalette::Active : QPalette::Inactive);

    QPainter p(this);
    style()->drawComplexControl(QStyle::CC_TitleBar, &opt, &p, this);
}

void QWorkspaceTitleBar::mouseDoubleClickEvent(QMouseEvent *e)
{
    Q_D(QWorkspaceTitleBar);
    if (e->button() != Qt::LeftButton) {
        e->ignore();
        return;
    }
    e->accept();
    QStyleOptionTitleBar opt;
    initStyleOption(&opt);
    switch (style()->hitTestComplexControl(QStyle::CC_TitleBar, &opt, e->pos(), this)) {
    case QStyle::SC_TitleBarLabel:
        emit doubleClicked();
        break;

    case QStyle::SC_TitleBarSysMenu:
        if (d->flags & Qt::WindowSystemMenuHint)
            emit doClose();
        break;

    default:
        break;
    }
}

void QWorkspaceTitleBar::leaveEvent(QEvent *)
{
    Q_D(QWorkspaceTitleBar);
    d->lastControl = QStyle::SC_None;
    if(autoRaise() && !d->pressed)
        update();
}

void QWorkspaceTitleBar::enterEvent(QEvent *)
{
    Q_D(QWorkspaceTitleBar);
    if(autoRaise() && !d->pressed)
        update();
    QEvent e(QEvent::Leave);
    QApplication::sendEvent(parentWidget(), &e);
}

void QWorkspaceTitleBar::setActive(bool active)
{
    Q_D(QWorkspaceTitleBar);
    if (d->act == active)
        return ;

    d->act = active;
    update();
}

bool QWorkspaceTitleBar::isActive() const
{
    Q_D(const QWorkspaceTitleBar);
    return d->act;
}

bool QWorkspaceTitleBar::usesActiveColor() const
{
    return (isActive() && isActiveWindow()) ||
        (!window() && QWidget::window()->isActiveWindow());
}

QWidget *QWorkspaceTitleBar::window() const
{
    Q_D(const QWorkspaceTitleBar);
    return d->window;
}

bool QWorkspaceTitleBar::event(QEvent *e)
{
    Q_D(QWorkspaceTitleBar);
    if (e->type() == QEvent::ApplicationPaletteChange) {
        d->readColors();
    } else if (e->type() == QEvent::WindowActivate
               || e->type() == QEvent::WindowDeactivate) {
        if (d->act)
            update();
    }
    return QWidget::event(e);
}

void QWorkspaceTitleBar::setMovable(bool b)
{
    Q_D(QWorkspaceTitleBar);
    d->movable = b;
}

bool QWorkspaceTitleBar::isMovable() const
{
    Q_D(const QWorkspaceTitleBar);
    return d->movable;
}

void QWorkspaceTitleBar::setAutoRaise(bool b)
{
    Q_D(QWorkspaceTitleBar);
    d->autoraise = b;
}

bool QWorkspaceTitleBar::autoRaise() const
{
    Q_D(const QWorkspaceTitleBar);
    return d->autoraise;
}

QSize QWorkspaceTitleBar::sizeHint() const
{
    ensurePolished();
    QStyleOptionTitleBar opt;
    initStyleOption(&opt);
    QRect menur = style()->subControlRect(QStyle::CC_TitleBar, &opt,
                                          QStyle::SC_TitleBarSysMenu, this);
    return QSize(menur.width(), style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt, this));
}

/*!
    \class QWorkspace
    \obsolete
    \brief The QWorkspace widget provides a workspace window that can be
    used in an MDI application.

    This class is deprecated. Use QMdiArea instead.

    Multiple Document Interface (MDI) applications are typically
    composed of a main window containing a menu bar, a toolbar, and
    a central QWorkspace widget. The workspace itself is used to display
    a number of child windows, each of which is a widget.

    The workspace itself is an ordinary Qt widget. It has a standard
    constructor that takes a parent widget.
    Workspaces can be placed in any layout, but are typically given
    as the central widget in a QMainWindow:

    \snippet doc/src/snippets/code/src_gui_widgets_qworkspace.cpp 0

    Child windows (MDI windows) are standard Qt widgets that are
    inserted into the workspace with addWindow(). As with top-level
    widgets, you can call functions such as show(), hide(),
    showMaximized(), and setWindowTitle() on a child window to change
    its appearance within the workspace. You can also provide widget
    flags to determine the layout of the decoration or the behavior of
    the widget itself.

    To change or retrieve the geometry of a child window, you must
    operate on its parentWidget(). The parentWidget() provides
    access to the decorated frame that contains the child window
    widget. When a child window is maximised, its decorated frame
    is hidden. If the top-level widget contains a menu bar, it will display
    the maximised window's operations menu to the left of the menu
    entries, and the window's controls to the right.

    A child window becomes active when it gets the keyboard focus,
    or when setFocus() is called. The user can activate a window by moving
    focus in the usual ways, for example by clicking a window or by pressing
    Tab. The workspace emits a signal windowActivated() when the active
    window changes, and the function activeWindow() returns a pointer to the
    active child window, or 0 if no window is active.

    The convenience function windowList() returns a list of all child
    windows. This information could be used in a popup menu
    containing a list of windows, for example. This feature is also
    available as part of the \l{Window Menu} Solution.

    QWorkspace provides two built-in layout strategies for child
    windows: cascade() and tile(). Both are slots so you can easily
    connect menu entries to them.

    \table
    \row \o \inlineimage mdi-cascade.png
         \o \inlineimage mdi-tile.png
    \endtable

    If you want your users to be able to work with child windows
    larger than the visible workspace area, set the scrollBarsEnabled
    property to true.

    \sa QDockWidget, {MDI Example}
*/


class QWorkspaceChild : public QWidget
{
    Q_OBJECT

    friend class QWorkspacePrivate;
    friend class QWorkspace;
    friend class QWorkspaceTitleBar;

public:
    QWorkspaceChild(QWidget* window, QWorkspace* parent=0, Qt::WindowFlags flags = 0);
    ~QWorkspaceChild();

    void setActive(bool);
    bool isActive() const;

    void adjustToFullscreen();

    QWidget* windowWidget() const;
    QWidget* iconWidget() const;

    void doResize();
    void doMove();

    QSize sizeHint() const;
    QSize minimumSizeHint() const;

    QSize baseSize() const;

    int frameWidth() const;

    void show();

    bool isWindowOrIconVisible() const;

signals:
    void showOperationMenu();
    void popupOperationMenu(const QPoint&);

public slots:
    void activate();
    void showMinimized();
    void showMaximized();
    void showNormal();
    void showShaded();
    void internalRaise();
    void titleBarDoubleClicked();

protected:
    void enterEvent(QEvent *);
    void leaveEvent(QEvent *);
    void childEvent(QChildEvent*);
    void resizeEvent(QResizeEvent *);
    void moveEvent(QMoveEvent *);
    bool eventFilter(QObject *, QEvent *);

    void paintEvent(QPaintEvent *);
    void changeEvent(QEvent *);

private:
    void updateMask();

    Q_DISABLE_COPY(QWorkspaceChild)

    QWidget *childWidget;
    QWidgetResizeHandler *widgetResizeHandler;
    QWorkspaceTitleBar *titlebar;
    QPointer<QWorkspaceTitleBar> iconw;
    QSize windowSize;
    QSize shadeRestore;
    QSize shadeRestoreMin;
    bool act                  :1;
    bool shademode            :1;
};

int QWorkspaceChild::frameWidth() const
{
    return contentsRect().left();
}



class QWorkspacePrivate : public QWidgetPrivate {
    Q_DECLARE_PUBLIC(QWorkspace)
public:
    QWorkspaceChild* active;
    QList<QWorkspaceChild *> windows;
    QList<QWorkspaceChild *> focus;
    QList<QWidget *> icons;
    QWorkspaceChild* maxWindow;
    QRect maxRestore;
    QPointer<QMDIControl> maxcontrols;
    QPointer<QMenuBar> maxmenubar;
    QHash<int, const char*> shortcutMap;

    int px;
    int py;
    QWidget *becomeActive;
    QPointer<QLabel> maxtools;
    QString topTitle;

    QMenu *popup, *toolPopup;
    enum WSActs { RestoreAct, MoveAct, ResizeAct, MinimizeAct, MaximizeAct, CloseAct, StaysOnTopAct, ShadeAct, NCountAct };
    QAction *actions[NCountAct];

    QScrollBar *vbar, *hbar;
    QWidget *corner;
    int yoffset, xoffset;
    QBrush background;

    void init();
    void insertIcon(QWidget* w);
    void removeIcon(QWidget* w);
    void place(QWidget*);

    QWorkspaceChild* findChild(QWidget* w);
    void showMaximizeControls();
    void hideMaximizeControls();
    void activateWindow(QWidget* w, bool change_focus = true);
    void hideChild(QWorkspaceChild *c);
    void showWindow(QWidget* w);
    void maximizeWindow(QWidget* w);
    void minimizeWindow(QWidget* w);
    void normalizeWindow(QWidget* w);

    QRect updateWorkspace();

private:
    void _q_normalizeActiveWindow();
    void _q_minimizeActiveWindow();
    void _q_showOperationMenu();
    void _q_popupOperationMenu(const QPoint&);
    void _q_operationMenuActivated(QAction *);
    void _q_scrollBarChanged();
    void _q_updateActions();
    bool inTitleChange;
};

static bool isChildOf(QWidget * child, QWidget * parent)
{
    if (!parent || !child)
        return false;
    QWidget * w = child;
    while(w && w != parent)
        w = w->parentWidget();
    return w != 0;
}

/*!
    Constructs a workspace with the given \a parent.
*/
QWorkspace::QWorkspace(QWidget *parent)
    : QWidget(*new QWorkspacePrivate, parent, 0)
{
    Q_D(QWorkspace);
    d->init();
}

#ifdef QT3_SUPPORT
/*!
    Use one of the constructors that doesn't take the \a name
    argument and then use setObjectName() instead.
*/
QWorkspace::QWorkspace(QWidget *parent, const char *name)
    : QWidget(*new QWorkspacePrivate, parent, 0)
{
    Q_D(QWorkspace);
    setObjectName(QString::fromAscii(name));
    d->init();
}
#endif // QT3_SUPPORT

/*!
    \internal
*/
void
QWorkspacePrivate::init()
{
    Q_Q(QWorkspace);

    maxcontrols = 0;
    active = 0;
    maxWindow = 0;
    maxtools = 0;
    px = 0;
    py = 0;
    becomeActive = 0;
    popup = new QMenu(q);
    toolPopup = new QMenu(q);
    popup->setObjectName(QLatin1String("qt_internal_mdi_popup"));
    toolPopup->setObjectName(QLatin1String("qt_internal_mdi_tool_popup"));

    actions[QWorkspacePrivate::RestoreAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarNormalButton, 0, q)),
                                                         QWorkspace::tr("&Restore"), q);
    actions[QWorkspacePrivate::MoveAct] = new QAction(QWorkspace::tr("&Move"), q);
    actions[QWorkspacePrivate::ResizeAct] = new QAction(QWorkspace::tr("&Size"), q);
    actions[QWorkspacePrivate::MinimizeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarMinButton, 0, q)),
                                                          QWorkspace::tr("Mi&nimize"), q);
    actions[QWorkspacePrivate::MaximizeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarMaxButton, 0, q)),
                                                          QWorkspace::tr("Ma&ximize"), q);
    actions[QWorkspacePrivate::CloseAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarCloseButton, 0, q)),
                                                          QWorkspace::tr("&Close")
#ifndef QT_NO_SHORTCUT
                                                          +QLatin1Char('\t')+(QString)QKeySequence(Qt::CTRL+Qt::Key_F4)
#endif
                                                          ,q);
    QObject::connect(actions[QWorkspacePrivate::CloseAct], SIGNAL(triggered()), q, SLOT(closeActiveWindow()));
    actions[QWorkspacePrivate::StaysOnTopAct] = new QAction(QWorkspace::tr("Stay on &Top"), q);
    actions[QWorkspacePrivate::StaysOnTopAct]->setChecked(true);
    actions[QWorkspacePrivate::ShadeAct] = new QAction(QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarShadeButton, 0, q)),
                                                          QWorkspace::tr("Sh&ade"), q);

    QObject::connect(popup, SIGNAL(aboutToShow()), q, SLOT(_q_updateActions()));
    QObject::connect(popup, SIGNAL(triggered(QAction*)), q, SLOT(_q_operationMenuActivated(QAction*)));
    popup->addAction(actions[QWorkspacePrivate::RestoreAct]);
    popup->addAction(actions[QWorkspacePrivate::MoveAct]);
    popup->addAction(actions[QWorkspacePrivate::ResizeAct]);
    popup->addAction(actions[QWorkspacePrivate::MinimizeAct]);
    popup->addAction(actions[QWorkspacePrivate::MaximizeAct]);
    popup->addSeparator();
    popup->addAction(actions[QWorkspacePrivate::CloseAct]);

    QObject::connect(toolPopup, SIGNAL(aboutToShow()), q, SLOT(_q_updateActions()));
    QObject::connect(toolPopup, SIGNAL(triggered(QAction*)), q, SLOT(_q_operationMenuActivated(QAction*)));
    toolPopup->addAction(actions[QWorkspacePrivate::MoveAct]);
    toolPopup->addAction(actions[QWorkspacePrivate::ResizeAct]);
    toolPopup->addAction(actions[QWorkspacePrivate::StaysOnTopAct]);
    toolPopup->addSeparator();
    toolPopup->addAction(actions[QWorkspacePrivate::ShadeAct]);
    toolPopup->addAction(actions[QWorkspacePrivate::CloseAct]);

#ifndef QT_NO_SHORTCUT
    // Set up shortcut bindings (id -> slot), most used first
    QList <QKeySequence> shortcuts = QKeySequence::keyBindings(QKeySequence::NextChild);
    foreach (const QKeySequence &seq, shortcuts)
        shortcutMap.insert(q->grabShortcut(seq), "activateNextWindow");

    shortcuts = QKeySequence::keyBindings(QKeySequence::PreviousChild);
    foreach (const QKeySequence &seq, shortcuts)
        shortcutMap.insert(q->grabShortcut(seq), "activatePreviousWindow");

    shortcuts = QKeySequence::keyBindings(QKeySequence::Close);
    foreach (const QKeySequence &seq, shortcuts)
        shortcutMap.insert(q->grabShortcut(seq), "closeActiveWindow");

    shortcutMap.insert(q->grabShortcut(QKeySequence(QLatin1String("ALT+-"))), "_q_showOperationMenu");
#endif // QT_NO_SHORTCUT

    q->setBackgroundRole(QPalette::Dark);
    q->setAutoFillBackground(true);
    q->setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));

    hbar = vbar = 0;
    corner = 0;
    xoffset = yoffset = 0;

    q->window()->installEventFilter(q);

    inTitleChange = false;
    updateWorkspace();
}

/*!
    Destroys the workspace and frees any allocated resources.
*/

QWorkspace::~QWorkspace()
{
}

/*! \reimp */
QSize QWorkspace::sizeHint() const
{
    QSize s(QApplication::desktop()->size());
    return QSize(s.width()*2/3, s.height()*2/3);
}


#ifdef QT3_SUPPORT
/*!
    Sets the background color to \a c.
    Use setBackground() instead.
*/
void QWorkspace::setPaletteBackgroundColor(const QColor & c)
{
    setBackground(c);
}

/*!
    Sets the background pixmap to \a pm.
    Use setBackground() instead.
*/
void QWorkspace::setPaletteBackgroundPixmap(const QPixmap & pm)
{
    setBackground(pm);
}
#endif // QT3_SUPPORT

/*!
    \property QWorkspace::background
    \brief the workspace's background
*/
QBrush QWorkspace::background() const
{
    Q_D(const QWorkspace);
    if (d->background.style() == Qt::NoBrush)
        return palette().dark();
    return d->background;
}

void QWorkspace::setBackground(const QBrush &background)
{
    Q_D(QWorkspace);
    d->background = background;
    setAttribute(Qt::WA_OpaquePaintEvent, background.style() == Qt::NoBrush);
    update();
}

/*!
    Adds widget \a w as new sub window to the workspace.  If \a flags
    are non-zero, they will override the flags set on the widget.

    Returns the widget used for the window frame.

    To remove the widget \a w from the workspace, simply call
    setParent() with the new parent (or 0 to make it a stand-alone
    window).
*/
QWidget * QWorkspace::addWindow(QWidget *w, Qt::WindowFlags flags)
{
    Q_D(QWorkspace);
    if (!w)
        return 0;

    w->setAutoFillBackground(true);

    QWidgetPrivate::adjustFlags(flags);

#if 0
    bool wasMaximized = w->isMaximized();
    bool wasMinimized = w->isMinimized();
#endif
    bool hasSize = w->testAttribute(Qt::WA_Resized);
    int x = w->x();
    int y = w->y();
    bool hasPos = w->testAttribute(Qt::WA_Moved);
    QSize s = w->size().expandedTo(qSmartMinSize(w));
    if (!hasSize && w->sizeHint().isValid())
        w->adjustSize();

    QWorkspaceChild* child = new QWorkspaceChild(w, this, flags);
    child->setObjectName(QLatin1String("qt_workspacechild"));
    child->installEventFilter(this);

    connect(child, SIGNAL(popupOperationMenu(QPoint)),
            this, SLOT(_q_popupOperationMenu(QPoint)));
    connect(child, SIGNAL(showOperationMenu()),
            this, SLOT(_q_showOperationMenu()));
    d->windows.append(child);
    if (child->isVisibleTo(this))
        d->focus.append(child);
    child->internalRaise();

    if (!hasPos)
        d->place(child);
    if (!hasSize)
        child->adjustSize();
    if (hasPos)
        child->move(x, y);

    return child;

#if 0
    if (wasMaximized)
        w->showMaximized();
    else if (wasMinimized)
        w->showMinimized();
    else if (!hasBeenHidden)
        d->activateWindow(w);

    d->updateWorkspace();
    return child;
#endif
}

/*! \reimp */
void QWorkspace::childEvent(QChildEvent * e)
{
    Q_D(QWorkspace);
    if (e->removed()) {
        if (d->windows.removeAll(static_cast<QWorkspaceChild*>(e->child()))) {
            d->focus.removeAll(static_cast<QWorkspaceChild*>(e->child()));
            if (d->maxWindow == e->child())
                d->maxWindow = 0;
            d->updateWorkspace();
        }
    }
}

/*! \reimp */
#ifndef QT_NO_WHEELEVENT
void QWorkspace::wheelEvent(QWheelEvent *e)
{
    Q_D(QWorkspace);
    if (!scrollBarsEnabled())
        return;
    // the scroll bars are children of the workspace, so if we receive
    // a wheel event we redirect to the scroll bars using a direct event
    // call, /not/ using sendEvent() because if the scroll bar ignores the
    // event QApplication::sendEvent() will propagate the event to the parent widget,
    // which is us, who /just/ sent it.
    if (d->vbar && d->vbar->isVisible() && !(e->modifiers() & Qt::AltModifier))
        d->vbar->event(e);
    else if (d->hbar && d->hbar->isVisible())
        d->hbar->event(e);
}
#endif

void QWorkspacePrivate::activateWindow(QWidget* w, bool change_focus)
{
    Q_Q(QWorkspace);
    if (!w) {
        active = 0;
        emit q->windowActivated(0);
        return;
    }
    if (!q->isVisible()) {
        becomeActive = w;
        return;
    }

    if (active && active->windowWidget() == w) {
        if (!isChildOf(q->focusWidget(), w)) // child window does not have focus
            active->setActive(true);
        return;
    }

    active = 0;
    // First deactivate all other workspace clients
    QList<QWorkspaceChild *>::Iterator it(windows.begin());
    while (it != windows.end()) {
        QWorkspaceChild* c = *it;
        ++it;
        if (c->windowWidget() == w)
            active = c;
        else
            c->setActive(false);
    }

    if (!active)
        return;

    // Then activate the new one, so the focus is stored correctly
    active->setActive(true);

    if (!active)
        return;

    if (maxWindow && maxWindow != active && active->windowWidget() &&
        (active->windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint))
        active->showMaximized();

    active->internalRaise();

    if (change_focus) {
        int from = focus.indexOf(active);
        if (from >= 0)
            focus.move(from, focus.size() - 1);
    }

    updateWorkspace();
    emit q->windowActivated(w);
}


/*!
    Returns a pointer to the widget corresponding to the active child
    window, or 0 if no window is active.

    \sa setActiveWindow()
*/
QWidget* QWorkspace::activeWindow() const
{
    Q_D(const QWorkspace);
    return d->active? d->active->windowWidget() : 0;
}

/*!
    Makes the child window that contains \a w the active child window.

    \sa activeWindow()
*/
void QWorkspace::setActiveWindow(QWidget *w)
{
    Q_D(QWorkspace);
    d->activateWindow(w, true);
    if (w && w->isMinimized())
        w->setWindowState(w->windowState() & ~Qt::WindowMinimized);
}

void QWorkspacePrivate::place(QWidget *w)
{
    Q_Q(QWorkspace);

    QList<QWidget *> widgets;
    for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it)
        if (*it != w)
            widgets.append(*it);

    int overlap, minOverlap = 0;
    int possible;

    QRect r1(0, 0, 0, 0);
    QRect r2(0, 0, 0, 0);
    QRect maxRect = q->rect();
    int x = maxRect.left(), y = maxRect.top();
    QPoint wpos(maxRect.left(), maxRect.top());

    bool firstPass = true;

    do {
        if (y + w->height() > maxRect.bottom()) {
            overlap = -1;
        } else if(x + w->width() > maxRect.right()) {
            overlap = -2;
        } else {
            overlap = 0;

            r1.setRect(x, y, w->width(), w->height());

            QWidget *l;
            QList<QWidget *>::Iterator it(widgets.begin());
            while (it != widgets.end()) {
                l = *it;
                ++it;

                if (maxWindow == l)
                    r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore);
                else
                    r2 = QStyle::visualRect(q->layoutDirection(), maxRect,
                                            QRect(l->x(), l->y(), l->width(), l->height()));

                if (r2.intersects(r1)) {
                    r2.setCoords(qMax(r1.left(), r2.left()),
                                 qMax(r1.top(), r2.top()),
                                 qMin(r1.right(), r2.right()),
                                 qMin(r1.bottom(), r2.bottom())
                                );

                    overlap += (r2.right() - r2.left()) *
                               (r2.bottom() - r2.top());
                }
            }
        }

        if (overlap == 0) {
            wpos = QPoint(x, y);
            break;
        }

        if (firstPass) {
            firstPass = false;
            minOverlap = overlap;
        } else if (overlap >= 0 && overlap < minOverlap) {
            minOverlap = overlap;
            wpos = QPoint(x, y);
        }

        if (overlap > 0) {
            possible = maxRect.right();
            if (possible - w->width() > x) possible -= w->width();

            QWidget *l;
            QList<QWidget *>::Iterator it(widgets.begin());
            while (it != widgets.end()) {
                l = *it;
                ++it;
                if (maxWindow == l)
                    r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore);
                else
                    r2 = QStyle::visualRect(q->layoutDirection(), maxRect,
                                            QRect(l->x(), l->y(), l->width(), l->height()));

                if((y < r2.bottom()) && (r2.top() < w->height() + y)) {
                    if(r2.right() > x)
                        possible = possible < r2.right() ?
                                   possible : r2.right();

                    if(r2.left() - w->width() > x)
                        possible = possible < r2.left() - w->width() ?
                                   possible : r2.left() - w->width();
                }
            }

            x = possible;
        } else if (overlap == -2) {
            x = maxRect.left();
            possible = maxRect.bottom();

            if (possible - w->height() > y) possible -= w->height();

            QWidget *l;
            QList<QWidget *>::Iterator it(widgets.begin());
            while (it != widgets.end()) {
                l = *it;
                ++it;
                if (maxWindow == l)
                    r2 = QStyle::visualRect(q->layoutDirection(), maxRect, maxRestore);
                else
                    r2 = QStyle::visualRect(q->layoutDirection(), maxRect,
                                            QRect(l->x(), l->y(), l->width(), l->height()));

                if(r2.bottom() > y)
                    possible = possible < r2.bottom() ?
                               possible : r2.bottom();

                if(r2.top() - w->height() > y)
                    possible = possible < r2.top() - w->height() ?
                               possible : r2.top() - w->height();
            }

            y = possible;
        }
    }
    while(overlap != 0 && overlap != -1);

    QRect resultRect = w->geometry();
    resultRect.moveTo(wpos);
    w->setGeometry(QStyle::visualRect(q->layoutDirection(), maxRect, resultRect));
    updateWorkspace();
}


void QWorkspacePrivate::insertIcon(QWidget* w)
{
    Q_Q(QWorkspace);
    if (!w || icons.contains(w))
        return;
    icons.append(w);
    if (w->parentWidget() != q) {
        w->setParent(q, 0);
        w->move(0,0);
    }
    QRect cr = updateWorkspace();
    int x = 0;
    int y = cr.height() - w->height();

    QList<QWidget *>::Iterator it(icons.begin());
    while (it != icons.end()) {
        QWidget* i = *it;
        ++it;
        if (x > 0 && x + i->width() > cr.width()){
            x = 0;
            y -= i->height();
        }

        if (i != w &&
            i->geometry().intersects(QRect(x, y, w->width(), w->height())))
            x += i->width();
    }
    w->move(x, y);

    if (q->isVisibleTo(q->parentWidget())) {
        w->show();
        w->lower();
    }
    updateWorkspace();
}


void QWorkspacePrivate::removeIcon(QWidget* w)
{
    if (icons.removeAll(w))
        w->hide();
}


/*! \reimp  */
void QWorkspace::resizeEvent(QResizeEvent *)
{
    Q_D(QWorkspace);
    if (d->maxWindow) {
        d->maxWindow->adjustToFullscreen();
        if (d->maxWindow->windowWidget())
            d->maxWindow->windowWidget()->overrideWindowState(Qt::WindowMaximized);
    }
    d->updateWorkspace();
}

/*! \reimp */
void QWorkspace::showEvent(QShowEvent *e)
{
    Q_D(QWorkspace);
    if (d->maxWindow)
        d->showMaximizeControls();
    QWidget::showEvent(e);
    if (d->becomeActive) {
        d->activateWindow(d->becomeActive);
        d->becomeActive = 0;
    } else if (d->windows.count() > 0 && !d->active) {
        d->activateWindow(d->windows.first()->windowWidget());
    }

//     // force a frame repaint - this is a workaround for what seems to be a bug
//     // introduced when changing the QWidget::show() implementation. Might be
//     // a windows bug as well though.
//     for (int i = 0; i < d->windows.count(); ++i) {
//      QWorkspaceChild* c = d->windows.at(i);
//         c->update(c->rect());
//     }

    d->updateWorkspace();
}

/*! \reimp */
void QWorkspace::hideEvent(QHideEvent *)
{
    Q_D(QWorkspace);
    if (!isVisible())
        d->hideMaximizeControls();
}

/*! \reimp */
void QWorkspace::paintEvent(QPaintEvent *)
{
    Q_D(QWorkspace);

    if (d->background.style() != Qt::NoBrush) {
        QPainter p(this);
        p.fillRect(0, 0, width(), height(), d->background);
    }
}

void QWorkspacePrivate::minimizeWindow(QWidget* w)
{
    QWorkspaceChild* c = findChild(w);

    if (!w || !(w->windowFlags() & Qt::WindowMinimizeButtonHint))
        return;

    if (c) {
        bool wasMax = false;
        if (c == maxWindow) {
            wasMax = true;
            maxWindow = 0;
            hideMaximizeControls();
            for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it) {
                QWorkspaceChild* c = *it;
                if (c->titlebar)
                    c->titlebar->setMovable(true);
                c->widgetResizeHandler->setActive(true);
            }
        }
        c->hide();
        if (wasMax)
            c->setGeometry(maxRestore);
        if (!focus.contains(c))
            focus.append(c);
        insertIcon(c->iconWidget());

        if (!maxWindow)
            activateWindow(w);

        updateWorkspace();

        w->overrideWindowState(Qt::WindowMinimized);
        c->overrideWindowState(Qt::WindowMinimized);
    }
}

void QWorkspacePrivate::normalizeWindow(QWidget* w)
{
    Q_Q(QWorkspace);
    QWorkspaceChild* c = findChild(w);
    if (!w)
        return;
    if (c) {
        w->overrideWindowState(Qt::WindowNoState);
        hideMaximizeControls();
        if (!maxmenubar || q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q) || !maxWindow) {
            if (w->minimumSize() != w->maximumSize())
                c->widgetResizeHandler->setActive(true);
            if (c->titlebar)
                c->titlebar->setMovable(true);
        }
        w->overrideWindowState(Qt::WindowNoState);
        c->overrideWindowState(Qt::WindowNoState);

        if (c == maxWindow) {
            c->setGeometry(maxRestore);
            maxWindow = 0;
        } else {
            if (c->iconw)
                removeIcon(c->iconw->parentWidget());
            c->show();
        }

        hideMaximizeControls();
        for (QList<QWorkspaceChild *>::Iterator it(windows.begin()); it != windows.end(); ++it) {
            QWorkspaceChild* c = *it;
            if (c->titlebar)
                c->titlebar->setMovable(true);
            if (c->childWidget && c->childWidget->minimumSize() != c->childWidget->maximumSize())
                c->widgetResizeHandler->setActive(true);
        }
        activateWindow(w, true);
        updateWorkspace();
    }
}

void QWorkspacePrivate::maximizeWindow(QWidget* w)
{
    Q_Q(QWorkspace);
    QWorkspaceChild* c = findChild(w);

    if (!w || !(w->windowFlags() & Qt::WindowMaximizeButtonHint))
        return;

    if (!c || c == maxWindow)
        return;

    bool updatesEnabled = q->updatesEnabled();
    q->setUpdatesEnabled(false);

    if (c->iconw && icons.contains(c->iconw->parentWidget()))
        normalizeWindow(w);
    QRect r(c->geometry());
    QWorkspaceChild *oldMaxWindow = maxWindow;
    maxWindow = c;

    showMaximizeControls();

    c->adjustToFullscreen();
    c->show();
    c->internalRaise();
    if (oldMaxWindow != c) {
        if (oldMaxWindow) {
            oldMaxWindow->setGeometry(maxRestore);
            oldMaxWindow->overrideWindowState(Qt::WindowNoState);
            if(oldMaxWindow->windowWidget())
                oldMaxWindow->windowWidget()->overrideWindowState(Qt::WindowNoState);
        }
        maxRestore = r;
    }

    activateWindow(w);

    if(!maxmenubar || q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) {
        if (!active && becomeActive) {
            active = (QWorkspaceChild*)becomeActive->parentWidget();
            active->setActive(true);
            becomeActive = 0;
            emit q->windowActivated(active->windowWidget());
        }
        c->widgetResizeHandler->setActive(false);
        if (c->titlebar)
            c->titlebar->setMovable(false);
    }
    updateWorkspace();

    w->overrideWindowState(Qt::WindowMaximized);
    c->overrideWindowState(Qt::WindowMaximized);
    q->setUpdatesEnabled(updatesEnabled);
}

void QWorkspacePrivate::showWindow(QWidget* w)
{
    if (w->isMinimized() && (w->windowFlags() & Qt::WindowMinimizeButtonHint))
        minimizeWindow(w);
    else if ((maxWindow || w->isMaximized()) && w->windowFlags() & Qt::WindowMaximizeButtonHint)
        maximizeWindow(w);
    else if (w->windowFlags() & Qt::WindowMaximizeButtonHint)
        normalizeWindow(w);
    else
        w->parentWidget()->show();
    if (maxWindow)
        maxWindow->internalRaise();
    updateWorkspace();
}


QWorkspaceChild* QWorkspacePrivate::findChild(QWidget* w)
{
    QList<QWorkspaceChild *>::Iterator it(windows.begin());
    while (it != windows.end()) {
        QWorkspaceChild* c = *it;
        ++it;
        if (c->windowWidget() == w)
            return c;
    }
    return 0;
}

/*!
    Returns a list of all visible or minimized child windows. If \a
    order is CreationOrder (the default), the windows are listed in
    the order in which they were inserted into the workspace. If \a
    order is StackingOrder, the windows are listed in their stacking
    order, with the topmost window as the last item in the list.
*/
QWidgetList QWorkspace::windowList(WindowOrder order) const
{
    Q_D(const QWorkspace);
    QWidgetList windows;
    if (order == StackingOrder) {
        QObjectList cl = children();
        for (int i = 0; i < cl.size(); ++i) {
            QWorkspaceChild *c = qobject_cast<QWorkspaceChild*>(cl.at(i));
            if (c && c->isWindowOrIconVisible())
                windows.append(c->windowWidget());
        }
    } else {
        QList<QWorkspaceChild *>::ConstIterator it(d->windows.begin());
        while (it != d->windows.end()) {
            QWorkspaceChild* c = *it;
            ++it;
            if (c && c->isWindowOrIconVisible())
                windows.append(c->windowWidget());
        }
    }
    return windows;
}


/*! \reimp */
bool QWorkspace::event(QEvent *e)
{
#ifndef QT_NO_SHORTCUT
    Q_D(QWorkspace);
    if (e->type() == QEvent::Shortcut) {
        QShortcutEvent *se = static_cast<QShortcutEvent *>(e);
        const char *theSlot = d->shortcutMap.value(se->shortcutId(), 0);
        if (theSlot)
            QMetaObject::invokeMethod(this, theSlot);
    } else
#endif
    if (e->type() == QEvent::FocusIn || e->type() == QEvent::FocusOut){
        return true;
    }
    return QWidget::event(e);
}

/*! \reimp */
bool QWorkspace::eventFilter(QObject *o, QEvent * e)
{
    Q_D(QWorkspace);
    static QTime* t = 0;
    static QWorkspace* tc = 0;
    if (o == d->maxtools) {
        switch (e->type()) {
        case QEvent::MouseButtonPress:
            {
                QMenuBar* b = (QMenuBar*)o->parent();
                if (!t)
                    t = new QTime;
                if (tc != this || t->elapsed() > QApplication::doubleClickInterval()) {
                    if (isRightToLeft()) {
                        QPoint p = b->mapToGlobal(QPoint(b->x() + b->width(), b->y() + b->height()));
                        p.rx() -= d->popup->sizeHint().width();
                        d->_q_popupOperationMenu(p);
                    } else {
                        d->_q_popupOperationMenu(b->mapToGlobal(QPoint(b->x(), b->y() + b->height())));
                    }
                    t->start();
                    tc = this;
                } else {
                    tc = 0;
                    closeActiveWindow();
                }
                return true;
            }
        default:
            break;
        }
        return QWidget::eventFilter(o, e);
    }
    switch (e->type()) {
    case QEvent::HideToParent:
        break;
    case QEvent::ShowToParent:
        if (QWorkspaceChild *c = qobject_cast<QWorkspaceChild*>(o))
            if (!d->focus.contains(c))
                d->focus.append(c);
        d->updateWorkspace();
        break;
    case QEvent::WindowTitleChange:
        if (!d->inTitleChange) {
            if (o == window())
                d->topTitle = window()->windowTitle();
            if (d->maxWindow && d->maxWindow->windowWidget() && d->topTitle.size()) {
                d->inTitleChange = true;
                window()->setWindowTitle(tr("%1 - [%2]")
                                         .arg(d->topTitle).arg(d->maxWindow->windowWidget()->windowTitle()));
                d->inTitleChange = false;
            }
        }
        break;

    case QEvent::ModifiedChange:
        if (o == d->maxWindow)
            window()->setWindowModified(d->maxWindow->isWindowModified());
        break;

    case QEvent::Close:
        if (o == window())
        {
            QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
            while (it != d->windows.end()) {
                QWorkspaceChild* c = *it;
                ++it;
                if (c->shademode)
                    c->showShaded();
            }
        } else if (qobject_cast<QWorkspaceChild*>(o)) {
            d->popup->hide();
        }
        d->updateWorkspace();
        break;
    default:
        break;
    }
    return QWidget::eventFilter(o, e);
}

static QMenuBar *findMenuBar(QWidget *w)
{
    // don't search recursively to avoid finding a menu bar of a
    // mainwindow that happens to be a workspace window (like
    // a mainwindow in designer)
    QList<QObject *> children = w->children();
    for (int i = 0; i < children.count(); ++i) {
        QMenuBar *bar = qobject_cast<QMenuBar *>(children.at(i));
        if (bar)
            return bar;
    }
    return 0;
}

void QWorkspacePrivate::showMaximizeControls()
{
    Q_Q(QWorkspace);
    Q_ASSERT(maxWindow);

    // merge windowtitle and modified state
    if (!topTitle.size())
        topTitle = q->window()->windowTitle();

    if (maxWindow->windowWidget()) {
        QString docTitle = maxWindow->windowWidget()->windowTitle();
        if (topTitle.size() && docTitle.size()) {
            inTitleChange = true;
            q->window()->setWindowTitle(QWorkspace::tr("%1 - [%2]").arg(topTitle).arg(docTitle));
            inTitleChange = false;
        }
        q->window()->setWindowModified(maxWindow->windowWidget()->isWindowModified());
    }

    if (!q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) {
        QMenuBar* b = 0;

        // Do a breadth-first search first on every parent,
        QWidget* w = q->parentWidget();
        while (w) {
            b = findMenuBar(w);
            if (b)
                break;
            w = w->parentWidget();
        }

        // last attempt.
        if (!b)
            b = findMenuBar(q->window());

        if (!b)
            return;

        if (!maxcontrols) {
            maxmenubar = b;
            maxcontrols = new QMDIControl(b);
            QObject::connect(maxcontrols, SIGNAL(_q_minimize()),
                             q, SLOT(_q_minimizeActiveWindow()));
            QObject::connect(maxcontrols, SIGNAL(_q_restore()),
                             q, SLOT(_q_normalizeActiveWindow()));
            QObject::connect(maxcontrols, SIGNAL(_q_close()),
                             q, SLOT(closeActiveWindow()));
        }

        b->setCornerWidget(maxcontrols);
        if (b->isVisible())
            maxcontrols->show();
        if (!active && becomeActive) {
            active = (QWorkspaceChild*)becomeActive->parentWidget();
            active->setActive(true);
            becomeActive = 0;
            emit q->windowActivated(active->windowWidget());
        }
        if (active) {
            if (!maxtools) {
                maxtools = new QLabel(q->window());
                maxtools->setObjectName(QLatin1String("qt_maxtools"));
                maxtools->installEventFilter(q);
            }
            if (active->windowWidget() && !active->windowWidget()->windowIcon().isNull()) {
                QIcon icon = active->windowWidget()->windowIcon();
                int iconSize = maxcontrols->size().height();
                maxtools->setPixmap(icon.pixmap(QSize(iconSize, iconSize)));
            } else {
                QPixmap pm = q->style()->standardPixmap(QStyle::SP_TitleBarMenuButton, 0, q);
                if (pm.isNull()) {
                    pm = QPixmap(14,14);
                    pm.fill(Qt::black);
                }
                maxtools->setPixmap(pm);
            }
            b->setCornerWidget(maxtools, Qt::TopLeftCorner);
            if (b->isVisible())
                maxtools->show();
        }
    }
}


void QWorkspacePrivate::hideMaximizeControls()
{
    Q_Q(QWorkspace);
    if (maxmenubar && !q->style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, q)) {
        if (maxmenubar) {
            maxmenubar->setCornerWidget(0, Qt::TopLeftCorner);
            maxmenubar->setCornerWidget(0, Qt::TopRightCorner);
        }
        if (maxcontrols) {
            maxcontrols->deleteLater();
            maxcontrols = 0;
        }
        if (maxtools) {
            maxtools->deleteLater();
            maxtools = 0;
        }
    }

    //unmerge the title bar/modification state
    if (topTitle.size()) {
        inTitleChange = true;
        q->window()->setWindowTitle(topTitle);
        inTitleChange = false;
    }
    q->window()->setWindowModified(false);
}

/*!
    Closes the child window that is currently active.

    \sa closeAllWindows()
*/
void QWorkspace::closeActiveWindow()
{
    Q_D(QWorkspace);
    if (d->maxWindow && d->maxWindow->windowWidget())
        d->maxWindow->windowWidget()->close();
    else if (d->active && d->active->windowWidget())
        d->active->windowWidget()->close();
    d->updateWorkspace();
}

/*!
    Closes all child windows.

    If any child window fails to accept the close event, the remaining windows
    will remain open.

    \sa closeActiveWindow()
*/
void QWorkspace::closeAllWindows()
{
    Q_D(QWorkspace);
    bool did_close = true;
    QList<QWorkspaceChild *>::const_iterator it = d->windows.constBegin();
    while (it != d->windows.constEnd() && did_close) {
        QWorkspaceChild *c = *it;
        ++it;
        if (c->windowWidget() && !c->windowWidget()->isHidden())
            did_close = c->windowWidget()->close();
    }
}

void QWorkspacePrivate::_q_normalizeActiveWindow()
{
    if (maxWindow)
        maxWindow->showNormal();
    else if (active)
        active->showNormal();
}

void QWorkspacePrivate::_q_minimizeActiveWindow()
{
    if (maxWindow)
        maxWindow->showMinimized();
    else if (active)
        active->showMinimized();
}

void QWorkspacePrivate::_q_showOperationMenu()
{
    Q_Q(QWorkspace);
    if  (!active || !active->windowWidget())
        return;
    Q_ASSERT((active->windowWidget()->windowFlags() & Qt::WindowSystemMenuHint));
    QPoint p;
    QMenu *popup = (active->titlebar && active->titlebar->isTool()) ? toolPopup : this->popup;
    if (q->isRightToLeft()) {
        p = QPoint(active->windowWidget()->mapToGlobal(QPoint(active->windowWidget()->width(),0)));
        p.rx() -= popup->sizeHint().width();
    } else {
        p = QPoint(active->windowWidget()->mapToGlobal(QPoint(0,0)));
    }
    if (!active->isVisible()) {
        p = active->iconWidget()->mapToGlobal(QPoint(0,0));
        p.ry() -= popup->sizeHint().height();
    }
    _q_popupOperationMenu(p);
}

void QWorkspacePrivate::_q_popupOperationMenu(const QPoint&  p)
{
    if (!active || !active->windowWidget() || !(active->windowWidget()->windowFlags() & Qt::WindowSystemMenuHint))
        return;
    if (active->titlebar && active->titlebar->isTool())
        toolPopup->popup(p);
    else
        popup->popup(p);
}

void QWorkspacePrivate::_q_updateActions()
{
    Q_Q(QWorkspace);
    for (int i = 1; i < NCountAct-1; i++) {
        bool enable = active != 0;
        actions[i]->setEnabled(enable);
    }

    if (!active || !active->windowWidget())
        return;

    QWidget *windowWidget = active->windowWidget();
    bool canResize = windowWidget->maximumSize() != windowWidget->minimumSize();
    actions[QWorkspacePrivate::ResizeAct]->setEnabled(canResize);
    actions[QWorkspacePrivate::MinimizeAct]->setEnabled((windowWidget->windowFlags() & Qt::WindowMinimizeButtonHint));
    actions[QWorkspacePrivate::MaximizeAct]->setEnabled((windowWidget->windowFlags() & Qt::WindowMaximizeButtonHint) && canResize);

    if (active == maxWindow) {
        actions[QWorkspacePrivate::MoveAct]->setEnabled(false);
        actions[QWorkspacePrivate::ResizeAct]->setEnabled(false);
        actions[QWorkspacePrivate::MaximizeAct]->setEnabled(false);
        actions[QWorkspacePrivate::RestoreAct]->setEnabled(true);
    } else if (active->isVisible()){
        actions[QWorkspacePrivate::RestoreAct]->setEnabled(false);
    } else {
        actions[QWorkspacePrivate::MoveAct]->setEnabled(false);
        actions[QWorkspacePrivate::ResizeAct]->setEnabled(false);
        actions[QWorkspacePrivate::MinimizeAct]->setEnabled(false);
        actions[QWorkspacePrivate::RestoreAct]->setEnabled(true);
    }
    if (active->shademode) {
        actions[QWorkspacePrivate::ShadeAct]->setIcon(
            QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarUnshadeButton, 0, q)));
        actions[QWorkspacePrivate::ShadeAct]->setText(QWorkspace::tr("&Unshade"));
    } else {
        actions[QWorkspacePrivate::ShadeAct]->setIcon(
            QIcon(q->style()->standardPixmap(QStyle::SP_TitleBarShadeButton, 0, q)));
        actions[QWorkspacePrivate::ShadeAct]->setText(QWorkspace::tr("Sh&ade"));
    }
    actions[QWorkspacePrivate::StaysOnTopAct]->setEnabled(!active->shademode && canResize);
    actions[QWorkspacePrivate::StaysOnTopAct]->setChecked(
        (active->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint));
}

void QWorkspacePrivate::_q_operationMenuActivated(QAction *action)
{
    if (!active)
        return;
    if(action == actions[QWorkspacePrivate::RestoreAct]) {
        active->showNormal();
    } else if(action == actions[QWorkspacePrivate::MoveAct]) {
        active->doMove();
    } else if(action == actions[QWorkspacePrivate::ResizeAct]) {
        if (active->shademode)
            active->showShaded();
        active->doResize();
    } else if(action == actions[QWorkspacePrivate::MinimizeAct]) {
        active->showMinimized();
    } else if(action == actions[QWorkspacePrivate::MaximizeAct]) {
        active->showMaximized();
    } else if(action == actions[QWorkspacePrivate::ShadeAct]) {
        active->showShaded();
    } else if(action == actions[QWorkspacePrivate::StaysOnTopAct]) {
        if(QWidget* w = active->windowWidget()) {
            if ((w->windowFlags() & Qt::WindowStaysOnTopHint)) {
                w->overrideWindowFlags(w->windowFlags() & ~Qt::WindowStaysOnTopHint);
            } else {
                w->overrideWindowFlags(w->windowFlags() | Qt::WindowStaysOnTopHint);
                w->parentWidget()->raise();
            }
        }
    }
}


void QWorkspacePrivate::hideChild(QWorkspaceChild *c)
{
    Q_Q(QWorkspace);

//     bool updatesEnabled = q->updatesEnabled();
//     q->setUpdatesEnabled(false);
    focus.removeAll(c);
    QRect restore;
    if (maxWindow == c)
        restore = maxRestore;
    if (active == c) {
        q->setFocus();
        q->activatePreviousWindow();
    }
    if (active == c)
        activateWindow(0);
    if (maxWindow == c) {
        hideMaximizeControls();
        maxWindow = 0;
    }
    c->hide();
    if (!restore.isEmpty())
        c->setGeometry(restore);
//     q->setUpdatesEnabled(updatesEnabled);
}

/*!
    Gives the input focus to the next window in the list of child
    windows.

    \sa activatePreviousWindow()
*/
void QWorkspace::activateNextWindow()
{
    Q_D(QWorkspace);

    if (d->focus.isEmpty())
        return;
    if (!d->active) {
        if (d->focus.first())
            d->activateWindow(d->focus.first()->windowWidget(), false);
        return;
    }

    int a = d->focus.indexOf(d->active) + 1;

    a = a % d->focus.count();

    if (d->focus.at(a))
        d->activateWindow(d->focus.at(a)->windowWidget(), false);
    else
        d->activateWindow(0);
}

/*!
    Gives the input focus to the previous window in the list of child
    windows.

    \sa activateNextWindow()
*/
void QWorkspace::activatePreviousWindow()
{
    Q_D(QWorkspace);

    if (d->focus.isEmpty())
        return;
    if (!d->active) {
        if (d->focus.last())
            d->activateWindow(d->focus.first()->windowWidget(), false);
        else
            d->activateWindow(0);
        return;
    }

    int a = d->focus.indexOf(d->active) - 1;
    if (a < 0)
        a = d->focus.count()-1;

    if (d->focus.at(a))
        d->activateWindow(d->focus.at(a)->windowWidget(), false);
    else
        d->activateWindow(0);
}


/*!
    \fn void QWorkspace::windowActivated(QWidget* w)

    This signal is emitted when the child window \a w becomes active.
    Note that \a w can be 0, and that more than one signal may be
    emitted for a single activation event.

    \sa activeWindow(), windowList()
*/

/*!
    Arranges all the child windows in a cascade pattern.

    \sa tile(), arrangeIcons()
*/
void QWorkspace::cascade()
{
    Q_D(QWorkspace);
    blockSignals(true);
    if  (d->maxWindow)
        d->maxWindow->showNormal();

    if (d->vbar) {
        d->vbar->blockSignals(true);
        d->vbar->setValue(0);
        d->vbar->blockSignals(false);
        d->hbar->blockSignals(true);
        d->hbar->setValue(0);
        d->hbar->blockSignals(false);
        d->_q_scrollBarChanged();
    }

    const int xoffset = 13;
    const int yoffset = 20;

    // make a list of all relevant mdi clients
    QList<QWorkspaceChild *> widgets;
    QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
    QWorkspaceChild* wc = 0;

    for (it = d->focus.begin(); it != d->focus.end(); ++it) {
        wc = *it;
        if (wc->windowWidget()->isVisibleTo(this) && !(wc->titlebar && wc->titlebar->isTool()))
            widgets.append(wc);
    }

    int x = 0;
    int y = 0;

    it = widgets.begin();
    while (it != widgets.end()) {
        QWorkspaceChild *child = *it;
        ++it;

        QSize prefSize = child->windowWidget()->sizeHint().expandedTo(qSmartMinSize(child->windowWidget()));
        if (!prefSize.isValid())
            prefSize = child->windowWidget()->size();
        prefSize = prefSize.expandedTo(qSmartMinSize(child->windowWidget()));
        if (prefSize.isValid())
            prefSize += QSize(child->baseSize().width(), child->baseSize().height());

        int w = prefSize.width();
        int h = prefSize.height();

        child->showNormal();
        if (y + h > height())
            y = 0;
        if (x + w > width())
            x = 0;
        child->setGeometry(x, y, w, h);
        x += xoffset;
        y += yoffset;
        child->internalRaise();
    }
    d->updateWorkspace();
    blockSignals(false);
}

/*!
    Arranges all child windows in a tile pattern.

    \sa cascade(), arrangeIcons()
*/
void QWorkspace::tile()
{
    Q_D(QWorkspace);
    blockSignals(true);
    QWidget *oldActive = d->active ? d->active->windowWidget() : 0;
    if  (d->maxWindow)
        d->maxWindow->showNormal();

    if (d->vbar) {
        d->vbar->blockSignals(true);
        d->vbar->setValue(0);
        d->vbar->blockSignals(false);
        d->hbar->blockSignals(true);
        d->hbar->setValue(0);
        d->hbar->blockSignals(false);
        d->_q_scrollBarChanged();
    }

    int rows = 1;
    int cols = 1;
    int n = 0;
    QWorkspaceChild* c;

    QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
    while (it != d->windows.end()) {
        c = *it;
        ++it;
        if (!c->windowWidget()->isHidden()
            && !(c->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)
            && !c->iconw)
            n++;
    }

    while (rows * cols < n) {
        if (cols <= rows)
            cols++;
        else
            rows++;
    }
    int add = cols * rows - n;
    bool* used = new bool[cols*rows];
    for (int i = 0; i < rows*cols; i++)
        used[i] = false;

    int row = 0;
    int col = 0;
    int w = width() / cols;
    int h = height() / rows;

    it = d->windows.begin();
    while (it != d->windows.end()) {
        c = *it;
        ++it;
        if (c->iconw || c->windowWidget()->isHidden() || (c->titlebar && c->titlebar->isTool()))
            continue;
        if (!row && !col) {
            w -= c->baseSize().width();
            h -= c->baseSize().height();
        }
        if ((c->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)) {
            QPoint p = c->pos();
            if (p.x()+c->width() < 0)
                p.setX(0);
            if (p.x() > width())
                p.setX(width() - c->width());
            if (p.y() + 10 < 0)
                p.setY(0);
            if (p.y() > height())
                p.setY(height() - c->height());

            if (p != c->pos())
                c->QWidget::move(p);
        } else {
            c->showNormal();
            used[row*cols+col] = true;
            QSize sz(w, h);
            QSize bsize(c->baseSize());
            sz = sz.expandedTo(c->windowWidget()->minimumSize()).boundedTo(c->windowWidget()->maximumSize());
            sz += bsize;

            if ( add ) {
                if (sz.height() == h + bsize.height()) // no relevant constrains
                    sz.rheight() *= 2;
                used[(row+1)*cols+col] = true;
                add--;
            }

            c->setGeometry(col*w + col*bsize.width(), row*h + row*bsize.height(), sz.width(), sz.height());

            while(row < rows && col < cols && used[row*cols+col]) {
                col++;
                if (col == cols) {
                    col = 0;
                    row++;
                }
            }
        }
    }
    delete [] used;

    d->activateWindow(oldActive);
    d->updateWorkspace();
    blockSignals(false);
}

/*!
    Arranges all iconified windows at the bottom of the workspace.

    \sa cascade(), tile()
*/
void QWorkspace::arrangeIcons()
{
    Q_D(QWorkspace);

    QRect cr = d->updateWorkspace();
    int x = 0;
    int y = -1;

    QList<QWidget *>::Iterator it(d->icons.begin());
    while (it != d->icons.end()) {
        QWidget* i = *it;
        if (y == -1)
            y = cr.height() - i->height();
        if (x > 0 && x + i->width() > cr.width()) {
            x = 0;
            y -= i->height();
        }
        i->move(x, y);
        x += i->width();
        ++it;
    }
    d->updateWorkspace();
}


QWorkspaceChild::QWorkspaceChild(QWidget* window, QWorkspace *parent, Qt::WindowFlags flags)
    : QWidget(parent,
             Qt::FramelessWindowHint | Qt::SubWindow)
{
    setAttribute(Qt::WA_DeleteOnClose);
    setAttribute(Qt::WA_NoMousePropagation);
    setMouseTracking(true);
    act = false;
    iconw = 0;
    shademode = false;
    titlebar = 0;
    setAutoFillBackground(true);

    setBackgroundRole(QPalette::Window);
    if (window) {
        flags |= (window->windowFlags() & Qt::MSWindowsOwnDC);
        if (flags)
            window->setParent(this, flags & ~Qt::WindowType_Mask);
        else
            window->setParent(this);
    }

    if (window && (flags & (Qt::WindowTitleHint
                            | Qt::WindowSystemMenuHint
                            | Qt::WindowMinimizeButtonHint
                            | Qt::WindowMaximizeButtonHint
                            | Qt::WindowContextHelpButtonHint))) {
        titlebar = new QWorkspaceTitleBar(window, this, flags);
        connect(titlebar, SIGNAL(doActivate()),
                 this, SLOT(activate()));
        connect(titlebar, SIGNAL(doClose()),
                 window, SLOT(close()));
        connect(titlebar, SIGNAL(doMinimize()),
                 this, SLOT(showMinimized()));
        connect(titlebar, SIGNAL(doNormal()),
                 this, SLOT(showNormal()));
        connect(titlebar, SIGNAL(doMaximize()),
                 this, SLOT(showMaximized()));
        connect(titlebar, SIGNAL(popupOperationMenu(QPoint)),
                 this, SIGNAL(popupOperationMenu(QPoint)));
        connect(titlebar, SIGNAL(showOperationMenu()),
                 this, SIGNAL(showOperationMenu()));
        connect(titlebar, SIGNAL(doShade()),
                 this, SLOT(showShaded()));
        connect(titlebar, SIGNAL(doubleClicked()),
                 this, SLOT(titleBarDoubleClicked()));
    }

    setMinimumSize(128, 0);
    int fw =  style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
    setContentsMargins(fw, fw, fw, fw);

    childWidget = window;
    if (!childWidget)
        return;

    setWindowTitle(childWidget->windowTitle());

    QPoint p;
    QSize s;
    QSize cs;

    bool hasBeenResized = childWidget->testAttribute(Qt::WA_Resized);

    if (!hasBeenResized)
        cs = childWidget->sizeHint().expandedTo(childWidget->minimumSizeHint()).expandedTo(childWidget->minimumSize()).boundedTo(childWidget->maximumSize());
    else
        cs = childWidget->size();

    windowSize = cs;

    int th = titlebar ? titlebar->sizeHint().height() : 0;
    if (titlebar) {
        if (!childWidget->windowIcon().isNull())
            titlebar->setWindowIcon(childWidget->windowIcon());

        if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
            th -= contentsRect().y();

        p = QPoint(contentsRect().x(),
                    th + contentsRect().y());
        s = QSize(cs.width() + 2*frameWidth(),
                   cs.height() + 2*frameWidth() + th);
    } else {
        p = QPoint(contentsRect().x(), contentsRect().y());
        s = QSize(cs.width() + 2*frameWidth(),
                   cs.height() + 2*frameWidth());
    }

    childWidget->move(p);
    resize(s);

    childWidget->installEventFilter(this);

    widgetResizeHandler = new QWidgetResizeHandler(this, window);
    widgetResizeHandler->setSizeProtection(!parent->scrollBarsEnabled());
    widgetResizeHandler->setFrameWidth(frameWidth());
    connect(widgetResizeHandler, SIGNAL(activate()),
             this, SLOT(activate()));
    if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
        widgetResizeHandler->setExtraHeight(th + contentsRect().y() - 2*frameWidth());
    else
        widgetResizeHandler->setExtraHeight(th + contentsRect().y() - frameWidth());
    if (childWidget->minimumSize() == childWidget->maximumSize())
        widgetResizeHandler->setActive(QWidgetResizeHandler::Resize, false);
    setBaseSize(baseSize());
}

QWorkspaceChild::~QWorkspaceChild()
{
    QWorkspace *workspace = qobject_cast<QWorkspace*>(parentWidget());
    if (iconw) {
        if (workspace)
            workspace->d_func()->removeIcon(iconw->parentWidget());
        delete iconw->parentWidget();
    }

    if (workspace) {
        workspace->d_func()->focus.removeAll(this);
        if (workspace->d_func()->active == this)
            workspace->activatePreviousWindow();
        if (workspace->d_func()->active == this)
            workspace->d_func()->activateWindow(0);
        if (workspace->d_func()->maxWindow == this) {
            workspace->d_func()->hideMaximizeControls();
            workspace->d_func()->maxWindow = 0;
        }
    }
}

void QWorkspaceChild::moveEvent(QMoveEvent *)
{
    ((QWorkspace*)parentWidget())->d_func()->updateWorkspace();
}

void QWorkspaceChild::resizeEvent(QResizeEvent *)
{
    bool wasMax = isMaximized();
    QRect r = contentsRect();
    QRect cr;

    updateMask();

    if (titlebar) {
        int th = titlebar->sizeHint().height();
        QRect tbrect(0, 0, width(), th);
        if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
            tbrect = QRect(r.x(), r.y(), r.width(), th);
        titlebar->setGeometry(tbrect);

        if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
            th -= frameWidth();
        cr = QRect(r.x(), r.y() + th + (shademode ? (frameWidth() * 3) : 0),
                    r.width(), r.height() - th);
    } else {
        cr = r;
    }

    if (!childWidget)
        return;

    bool doContentsResize = (windowSize == childWidget->size()
                             || !(childWidget->testAttribute(Qt::WA_Resized) && childWidget->testAttribute(Qt::WA_PendingResizeEvent))
                             ||childWidget->isMaximized());

    windowSize = cr.size();
    childWidget->move(cr.topLeft());
    if (doContentsResize)
        childWidget->resize(cr.size());
    ((QWorkspace*)parentWidget())->d_func()->updateWorkspace();

    if (wasMax) {
        overrideWindowState(Qt::WindowMaximized);
        childWidget->overrideWindowState(Qt::WindowMaximized);
    }
}

QSize QWorkspaceChild::baseSize() const
{
    int th = titlebar ? titlebar->sizeHint().height() : 0;
    if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
        th -= frameWidth();
    return QSize(2*frameWidth(), 2*frameWidth() + th);
}

QSize QWorkspaceChild::sizeHint() const
{
    if (!childWidget)
        return QWidget::sizeHint() + baseSize();

    QSize prefSize = windowWidget()->sizeHint().expandedTo(windowWidget()->minimumSizeHint());
    prefSize = prefSize.expandedTo(windowWidget()->minimumSize()).boundedTo(windowWidget()->maximumSize());
    prefSize += baseSize();

    return prefSize;
}

QSize QWorkspaceChild::minimumSizeHint() const
{
    if (!childWidget)
        return QWidget::minimumSizeHint() + baseSize();
    QSize s = childWidget->minimumSize();
    if (s.isEmpty())
        s = childWidget->minimumSizeHint();
    return s + baseSize();
}

void QWorkspaceChild::activate()
{
    ((QWorkspace*)parentWidget())->d_func()->activateWindow(windowWidget());
}

bool QWorkspaceChild::eventFilter(QObject * o, QEvent * e)
{
    if (!isActive()
        && (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::FocusIn)) {
        if (iconw) {
            ((QWorkspace*)parentWidget())->d_func()->normalizeWindow(windowWidget());
            if (iconw) {
                ((QWorkspace*)parentWidget())->d_func()->removeIcon(iconw->parentWidget());
                delete iconw->parentWidget();
                iconw = 0;
            }
        }
        activate();
    }

    // for all widgets except the window, that's the only thing we
    // process, and if we have no childWidget we skip totally
    if (o != childWidget || childWidget == 0)
        return false;

    switch (e->type()) {
    case QEvent::ShowToParent:
        if (((QWorkspace*)parentWidget())->d_func()->focus.indexOf(this) < 0)
            ((QWorkspace*)parentWidget())->d_func()->focus.append(this);

        if (windowWidget() && (windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)) {
            internalRaise();
            show();
        }
        ((QWorkspace*)parentWidget())->d_func()->showWindow(windowWidget());
        break;
    case QEvent::WindowStateChange: {
        if (static_cast<QWindowStateChangeEvent*>(e)->isOverride())
            break;
        Qt::WindowStates state = windowWidget()->windowState();

        if (state & Qt::WindowMinimized) {
            ((QWorkspace*)parentWidget())->d_func()->minimizeWindow(windowWidget());
        } else if (state & Qt::WindowMaximized) {
            if (windowWidget()->maximumSize().isValid() &&
                (windowWidget()->maximumWidth() < parentWidget()->width() ||
                 windowWidget()->maximumHeight() < parentWidget()->height())) {
                windowWidget()->resize(windowWidget()->maximumSize());
                windowWidget()->overrideWindowState(Qt::WindowNoState);
                if (titlebar)
                    titlebar->update();
                break;
            }
            if ((windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint))
                ((QWorkspace*)parentWidget())->d_func()->maximizeWindow(windowWidget());
            else
                ((QWorkspace*)parentWidget())->d_func()->normalizeWindow(windowWidget());
        } else {
            ((QWorkspace*)parentWidget())->d_func()->normalizeWindow(windowWidget());
            if (iconw) {
                ((QWorkspace*)parentWidget())->d_func()->removeIcon(iconw->parentWidget());
                delete iconw->parentWidget();
            }
        }
    } break;
    case QEvent::HideToParent:
    {
        QWidget * w = iconw;
        if (w && (w = w->parentWidget())) {
            ((QWorkspace*)parentWidget())->d_func()->removeIcon(w);
            delete w;
        }
        ((QWorkspace*)parentWidget())->d_func()->hideChild(this);
    } break;
    case QEvent::WindowIconChange:
        {
            QWorkspace* ws = (QWorkspace*)parentWidget();
            if (ws->d_func()->maxtools && ws->d_func()->maxWindow == this) {
                int iconSize = ws->d_func()->maxtools->size().height();
                ws->d_func()->maxtools->setPixmap(childWidget->windowIcon().pixmap(QSize(iconSize, iconSize)));
            }
        }
        // fall through
    case QEvent::WindowTitleChange:
        setWindowTitle(windowWidget()->windowTitle());
        if (titlebar)
            titlebar->update();
        if (iconw)
            iconw->update();
        break;
    case QEvent::ModifiedChange:
        setWindowModified(windowWidget()->isWindowModified());
        if (titlebar)
            titlebar->update();
        if (iconw)
            iconw->update();
        break;
    case QEvent::Resize:
        {
            QResizeEvent* re = (QResizeEvent*)e;
            if (re->size() != windowSize && !shademode) {
                resize(re->size() + baseSize());
                childWidget->update(); //workaround
            }
        }
        break;

    case QEvent::WindowDeactivate:
        if (titlebar && titlebar->isActive()) {
            update();
        }
        break;

    case QEvent::WindowActivate:
        if (titlebar && titlebar->isActive()) {
            update();
        }
        break;

    default:
        break;
    }

    return QWidget::eventFilter(o, e);
}

void QWorkspaceChild::childEvent(QChildEvent* e)
{
    if (e->type() == QEvent::ChildRemoved && e->child() == childWidget) {
        childWidget = 0;
        if (iconw) {
            ((QWorkspace*)parentWidget())->d_func()->removeIcon(iconw->parentWidget());
            delete iconw->parentWidget();
        }
        close();
    }
}


void QWorkspaceChild::doResize()
{
    widgetResizeHandler->doResize();
}

void QWorkspaceChild::doMove()
{
    widgetResizeHandler->doMove();
}

void QWorkspaceChild::enterEvent(QEvent *)
{
}

void QWorkspaceChild::leaveEvent(QEvent *)
{
#ifndef QT_NO_CURSOR
    if (!widgetResizeHandler->isButtonDown())
        setCursor(Qt::ArrowCursor);
#endif
}

void QWorkspaceChild::paintEvent(QPaintEvent *)
{
    QPainter p(this);
    QStyleOptionFrame opt;
    opt.rect = rect();
    opt.palette = palette();
    opt.state = QStyle::State_None;
    opt.lineWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
    opt.midLineWidth = 1;

    if (titlebar && titlebar->isActive() && isActiveWindow())
        opt.state |= QStyle::State_Active;

    style()->drawPrimitive(QStyle::PE_FrameWindow, &opt, &p, this);
}

void QWorkspaceChild::changeEvent(QEvent *ev)
{
    if(ev->type() == QEvent::StyleChange) {
        resizeEvent(0);
        if (iconw) {
            QFrame *frame = qobject_cast<QFrame*>(iconw->parentWidget());
            Q_ASSERT(frame);
            if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) {
                frame->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
                frame->resize(196+2*frame->frameWidth(), 20 + 2*frame->frameWidth());
            } else {
                frame->resize(196, 20);
            }
        }
        updateMask();
    }
    QWidget::changeEvent(ev);
}

void QWorkspaceChild::setActive(bool b)
{
    if (!childWidget)
        return;

    bool hasFocus = isChildOf(window()->focusWidget(), this);
    if (act == b && (act == hasFocus))
        return;

    act = b;

    if (titlebar)
        titlebar->setActive(act);
    if (iconw)
        iconw->setActive(act);
    update();

    QList<QWidget*> wl = qFindChildren<QWidget*>(childWidget);
    if (act) {
        for (int i = 0; i < wl.size(); ++i) {
            QWidget *w = wl.at(i);
            w->removeEventFilter(this);
        }
        if (!hasFocus) {
            QWidget *lastfocusw = childWidget->focusWidget();
            if (lastfocusw && lastfocusw->focusPolicy() != Qt::NoFocus) {
                lastfocusw->setFocus();
            } else if (childWidget->focusPolicy() != Qt::NoFocus) {
                childWidget->setFocus();
            } else {
                // find something, anything, that accepts focus, and use that.
                for (int i = 0; i < wl.size(); ++i) {
                    QWidget *w = wl.at(i);
                    if(w->focusPolicy() != Qt::NoFocus) {
                        w->setFocus();
                        hasFocus = true;
                        break;
                    }
                }
                if (!hasFocus)
                    setFocus();
            }
        }
    } else {
        for (int i = 0; i < wl.size(); ++i) {
            QWidget *w = wl.at(i);
            w->removeEventFilter(this);
            w->installEventFilter(this);
        }
    }
}

bool QWorkspaceChild::isActive() const
{
    return act;
}

QWidget* QWorkspaceChild::windowWidget() const
{
    return childWidget;
}

bool QWorkspaceChild::isWindowOrIconVisible() const
{
    return childWidget && (!isHidden()  || (iconw && !iconw->isHidden()));
}

void QWorkspaceChild::updateMask()
{
    QStyleOptionTitleBar titleBarOptions;
    titleBarOptions.rect = rect();
    titleBarOptions.titleBarFlags = windowFlags();
    titleBarOptions.titleBarState = windowState();

    QStyleHintReturnMask frameMask;
    if (style()->styleHint(QStyle::SH_WindowFrame_Mask, &titleBarOptions, this, &frameMask)) {
        setMask(frameMask.region);
    } else if (!mask().isEmpty()) {
        clearMask();
    }

    if (iconw) {
        QFrame *frame = qobject_cast<QFrame *>(iconw->parentWidget());
        Q_ASSERT(frame);

        titleBarOptions.rect = frame->rect();
        titleBarOptions.titleBarFlags = frame->windowFlags();
        titleBarOptions.titleBarState = frame->windowState() | Qt::WindowMinimized;
        if (style()->styleHint(QStyle::SH_WindowFrame_Mask, &titleBarOptions, frame, &frameMask)) {
            frame->setMask(frameMask.region);
        } else if (!frame->mask().isEmpty()) {
            frame->clearMask();
        }
    }
}

QWidget* QWorkspaceChild::iconWidget() const
{
    if (!iconw) {
        QWorkspaceChild* that = (QWorkspaceChild*) this;

        QFrame* frame = new QFrame(that, Qt::Window);
        QVBoxLayout *vbox = new QVBoxLayout(frame);
        vbox->setMargin(0);
        QWorkspaceTitleBar *tb = new QWorkspaceTitleBar(windowWidget(), frame);
        vbox->addWidget(tb);
        tb->setObjectName(QLatin1String("_workspacechild_icon_"));
        QStyleOptionTitleBar opt;
        tb->initStyleOption(&opt);
        int th = style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt, tb);
        int iconSize = style()->pixelMetric(QStyle::PM_MdiSubWindowMinimizedWidth, 0, this);
        if (!style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar)) {
            frame->setFrameStyle(QFrame::StyledPanel | QFrame::Raised);
            frame->resize(iconSize+2*frame->frameWidth(), th+2*frame->frameWidth());
        } else {
            frame->resize(iconSize, th);
        }

        that->iconw = tb;
        that->updateMask();
        iconw->setActive(isActive());

        connect(iconw, SIGNAL(doActivate()),
                 this, SLOT(activate()));
        connect(iconw, SIGNAL(doClose()),
                 windowWidget(), SLOT(close()));
        connect(iconw, SIGNAL(doNormal()),
                 this, SLOT(showNormal()));
        connect(iconw, SIGNAL(doMaximize()),
                 this, SLOT(showMaximized()));
        connect(iconw, SIGNAL(popupOperationMenu(QPoint)),
                 this, SIGNAL(popupOperationMenu(QPoint)));
        connect(iconw, SIGNAL(showOperationMenu()),
                 this, SIGNAL(showOperationMenu()));
        connect(iconw, SIGNAL(doubleClicked()),
                 this, SLOT(titleBarDoubleClicked()));
    }
    if (windowWidget()) {
        iconw->setWindowTitle(windowWidget()->windowTitle());
    }
    return iconw->parentWidget();
}

void QWorkspaceChild::showMinimized()
{
    windowWidget()->setWindowState(Qt::WindowMinimized | (windowWidget()->windowState() & ~Qt::WindowMaximized));
}

void QWorkspaceChild::showMaximized()
{
    windowWidget()->setWindowState(Qt::WindowMaximized | (windowWidget()->windowState() & ~Qt::WindowMinimized));
}

void QWorkspaceChild::showNormal()
{
    windowWidget()->setWindowState(windowWidget()->windowState() & ~(Qt::WindowMinimized|Qt::WindowMaximized));
}

void QWorkspaceChild::showShaded()
{
    if (!titlebar)
        return;
    ((QWorkspace*)parentWidget())->d_func()->activateWindow(windowWidget());
    QWidget* w = windowWidget();
    if (shademode) {
        w->overrideWindowState(Qt::WindowNoState);
        overrideWindowState(Qt::WindowNoState);

        shademode = false;
        resize(shadeRestore.expandedTo(minimumSizeHint()));
        setMinimumSize(shadeRestoreMin);
        style()->polish(this);
    } else {
        shadeRestore = size();
        shadeRestoreMin = minimumSize();
        setMinimumHeight(0);
        shademode = true;
        w->overrideWindowState(Qt::WindowMinimized);
        overrideWindowState(Qt::WindowMinimized);

        if (style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar))
            resize(width(), titlebar->height());
        else
            resize(width(), titlebar->height() + 2*frameWidth() + 1);
        style()->polish(this);
    }
    titlebar->update();
}

void QWorkspaceChild::titleBarDoubleClicked()
{
    if (!windowWidget())
        return;
    if (iconw)
        showNormal();
    else if (windowWidget()->windowFlags() & Qt::WindowShadeButtonHint)
            showShaded();
    else if (windowWidget()->windowFlags() & Qt::WindowMaximizeButtonHint)
        showMaximized();
}

void QWorkspaceChild::adjustToFullscreen()
{
    if (!childWidget)
        return;

    if(!((QWorkspace*)parentWidget())->d_func()->maxmenubar || style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, this)) {
        setGeometry(parentWidget()->rect());
    } else {
        int fw =  style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, 0, this);
        bool noBorder = style()->styleHint(QStyle::SH_TitleBar_NoBorder, 0, titlebar);
        int th = titlebar ? titlebar->sizeHint().height() : 0;
        int w = parentWidget()->width() + 2*fw;
        int h = parentWidget()->height() + (noBorder ? fw : 2*fw) + th;
        w = qMax(w, childWidget->minimumWidth());
        h = qMax(h, childWidget->minimumHeight());
        setGeometry(-fw, (noBorder ? 0 : -fw) - th, w, h);
    }
    childWidget->overrideWindowState(Qt::WindowMaximized);
    overrideWindowState(Qt::WindowMaximized);
}

void QWorkspaceChild::internalRaise()
{

    QWidget *stackUnderWidget = 0;
    if (!windowWidget() || (windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint) == 0) {

        QList<QWorkspaceChild *>::Iterator it(((QWorkspace*)parent())->d_func()->windows.begin());
        while (it != ((QWorkspace*)parent())->d_func()->windows.end()) {
            QWorkspaceChild* c = *it;
            ++it;
            if (c->windowWidget() &&
                !c->windowWidget()->isHidden() &&
                (c->windowWidget()->windowFlags() & Qt::WindowStaysOnTopHint)) {
                if (stackUnderWidget)
                    c->stackUnder(stackUnderWidget);
                else
                    c->raise();
                stackUnderWidget = c;
            }
        }
    }

    if (stackUnderWidget) {
        if (iconw)
            iconw->parentWidget()->stackUnder(stackUnderWidget);
        stackUnder(stackUnderWidget);
    } else {
        if (iconw)
            iconw->parentWidget()->raise();
        raise();
    }

}

void QWorkspaceChild::show()
{
    if (childWidget && childWidget->isHidden())
        childWidget->show();
    QWidget::show();
}

bool QWorkspace::scrollBarsEnabled() const
{
    Q_D(const QWorkspace);
    return d->vbar != 0;
}

/*!
    \property QWorkspace::scrollBarsEnabled
    \brief whether the workspace provides scroll bars

    If this property is true, the workspace will provide scroll bars if any
    of the child windows extend beyond the edges of the visible
    workspace. The workspace area will automatically increase to
    contain child windows if they are resized beyond the right or
    bottom edges of the visible area.

    If this property is false (the default), resizing child windows
    out of the visible area of the workspace is not permitted, although
    it is still possible to position them partially outside the visible area.
*/
void QWorkspace::setScrollBarsEnabled(bool enable)
{
    Q_D(QWorkspace);
    if ((d->vbar != 0) == enable)
        return;

    d->xoffset = d->yoffset = 0;
    if (enable) {
        d->vbar = new QScrollBar(Qt::Vertical, this);
        d->vbar->setObjectName(QLatin1String("vertical scrollbar"));
        connect(d->vbar, SIGNAL(valueChanged(int)), this, SLOT(_q_scrollBarChanged()));
        d->hbar = new QScrollBar(Qt::Horizontal, this);
        d->hbar->setObjectName(QLatin1String("horizontal scrollbar"));
        connect(d->hbar, SIGNAL(valueChanged(int)), this, SLOT(_q_scrollBarChanged()));
        d->corner = new QWidget(this);
        d->corner->setBackgroundRole(QPalette::Window);
        d->corner->setObjectName(QLatin1String("qt_corner"));
        d->updateWorkspace();
    } else {
        delete d->vbar;
        delete d->hbar;
        delete d->corner;
        d->vbar = d->hbar = 0;
        d->corner = 0;
    }

    QList<QWorkspaceChild *>::Iterator it(d->windows.begin());
    while (it != d->windows.end()) {
        QWorkspaceChild *child = *it;
        ++it;
        child->widgetResizeHandler->setSizeProtection(!enable);
    }
}

QRect QWorkspacePrivate::updateWorkspace()
{
    Q_Q(QWorkspace);
    QRect cr(q->rect());

    if (q->scrollBarsEnabled() && !maxWindow) {
        corner->raise();
        vbar->raise();
        hbar->raise();
        if (maxWindow)
            maxWindow->internalRaise();

        QRect r(0, 0, 0, 0);
        QList<QWorkspaceChild *>::Iterator it(windows.begin());
        while (it != windows.end()) {
            QWorkspaceChild *child = *it;
            ++it;
            if (!child->isHidden())
                r = r.unite(child->geometry());
        }
        vbar->blockSignals(true);
        hbar->blockSignals(true);

        int hsbExt = hbar->sizeHint().height();
        int vsbExt = vbar->sizeHint().width();


        bool showv = yoffset || yoffset + r.bottom() - q->height() + 1 > 0 || yoffset + r.top() < 0;
        bool showh = xoffset || xoffset + r.right() - q->width() + 1 > 0 || xoffset + r.left() < 0;

        if (showh && !showv)
            showv = yoffset + r.bottom() - q->height() + hsbExt + 1 > 0;
        if (showv && !showh)
            showh = xoffset + r.right() - q->width() + vsbExt  + 1 > 0;

        if (!showh)
            hsbExt = 0;
        if (!showv)
            vsbExt = 0;

        if (showv) {
            vbar->setSingleStep(qMax(q->height() / 12, 30));
            vbar->setPageStep(q->height() - hsbExt);
            vbar->setMinimum(qMin(0, yoffset + qMin(0, r.top())));
            vbar->setMaximum(qMax(0, yoffset + qMax(0, r.bottom() - q->height() + hsbExt + 1)));
            vbar->setGeometry(q->width() - vsbExt, 0, vsbExt, q->height() - hsbExt);
            vbar->setValue(yoffset);
            vbar->show();
        } else {
            vbar->hide();
        }

        if (showh) {
            hbar->setSingleStep(qMax(q->width() / 12, 30));
            hbar->setPageStep(q->width() - vsbExt);
            hbar->setMinimum(qMin(0, xoffset + qMin(0, r.left())));
            hbar->setMaximum(qMax(0, xoffset + qMax(0, r.right() - q->width() + vsbExt  + 1)));
            hbar->setGeometry(0, q->height() - hsbExt, q->width() - vsbExt, hsbExt);
            hbar->setValue(xoffset);
            hbar->show();
        } else {
            hbar->hide();
        }

        if (showh && showv) {
            corner->setGeometry(q->width() - vsbExt, q->height() - hsbExt, vsbExt, hsbExt);
            corner->show();
        } else {
            corner->hide();
        }

        vbar->blockSignals(false);
        hbar->blockSignals(false);

        cr.setRect(0, 0, q->width() - vsbExt, q->height() - hsbExt);
    }

    QList<QWidget *>::Iterator ii(icons.begin());
    while (ii != icons.end()) {
        QWidget* w = *ii;
        ++ii;
        int x = w->x();
        int y = w->y();
        bool m = false;
        if (x+w->width() > cr.width()) {
            m = true;
            x =  cr.width() - w->width();
        }
        if (y+w->height() >  cr.height()) {
            y =  cr.height() - w->height();
            m = true;
        }
        if (m) {
            if (QWorkspaceChild *child = qobject_cast<QWorkspaceChild*>(w))
                child->move(x, y);
            else
                w->move(x, y);
        }
    }

    return cr;

}

void QWorkspacePrivate::_q_scrollBarChanged()
{
    int ver = yoffset - vbar->value();
    int hor = xoffset - hbar->value();
    yoffset = vbar->value();
    xoffset = hbar->value();

    QList<QWorkspaceChild *>::Iterator it(windows.begin());
    while (it != windows.end()) {
        QWorkspaceChild *child = *it;
        ++it;
        // we do not use move() due to the reimplementation in QWorkspaceChild
        child->setGeometry(child->x() + hor, child->y() + ver, child->width(), child->height());
    }
    updateWorkspace();
}

/*!
    \enum QWorkspace::WindowOrder

    Specifies the order in which child windows are returned from windowList().

    \value CreationOrder The windows are returned in the order of their creation
    \value StackingOrder The windows are returned in the order of their stacking
*/

/*!\reimp */
void QWorkspace::changeEvent(QEvent *ev)
{
    Q_D(QWorkspace);
    if(ev->type() == QEvent::StyleChange) {
        if (isVisible() && d->maxWindow && d->maxmenubar) {
            if(style()->styleHint(QStyle::SH_Workspace_FillSpaceOnMaximize, 0, this)) {
                d->hideMaximizeControls(); //hide any visible maximized controls
                d->showMaximizeControls(); //updates the modification state as well
            }
        }
    }
    QWidget::changeEvent(ev);
}

QT_END_NAMESPACE

#include "moc_qworkspace.cpp"

#include "qworkspace.moc"

#endif // QT_NO_WORKSPACE
