/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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, Digia gives you certain additional
** rights.  These rights are described in the Digia 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.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qcursor.h"
#include "qapplication.h"
#include "qapplication_p.h"
#include "qpainter.h"
#include "qbitmap.h"
#include "qimage.h"
#include "qhash.h"
#include "qstack.h"
#include "qlayout.h"
#include "qtextcodec.h"
#include "qinputcontext.h"
#include "qdesktopwidget.h"

#include "qwsdisplay_qws.h"
#include "private/qwsdisplay_qws_p.h"
#include "qscreen_qws.h"
#include "qwsmanager_qws.h"
#include <private/qwsmanager_p.h>
#include <private/qbackingstore_p.h>
#include <private/qwindowsurface_qws_p.h>
#include <private/qwslock_p.h>
#include "qpaintengine.h"

#include "qdebug.h"

#include "qwidget_p.h"

QT_BEGIN_NAMESPACE

QT_USE_NAMESPACE

extern int *qt_last_x;
extern int *qt_last_y;
extern WId qt_last_cursor;
extern bool qws_overrideCursor;
extern QWidget *qt_pressGrab;
extern QWidget *qt_mouseGrb;

static QWidget *keyboardGrb = 0;

static int takeLocalId()
{
    static int n=-1000;
    return --n;
}

class QWSServer;
extern QWSServer *qwsServer;

static inline bool isServerProcess()
{
    return (qwsServer != 0);
}

/*****************************************************************************
  QWidget member functions
 *****************************************************************************/

void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool /*destroyOldWindow*/)
{
    Q_Q(QWidget);
    Qt::WindowType type = q->windowType();

    // Make sure the WindowTitleHint is on if any of the title bar hints are set
    // Note: This might be moved to cross-platform QWidgetPrivate::adjustFlags()
    if (  !(data.window_flags & Qt::CustomizeWindowHint) && (
           (data.window_flags & Qt::WindowSystemMenuHint) ||
           (data.window_flags & Qt::WindowContextHelpButtonHint) ||
           (data.window_flags & Qt::WindowMinimizeButtonHint) ||
           (data.window_flags & Qt::WindowMaximizeButtonHint) ||
           (data.window_flags & Qt::WindowCloseButtonHint) ) ) {
        data.window_flags |= Qt::WindowTitleHint;
    }

    // Decoration plugins on QWS don't support switching on the close button on its own
    if (data.window_flags & Qt::WindowCloseButtonHint)
        data.window_flags |= Qt::WindowSystemMenuHint;

    Qt::WindowFlags flags = data.window_flags;

    data.alloc_region_index = -1;

    // we don't have a "Drawer" window type
    if (type == Qt::Drawer) {
        type = Qt::Widget;
        flags &= ~Qt::WindowType_Mask;
    }


    bool topLevel = (flags & Qt::Window);
    bool popup = (type == Qt::Popup);
    bool dialog = (type == Qt::Dialog
                   || type == Qt::Sheet
                   || (flags & Qt::MSWindowsFixedSizeDialogHint));
    bool desktop = (type == Qt::Desktop);
    bool tool = (type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip);


#ifndef QT_NO_WARNING_OUTPUT
    static bool toolWarningShown = false;
    if (!toolWarningShown && type == Qt::Tool && !(flags & Qt::FramelessWindowHint)) {
        qWarning("Qt for Embedded Linux " QT_VERSION_STR " does not support tool windows with frames.\n"
                 "This behavior will change in a later release. To ensure compatibility with\n"
                 "future versions, use (Qt::Tool | Qt::FramelessWindowHint).");
        toolWarningShown = true;
    }
#endif

    WId           id;
    QWSDisplay* dpy = QWidget::qwsDisplay();

    if (!window)                                // always initialize
        initializeWindow = true;

    // use the size of the primary screen to determine the default window size
    QList<QScreen *> screens = qt_screen->subScreens();
    if (screens.isEmpty())
        screens.append(qt_screen);
    int sw = screens[0]->width();
    int sh = screens[0]->height();

    if (desktop) {                                // desktop widget
        dialog = popup = false;                        // force these flags off
        data.crect.setRect(0, 0, sw, sh);
    } else if (topLevel && !q->testAttribute(Qt::WA_Resized)) {
        int width = sw / 2;
        int height = 4 * sh / 10;
        if (extra) {
            width = qMax(qMin(width, extra->maxw), extra->minw);
            height = qMax(qMin(height, extra->maxh), extra->minh);
        }
        data.crect.setSize(QSize(width, height));
    }

    if (window) {                                // override the old window
        id = window;
        setWinId(window);
    } else if (desktop) {                        // desktop widget
        id = (WId)-2;                                // id = root window
#if 0
        QWidget *otherDesktop = q->find(id);        // is there another desktop?
        if (otherDesktop && otherDesktop->testWFlags(Qt::WPaintDesktop)) {
            otherDesktop->d_func()->setWinId(0);        // remove id from widget mapper
            setWinId(id);                        // make sure otherDesktop is
            otherDesktop->d_func()->setWinId(id);        //   found first
        } else
#endif
        {
            setWinId(id);
        }
    } else {
        id = topLevel ? dpy->takeId() : takeLocalId();
        setWinId(id);                                // set widget id/handle + hd
    }


    bool hasFrame = true;
    if (topLevel) {
        if (desktop || popup || tool || q->testAttribute(Qt::WA_DontShowOnScreen))
            hasFrame = false;
        else
            hasFrame = !(flags & Qt::FramelessWindowHint);
    }
    if (desktop) {
        q->setAttribute(Qt::WA_WState_Visible);
    } else if (topLevel) {                        // set X cursor
        //QCursor *oc = QApplication::overrideCursor();
        if (initializeWindow) {
            //XXX XDefineCursor(dpy, winid, oc ? oc->handle() : cursor().handle());
        }
        QWidget::qwsDisplay()->nameRegion(q->internalWinId(), q->objectName(), q->windowTitle());
    }

    if (topLevel) {
        createTLExtra();
        QTLWExtra *topextra = extra->topextra;
#ifndef QT_NO_QWS_MANAGER
        if (hasFrame) {
            // get size of wm decoration and make the old crect the new frect
            QRect cr = data.crect;
            QRegion r = QApplication::qwsDecoration().region(q, cr) | cr;
            QRect br(r.boundingRect());
            topextra->frameStrut.setCoords(cr.x() - br.x(),
                                                  cr.y() - br.y(),
                                                  br.right() - cr.right(),
                                                  br.bottom() - cr.bottom());
            if (!q->testAttribute(Qt::WA_Moved) || topextra->posFromMove)
                data.crect.translate(topextra->frameStrut.left(), topextra->frameStrut.top());
            if (!topData()->qwsManager) {
                topData()->qwsManager = new QWSManager(q);
                if((q->data->window_state & ~Qt::WindowActive) == Qt::WindowMaximized)
                    topData()->qwsManager->maximize();
            }

        } else if (topData()->qwsManager) {
            delete topData()->qwsManager;
            topData()->qwsManager = 0;
            data.crect.translate(-topextra->frameStrut.left(), -topextra->frameStrut.top());
            topextra->frameStrut.setCoords(0, 0, 0, 0);
        }
#endif
        if (!topextra->caption.isEmpty())
            setWindowTitle_helper(topextra->caption);

        //XXX If we are session managed, inform the window manager about it
    } else {
        if (extra && extra->topextra)        { // already allocated due to reparent?
            extra->topextra->frameStrut.setCoords(0, 0, 0, 0);
        }
        //updateRequestedRegion(mapToGlobal(QPoint(0,0)));
    }
}


void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
{
    Q_D(QWidget);
    d->aboutToDestroy();
    if (!isWindow() && parentWidget())
        parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));

    d->deactivateWidgetCleanup();
    if (testAttribute(Qt::WA_WState_Created)) {
        setAttribute(Qt::WA_WState_Created, false);
        QObjectList childObjects =  children();
        for (int i = 0; i < childObjects.size(); ++i) {
            QObject *obj = childObjects.at(i);
            if (obj->isWidgetType())
                static_cast<QWidget*>(obj)->destroy(destroySubWindows,
                                                     destroySubWindows);
        }
        releaseMouse();
        if (qt_pressGrab == this)
          qt_pressGrab = 0;

        if (keyboardGrb == this)
            releaseKeyboard();
        if (testAttribute(Qt::WA_ShowModal))                // just be sure we leave modal
            QApplicationPrivate::leaveModal(this);
        else if ((windowType() == Qt::Popup))
            qApp->d_func()->closePopup(this);
#ifndef QT_NO_IM
        if (d->ic) {
            delete d->ic;
            d->ic =0;
        } else {
            // release previous focus information participating with
            // preedit preservation of qic -- while we still have a winId
            QInputContext *qic = QApplicationPrivate::inputContext;
            if (qic)
                qic->widgetDestroyed(this);
        }
#endif //QT_NO_IM

        if ((windowType() == Qt::Desktop)) {
        } else {
            if (parentWidget() && parentWidget()->testAttribute(Qt::WA_WState_Created)) {
                d->hide_sys();
            }
            if (destroyWindow && isWindow()) {
                if (d->extra && d->extra->topextra && d->extra->topextra->backingStore)
                    d->extra->topextra->backingStore->windowSurface->setGeometry(QRect());
                qwsDisplay()->destroyRegion(internalWinId());
            }
        }
        QT_TRY {
            d->setWinId(0);
        } QT_CATCH (const std::bad_alloc &) {
            // swallow - destructors must not throw
        }
    }
}


void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
{
    Q_Q(QWidget);
    bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
     if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
        q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
#ifndef QT_NO_CURSOR
    QCursor oldcurs;
    bool setcurs=q->testAttribute(Qt::WA_SetCursor);
    if (setcurs) {
        oldcurs = q->cursor();
        q->unsetCursor();
    }
#endif

    WId old_winid = data.winid;
    if ((q->windowType() == Qt::Desktop))
        old_winid = 0;

    if (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_WState_Created))
        hide_sys();

    setWinId(0);

    if (parent != newparent) {
        QWidget *oldparent = q->parentWidget();
        QObjectPrivate::setParent_helper(newparent);
        if (oldparent) {
//            oldparent->d_func()->setChildrenAllocatedDirty();
//            oldparent->data->paintable_region_dirty = true;
        }
        if (newparent) {
//            newparent->d_func()->setChildrenAllocatedDirty();
//            newparent->data->paintable_region_dirty = true;
            //@@@@@@@
        }
    }
    Qt::FocusPolicy fp = q->focusPolicy();
    QSize    s            = q->size();
    //QBrush   bgc    = background();                        // save colors
    bool explicitlyHidden = q->testAttribute(Qt::WA_WState_Hidden) && q->testAttribute(Qt::WA_WState_ExplicitShowHide);

    data.window_flags = f;
    q->setAttribute(Qt::WA_WState_Created, false);
    q->setAttribute(Qt::WA_WState_Visible, false);
    q->setAttribute(Qt::WA_WState_Hidden, false);
    adjustFlags(data.window_flags, q);
    // keep compatibility with previous versions, we need to preserve the created state
    // (but we recreate the winId for the widget being reparented, again for compatibility)
    if (wasCreated || (!q->isWindow() && newparent->testAttribute(Qt::WA_WState_Created)))
        createWinId();
    if (q->isWindow() || (!newparent || newparent->isVisible()) || explicitlyHidden)
        q->setAttribute(Qt::WA_WState_Hidden);
    q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);

    if (q->isWindow()) {
        QRect fs = frameStrut();
        data.crect = QRect(fs.left(), fs.top(), s.width(), s.height());
        if ((data.window_flags & Qt::FramelessWindowHint) && extra && extra->topextra)
            extra->topextra->frameStrut.setCoords(0, 0, 0, 0);
    } else {
        data.crect = QRect(0, 0, s.width(), s.height());
    }

    q->setFocusPolicy(fp);
    if (extra && !extra->mask.isEmpty()) {
        QRegion r = extra->mask;
        extra->mask = QRegion();
        q->setMask(r);
    }
    if ((int)old_winid > 0) {
        QWidget::qwsDisplay()->destroyRegion(old_winid);
        extra->topextra->backingStore->windowSurface->setGeometry(QRect());
    }
#ifndef QT_NO_CURSOR
    if (setcurs) {
        q->setCursor(oldcurs);
    }
#endif
}


QPoint QWidget::mapToGlobal(const QPoint &pos) const
{
    int           x=pos.x(), y=pos.y();
    const QWidget* w = this;
    while (w) {
        x += w->data->crect.x();
        y += w->data->crect.y();
        w = w->isWindow() ? 0 : w->parentWidget();
    }
    return QPoint(x, y);
}

QPoint QWidget::mapFromGlobal(const QPoint &pos) const
{
    int           x=pos.x(), y=pos.y();
    const QWidget* w = this;
    while (w) {
        x -= w->data->crect.x();
        y -= w->data->crect.y();
        w = w->isWindow() ? 0 : w->parentWidget();
    }
    return QPoint(x, y);
}

#if 0 // #####
void QWidget::setMicroFocusHint(int x, int y, int width, int height,
                                 bool text, QFont *)
{
    if (QRect(x, y, width, height) != microFocusHint()) {
        d->createExtra();
        d->extra->micro_focus_hint.setRect(x, y, width, height);
    }
#ifndef QT_NO_QWS_INPUTMETHODS
    if (text) {
        QWidget *tlw = window();
        int winid = tlw->internalWinId();
        QPoint p(x, y + height);
        QPoint gp = mapToGlobal(p);

        QRect r = QRect(mapToGlobal(QPoint(0,0)),
                         size());

        r.setBottom(tlw->geometry().bottom());

        //qDebug("QWidget::setMicroFocusHint %d %d %d %d", r.x(),
        //        r.y(), r.width(), r.height());
        QInputContext::setMicroFocusWidget(this);

        qwsDisplay()->setIMInfo(winid, gp.x(), gp.y(), r);

        //send font info,  ###if necessary
        qwsDisplay()->setInputFont(winid, font());
    }
#endif
}
#endif

void QWidgetPrivate::updateSystemBackground() {}

#ifndef QT_NO_CURSOR
void QWidgetPrivate::setCursor_sys(const QCursor &cursor)
{
    Q_UNUSED(cursor);
    Q_Q(QWidget);
    if (q->isVisible())
        updateCursor();
}

void QWidgetPrivate::unsetCursor_sys()
{
    Q_Q(QWidget);
    if (q->isVisible())
        updateCursor();
}
#endif //QT_NO_CURSOR

void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
{
    Q_Q(QWidget);
    QWidget::qwsDisplay()->setWindowCaption(q, caption);
}

void QWidgetPrivate::setWindowIcon_sys(bool /*forceReset*/)
{
#if 0
     QTLWExtra* x = d->topData();
     delete x->icon;
     x->icon = 0;
    QBitmap mask;
    if (unscaledPixmap.isNull()) {
    } else {
        QImage unscaledIcon = unscaledPixmap.toImage();
        QPixmap pixmap =
            QPixmap::fromImage(unscaledIcon.scale(16, 16, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
        x->icon = new QPixmap(pixmap);
        mask = pixmap.mask() ? *pixmap.mask() : pixmap.createHeuristicMask();
    }
#endif
}

void QWidgetPrivate::setWindowIconText_sys(const QString &iconText)
{
    Q_UNUSED(iconText);
}

void QWidget::grabMouse()
{
    if (qt_mouseGrb)
        qt_mouseGrb->releaseMouse();

    qwsDisplay()->grabMouse(this,true);

    qt_mouseGrb = this;
    qt_pressGrab = 0;
}

#ifndef QT_NO_CURSOR
void QWidget::grabMouse(const QCursor &cursor)
{
    if (qt_mouseGrb)
        qt_mouseGrb->releaseMouse();

    qwsDisplay()->grabMouse(this,true);
    qwsDisplay()->selectCursor(this, cursor.handle());
    qt_mouseGrb = this;
    qt_pressGrab = 0;
}
#endif

void QWidget::releaseMouse()
{
    if (qt_mouseGrb == this) {
        qwsDisplay()->grabMouse(this,false);
        qt_mouseGrb = 0;
    }
}

void QWidget::grabKeyboard()
{
    if (keyboardGrb)
        keyboardGrb->releaseKeyboard();
    qwsDisplay()->grabKeyboard(this, true);
    keyboardGrb = this;
}

void QWidget::releaseKeyboard()
{
    if (keyboardGrb == this) {
        qwsDisplay()->grabKeyboard(this, false);
        keyboardGrb = 0;
    }
}


QWidget *QWidget::mouseGrabber()
{
    if (qt_mouseGrb)
        return qt_mouseGrb;
    return qt_pressGrab;
}


QWidget *QWidget::keyboardGrabber()
{
    return keyboardGrb;
}

void QWidget::activateWindow()
{
    QWidget *tlw = window();
    if (tlw->isVisible()) {
        Q_ASSERT(tlw->testAttribute(Qt::WA_WState_Created));
        qwsDisplay()->requestFocus(tlw->internalWinId(), true);
    }
}

void QWidgetPrivate::show_sys()
{
    Q_Q(QWidget);
    q->setAttribute(Qt::WA_Mapped);
    if (q->testAttribute(Qt::WA_DontShowOnScreen)) {
        invalidateBuffer(q->rect());
        return;
    }

    if (q->isWindow()) {


        if (!q->testAttribute(Qt::WA_ShowWithoutActivating)
            && q->windowType() != Qt::Popup
            && q->windowType() != Qt::Tool
            && q->windowType() != Qt::ToolTip) {
            QWidget::qwsDisplay()->requestFocus(data.winid,true);
        }


        if (QWindowSurface *surface = q->windowSurface()) {
            const QRect frameRect = q->frameGeometry();
            if (surface->geometry() != frameRect)
                surface->setGeometry(frameRect);
        }

        QRegion r = localRequestedRegion();
#ifndef QT_NO_QWS_MANAGER
        if (extra && extra->topextra && extra->topextra->qwsManager) {
            r.translate(data.crect.topLeft());
            r += extra->topextra->qwsManager->region();
            r.translate(-data.crect.topLeft());
        }
#endif
        data.fstrut_dirty = true;
        invalidateBuffer(r);
	bool staysontop =
            (q->windowFlags() & Qt::WindowStaysOnTopHint)
            || q->windowType() == Qt::Popup;
        if (!staysontop && q->parentWidget()) { // if our parent stays on top, so must we
            QWidget *ptl = q->parentWidget()->window();
            if (ptl && (ptl->windowFlags() & Qt::WindowStaysOnTopHint))
                staysontop = true;
        }

        QWSChangeAltitudeCommand::Altitude altitude;
        altitude = staysontop ? QWSChangeAltitudeCommand::StaysOnTop : QWSChangeAltitudeCommand::Raise;
        QWidget::qwsDisplay()->setAltitude(data.winid, altitude, true);
        if (!q->objectName().isEmpty()) {
            QWidget::qwsDisplay()->setWindowCaption(q, q->windowTitle());
        }
    }
#ifdef Q_BACKINGSTORE_SUBSURFACES
    else if ( extra && extra->topextra && extra->topextra->windowSurface) {
        QWSWindowSurface *surface;
        surface = static_cast<QWSWindowSurface*>(q->windowSurface());
        const QPoint p = q->mapToGlobal(QPoint());
        surface->setGeometry(QRect(p, q->size()));
    }
#endif

    if (!q->window()->data->in_show) {
         invalidateBuffer(q->rect());
    }
}


void QWidgetPrivate::hide_sys()
{
    Q_Q(QWidget);
    deactivateWidgetCleanup();

    if (q->isWindow()) {
        q->releaseMouse();
//        requestWindowRegion(QRegion());

        if (extra->topextra->backingStore)
            extra->topextra->backingStore->releaseBuffer();


        QWidget::qwsDisplay()->requestFocus(data.winid,false);
    } else {
        QWidget *p = q->parentWidget();
        if (p &&p->isVisible()) {
            invalidateBuffer(q->rect());
        }
    }
}



static Qt::WindowStates effectiveState(Qt::WindowStates state)
 {
     if (state & Qt::WindowMinimized)
         return Qt::WindowMinimized;
     else if (state & Qt::WindowFullScreen)
         return Qt::WindowFullScreen;
     else if (state & Qt::WindowMaximized)
         return Qt::WindowMaximized;
     return Qt::WindowNoState;
 }

void QWidgetPrivate::setMaxWindowState_helper()
{
    // in_set_window_state is usually set in setWindowState(), but this
    // function is used in other functions as well
    // (e.g QApplicationPrivate::setMaxWindowRect())
    const uint old_state = data.in_set_window_state;
    data.in_set_window_state = 1;

#ifndef QT_NO_QWS_MANAGER
    if (extra && extra->topextra && extra->topextra->qwsManager)
        extra->topextra->qwsManager->maximize();
    else
#endif
    {
        Q_Q(QWidget);
        const QDesktopWidget *desktop = QApplication::desktop();
        const int screen = desktop->screenNumber(q);
        const QRect maxWindowRect = desktop->availableGeometry(screen);
        q->setGeometry(maxWindowRect);
    }
    data.in_set_window_state = old_state;
}

void QWidgetPrivate::setFullScreenSize_helper()
{
    Q_Q(QWidget);

    const uint old_state = data.in_set_window_state;
    data.in_set_window_state = 1;

    const QRect screen = qApp->desktop()->screenGeometry(qApp->desktop()->screenNumber(q));
    q->move(screen.topLeft());
    q->resize(screen.size());

    data.in_set_window_state = old_state;
}

void QWidget::setWindowState(Qt::WindowStates newstate)
{
    Q_D(QWidget);
    Qt::WindowStates oldstate = windowState();
    if (oldstate == newstate)
        return;
    if (isWindow() && !testAttribute(Qt::WA_WState_Created))
        create();

    data->window_state = newstate;
    data->in_set_window_state = 1;
    bool needShow = false;
    Qt::WindowStates newEffectiveState = effectiveState(newstate);
    Qt::WindowStates oldEffectiveState = effectiveState(oldstate);
    if (isWindow() && newEffectiveState != oldEffectiveState) {
        d->createTLExtra();
        if (oldEffectiveState == Qt::WindowNoState) { //normal
            d->topData()->normalGeometry = geometry();
        } else if (oldEffectiveState == Qt::WindowFullScreen) {
            setParent(0, d->topData()->savedFlags);
            needShow = true;
        } else if (oldEffectiveState == Qt::WindowMinimized) {
            needShow = true;
        }

        if (newEffectiveState == Qt::WindowMinimized) {
            //### not ideal...
            hide();
            needShow = false;
        } else if (newEffectiveState == Qt::WindowFullScreen) {
            d->topData()->savedFlags = windowFlags();
            setParent(0, Qt::FramelessWindowHint | (windowFlags() & Qt::WindowStaysOnTopHint));
            d->setFullScreenSize_helper();
            raise();
            needShow = true;
        } else if (newEffectiveState == Qt::WindowMaximized) {
            createWinId();
            d->setMaxWindowState_helper();
        } else { //normal
            QRect r = d->topData()->normalGeometry;
            if (r.width() >= 0) {
                d->topData()->normalGeometry = QRect(0,0,-1,-1);
                setGeometry(r);
            }
        }
    }
    data->in_set_window_state = 0;

    if (needShow)
        show();

    if (newstate & Qt::WindowActive)
        activateWindow();

    QWindowStateChangeEvent e(oldstate);
    QApplication::sendEvent(this, &e);
}

void QWidgetPrivate::setFocus_sys()
{

}

void QWidgetPrivate::raise_sys()
{
    Q_Q(QWidget);
    //@@@ transaction
    if (q->isWindow()) {
        Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
        QWidget::qwsDisplay()->setAltitude(q->internalWinId(),
                                           QWSChangeAltitudeCommand::Raise);
        // XXX: subsurfaces?
#ifdef QT_NO_WINDOWGROUPHINT
#else
        QObjectList childObjects =  q->children();
        if (!childObjects.isEmpty()) {
            QWidgetList toraise;
            for (int i = 0; i < childObjects.size(); ++i) {
                QObject *obj = childObjects.at(i);
                if (obj->isWidgetType()) {
                    QWidget* w = static_cast<QWidget*>(obj);
                    if (w->isWindow())
                        toraise.append(w);
                }
            }

            for (int i = 0; i < toraise.size(); ++i) {
                QWidget *w = toraise.at(i);
                if (w->isVisible())
                    w->raise();
            }
        }
#endif // QT_NO_WINDOWGROUPHINT
    }
}

void QWidgetPrivate::lower_sys()
{
    Q_Q(QWidget);
    if (q->isWindow()) {
        Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
        QWidget::qwsDisplay()->setAltitude(data.winid,
                                           QWSChangeAltitudeCommand::Lower);
    } else if (QWidget *p = q->parentWidget()) {
        setDirtyOpaqueRegion();
        p->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
    }
}

void QWidgetPrivate::stackUnder_sys(QWidget*)
{
    Q_Q(QWidget);
    if (QWidget *p = q->parentWidget()) {
        setDirtyOpaqueRegion();
        p->d_func()->invalidateBuffer(effectiveRectFor(q->geometry()));
    }
}

void QWidgetPrivate::moveSurface(QWindowSurface *surface, const QPoint &offset)
{
    QWSWindowSurface *s = static_cast<QWSWindowSurface*>(surface);
    if (!s->move(offset))
        s->invalidateBuffer();

    QWSDisplay::instance()->moveRegion(s->winId(), offset.x(), offset.y());
}

void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
{
    Q_Q(QWidget);
    if (extra) {                                // any size restrictions?
        w = qMin(w,extra->maxw);
        h = qMin(h,extra->maxh);
        w = qMax(w,extra->minw);
        h = qMax(h,extra->minh);
    }

    QPoint oldp = q->geometry().topLeft();
    QSize olds = q->size();
    QRect r(x, y, w, h);

    bool isResize = olds != r.size();
    isMove = oldp != r.topLeft(); //### why do we have isMove as a parameter?

    // We only care about stuff that changes the geometry, or may
    // cause the window manager to change its state
    if (r.size() == olds && oldp == r.topLeft())
        return;

    if (!data.in_set_window_state) {
        q->data->window_state &= ~Qt::WindowMaximized;
        q->data->window_state &= ~Qt::WindowFullScreen;
        if (q->isWindow())
            topData()->normalGeometry = QRect(0, 0, -1, -1);
    }
    QPoint oldPos = q->pos();
    data.crect = r;

    if ((q->windowType() == Qt::Desktop))
        return;

    if (q->isVisible()) {

        bool toplevelMove = false;
        QWSWindowSurface *surface = 0;

        if (q->isWindow()) {
            //### ConfigPending not implemented, do we need it?
            //setAttribute(Qt::WA_WState_ConfigPending);
            const QWidgetBackingStore *bs = maybeBackingStore();
            if (bs)
                surface = static_cast<QWSWindowSurface*>(bs->windowSurface);
            if (isMove && !isResize && surface) {
                const QPoint offset(x - oldp.x(), y - oldp.y());
                moveSurface(surface, offset);
                toplevelMove = true; //server moves window, but we must send moveEvent, which might trigger painting

#ifdef Q_BACKINGSTORE_SUBSURFACES
                QList<QWindowSurface*> surfaces = bs->subSurfaces;
                for (int i = 0; i < surfaces.size(); ++i)
                    moveSurface(surfaces.at(i), offset);
#endif
            } else {
                    updateFrameStrut();
            }
        }

        if (!toplevelMove) {
            if (q->isWindow()) {
                if (surface)
                    surface->setGeometry(q->frameGeometry());
                else
                    invalidateBuffer(q->rect()); //###

#ifdef Q_BACKINGSTORE_SUBSURFACES
                // XXX: should not resize subsurfaces. Children within a layout
                // will be resized automatically while children with a static
                // geometry should get a new clip region instead.
                const QRect clipRect = q->geometry();
                QWidgetBackingStore *bs = maybeBackingStore();
                QList<QWindowSurface*> surfaces = bs->subSurfaces;
                for (int i = 0; i < surfaces.size(); ++i) {
                    QWSWindowSurface *s = static_cast<QWSWindowSurface*>(surfaces.at(i));
                    QRect srect = s->geometry();
                    s->setGeometry(clipRect & srect);
                }
#endif
            }
#ifdef Q_BACKINGSTORE_SUBSURFACES
            // XXX: merge this case with the isWindow() case
            else if (maybeTopData() && maybeTopData()->windowSurface) {
                QWSWindowSurface *surface;
                surface = static_cast<QWSWindowSurface*>(q->windowSurface());
                if (isMove && !isResize) {
                    moveSurface(surface, QPoint(x - oldp.x(), y - oldp.y()));
                } else {
                    const QPoint p = q->mapToGlobal(QPoint());
                    surface->setGeometry(QRect(p, QSize(w, h)));
                }
            }
#endif
            else {
                if (isMove && !isResize)
                    moveRect(QRect(oldPos, olds), x - oldPos.x(), y - oldPos.y());
                else
                    invalidateBuffer_resizeHelper(oldPos, olds);
            }
        }

        //### must have frame geometry correct before sending move/resize events
        if (isMove) {
            QMoveEvent e(q->pos(), oldPos);
            QApplication::sendEvent(q, &e);
        }
        if (isResize) {
            QResizeEvent e(r.size(), olds);
            QApplication::sendEvent(q, &e);
        }

    } else { // not visible
        if (isMove && q->pos() != oldPos)
            q->setAttribute(Qt::WA_PendingMoveEvent, true);
        if (isResize)
            q->setAttribute(Qt::WA_PendingResizeEvent, true);
    }
}

void QWidgetPrivate::setConstraints_sys()
{
}

QScreen* QWidgetPrivate::getScreen() const
{
    Q_Q(const QWidget);

    const QList<QScreen*> subScreens = qt_screen->subScreens();
    if (subScreens.isEmpty() || q->windowType() == Qt::Desktop)
        return qt_screen;

    const int screen = QApplication::desktop()->screenNumber(q);

    return qt_screen->subScreens().at(screen < 0 ? 0 : screen);
}

void QWidgetPrivate::scroll_sys(int dx, int dy)
{
    Q_Q(QWidget);
    scrollChildren(dx, dy);
    scrollRect(q->rect(), dx, dy);
}

void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
{
    scrollRect(r, dx, dy);
}

int QWidget::metric(PaintDeviceMetric m) const
{
    Q_D(const QWidget);

    int val;
    if (m == PdmWidth) {
        val = data->crect.width();
    } else if (m == PdmWidthMM) {
        const QScreen *screen = d->getScreen();
        val = data->crect.width() * screen->physicalWidth() / screen->width();
    } else if (m == PdmHeight) {
        val = data->crect.height();
    } else if (m == PdmHeightMM) {
        const QScreen *screen = d->getScreen();
        val = data->crect.height() * screen->physicalHeight() / screen->height();
    } else if (m == PdmDepth) {
        return qwsDisplay()->depth();
    } else if (m == PdmDpiX || m == PdmPhysicalDpiX) {
        if (d->extra && d->extra->customDpiX)
            return d->extra->customDpiX;
        else if (d->parent)
            return static_cast<QWidget *>(d->parent)->metric(m);
        const QScreen *screen = d->getScreen();
        return qRound(screen->width() / double(screen->physicalWidth() / 25.4));
    } else if (m == PdmDpiY || m == PdmPhysicalDpiY) {
        if (d->extra && d->extra->customDpiY)
            return d->extra->customDpiY;
        else if (d->parent)
            return static_cast<QWidget *>(d->parent)->metric(m);
        const QScreen *screen = d->getScreen();
        return qRound(screen->height() / double(screen->physicalHeight() / 25.4));
    } else if (m == PdmNumColors) {
        QScreen *screen = d->getScreen();
        int ret = screen->colorCount();
        if (!ret) {
            const int depth = qwsDisplay()->depth();
            switch (depth) {
            case 1:
                ret = 2;
                break;
            case 8:
                ret = 256;
                break;
            case 16:
                ret = 65536;
                break;
            case 24:
                ret = 16777216;
                break;
            case 32:
                ret = 2147483647;
                break;
            }
        }
        return ret;
    } else {
        val = QPaintDevice::metric(m);// XXX
    }
    return val;
}

void QWidgetPrivate::createSysExtra()
{
}

void QWidgetPrivate::deleteSysExtra()
{
}

void QWidgetPrivate::createTLSysExtra()
{
#ifndef QT_NO_QWS_MANAGER
    extra->topextra->qwsManager = 0;
#endif
}

void QWidgetPrivate::deleteTLSysExtra()
{
}

void QWidgetPrivate::registerDropSite(bool on)
{
    Q_UNUSED(on);
}

QRegion QWidgetPrivate::localRequestedRegion() const
{
    Q_Q(const QWidget);
    QRegion r(q->rect());
    if (extra && !extra->mask.isEmpty())
        r &= extra->mask;

    return r;
}

QRegion QWidgetPrivate::localAllocatedRegion() const
{
    Q_Q(const QWidget);

    QWidgetBackingStore *wbs = q->window()->d_func()->maybeBackingStore();

    QWindowSurface *ws = wbs ? wbs->windowSurface : 0;
    if (!ws)
        return QRegion();
    QRegion r = static_cast<QWSWindowSurface*>(ws)->clipRegion();
    if (!q->isWindow()) {
        QPoint off = q->mapTo(q->window(), QPoint());
        r &= localRequestedRegion().translated(off);
        r.translate(-off);
    }
    return r;
}

inline bool QRect::intersects(const QRect &r) const
{
    return (qMax(x1, r.x1) <= qMin(x2, r.x2) &&
             qMax(y1, r.y1) <= qMin(y2, r.y2));
}

void QWidgetPrivate::setMask_sys(const QRegion &region)
{
    Q_UNUSED(region);
    Q_Q(QWidget);

    if (!q->isVisible() || !q->isWindow())
        return;

    data.fstrut_dirty = true;
    invalidateBuffer(q->rect());
    QWindowSurface *surface = extra->topextra->backingStore->windowSurface;
    if (surface) {
        // QWSWindowSurface::setGeometry() returns without doing anything
        // if old geom  == new geom. Therefore, we need to reset the old value.
        surface->QWindowSurface::setGeometry(QRect());
        surface->setGeometry(q->frameGeometry());
    }
}

void QWidgetPrivate::updateFrameStrut()
{
    Q_Q(QWidget);

    if(!q->isVisible() || (q->windowType() == Qt::Desktop)) {
        data.fstrut_dirty = q->isVisible();
        return;
    }

#ifndef QT_NO_QWS_MANAGER
    if (extra && extra->topextra && extra->topextra->qwsManager) {
        QTLWExtra *topextra = extra->topextra;
        const QRect oldFrameStrut = topextra->frameStrut;
        const QRect contents = data.crect;
        QRegion r = localRequestedRegion().translated(contents.topLeft());
        r += extra->topextra->qwsManager->region();
        const QRect frame = r.boundingRect();

        topextra->frameStrut.setCoords(contents.left() - frame.left(),
                                       contents.top() - frame.top(),
                                       frame.right() - contents.right(),
                                       frame.bottom() - contents.bottom());
        topextra->qwsManager->repaintRegion(QDecoration::All, QDecoration::Normal);
    }
#endif
    data.fstrut_dirty = false;
}

#ifndef QT_NO_CURSOR
void QWidgetPrivate::updateCursor() const
{
    Q_Q(const QWidget);

    if (QApplication::overrideCursor())
        return;

    if (qt_last_x
        && (!QWidget::mouseGrabber() || QWidget::mouseGrabber() == q)
        && qt_last_cursor != (WId)q->cursor().handle())
    {
        const QPoint pos(*qt_last_x, *qt_last_y);
        const QPoint offset = q->mapToGlobal(QPoint());
        if (!localAllocatedRegion().contains(pos - offset))
            return;

        const QWidget *w = q->childAt(q->mapFromGlobal(pos));
        if (!w || w->cursor().handle() == q->cursor().handle())
            QWidget::qwsDisplay()->selectCursor(const_cast<QWidget*>(q),
                                                q->cursor().handle());
    }
}
#endif

void QWidgetPrivate::setWindowOpacity_sys(qreal level)
{
    Q_Q(QWidget);
    Q_UNUSED(level);
    createWinId();
    QWidget::qwsDisplay()->setOpacity(q->data->winid, topData()->opacity);
}

//static QSingleCleanupHandler<QWSPaintEngine> qt_paintengine_cleanup_handler;
//static QWSPaintEngine *qt_widget_paintengine = 0;
QPaintEngine *QWidget::paintEngine() const
{
    qWarning("QWidget::paintEngine: Should no longer be called");
    return 0; //##### @@@
//     if (!qt_widget_paintengine) {
//         qt_widget_paintengine = new QRasterPaintEngine();
//         qt_paintengine_cleanup_handler.set(&qt_widget_paintengine);
//     }
//     if (qt_widget_paintengine->isActive()) {
//         if (d->extraPaintEngine)
//             return d->extraPaintEngine;
//         const_cast<QWidget *>(this)->d_func()->extraPaintEngine = new QRasterPaintEngine();
//         return d->extraPaintEngine;
//     }
//    return qt_widget_paintengine;
}

QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
{
    Q_Q(QWidget);
    if (q->windowType() == Qt::Desktop)
        return 0;
    q->ensurePolished();
    return qt_screen->createSurface(q);
}

void QWidgetPrivate::setModal_sys()
{
}


QT_END_NAMESPACE
