/****************************************************************************
**
** 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$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qplatformdefs.h"

#include "qwindowsystem_qws.h"
#include "qwsevent_qws.h"
#include "qwscommand_qws_p.h"
#include "qtransportauth_qws_p.h"
#include "qwsutils_qws.h"
#include "qwscursor_qws.h"
#include "qwsdisplay_qws.h"
#include "qmouse_qws.h"
#include "qcopchannel_qws.h"
#include "qwssocket_qws.h"

#include "qapplication.h"
#include "private/qapplication_p.h"
#include "qsocketnotifier.h"
#include "qpolygon.h"
#include "qimage.h"
#include "qcursor.h"
#include <private/qpaintengine_raster_p.h>
#include "qscreen_qws.h"
#include "qwindowdefs.h"
#include "private/qlock_p.h"
#include "qwslock_p.h"
#include "qfile.h"
#include "qtimer.h"
#include "qpen.h"
#include "qdesktopwidget.h"
#include "qevent.h"
#include "qinputcontext.h"
#include "qpainter.h"

#include <qdebug.h>

#include "qkbddriverfactory_qws.h"
#include "qmousedriverfactory_qws.h"

#include <qbuffer.h>
#include <qdir.h>

#include <private/qwindowsurface_qws_p.h>
#include <private/qfontengine_qpf_p.h>

#include "qwindowsystem_p.h"


#include <stdlib.h>
#include <stdio.h>
#include <errno.h>

#ifndef QT_NO_QWS_MULTIPROCESS
#include <sys/param.h>
#include <sys/mount.h>
#endif

#if !defined(QT_NO_SOUND) && !defined(Q_OS_DARWIN)
#ifdef QT_USE_OLD_QWS_SOUND
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#else
#include "qsoundqss_qws.h"
#endif
#endif

//#define QWS_DEBUG_FONTCLEANUP

QT_BEGIN_NAMESPACE

QWSServer Q_GUI_EXPORT *qwsServer=0;
static QWSServerPrivate *qwsServerPrivate=0;

#define MOUSE 0
#define KEY 1
//#define EVENT_BLOCK_DEBUG

QWSScreenSaver::~QWSScreenSaver()
{
}

extern QByteArray qws_display_spec;
extern void qt_init_display(); //qapplication_qws.cpp
extern QString qws_qtePipeFilename();

extern void qt_client_enqueue(const QWSEvent *); //qapplication_qws.cpp
extern QList<QWSCommand*> *qt_get_server_queue();

Q_GLOBAL_STATIC_WITH_ARGS(QString, defaultMouse, (QLatin1String("Auto")))
Q_GLOBAL_STATIC_WITH_ARGS(QString, defaultKeyboard, (QLatin1String("TTY")))
static const int FontCleanupInterval = 60 * 1000;

static int qws_keyModifiers = 0;

static QWSWindow *keyboardGrabber;
static bool keyboardGrabbing;

static int get_object_id(int count = 1)
{
    static int next=1000;
    int n = next;
    next += count;
    return n;
}
#ifndef QT_NO_QWS_INPUTMETHODS
static QWSInputMethod *current_IM = 0;

static QWSWindow *current_IM_composing_win = 0;
static int current_IM_winId = -1;
static bool force_reject_strokeIM = false;
#endif

static void cleanupFontsDir();

//#define QWS_REGION_DEBUG

/*!
    \class QWSScreenSaver
    \ingroup qws

    \brief The QWSScreenSaver class is a base class for screensavers
    in Qt for Embedded Linux.

    When running \l{Qt for Embedded Linux} applications, it is the server
    application that installs and controls the screensaver.
    \l{Qt for Embedded Linux} supports multilevel screen saving; i.e., it is possible to
    specify several different levels of screen responsiveness. For
    example, you can choose to first turn off the light before you
    fully activate the screensaver.

    Note that there exists no default screensaver implementation.

    To create a custom screensaver, derive from this class and
    reimplement the restore() and save() functions. These functions
    are called whenever the screensaver is activated or deactivated,
    respectively. Once an instance of your custom screensaver is
    created, you can use the QWSServer::setScreenSaver() function to
    install it.

    \sa QWSServer, QScreen, {Qt for Embedded Linux}
*/

/*!
    \fn QWSScreenSaver::~QWSScreenSaver()

    Reimplement this function to destroy the screensaver.
*/

/*!
    \fn QWSScreenSaver::restore()

    Implement this function to deactivate the screensaver, restoring
    the previously saved screen.

    \sa save(), QWSServer::screenSaverActivate()
*/

/*!
    \fn QWSScreenSaver::save(int level)

    Implement this function to activate the screensaver, saving the
    current screen.

    \l{Qt for Embedded Linux} supports multilevel screen saving; i.e., it is
    possible to specify several different levels of screen
    responsiveness. For example, you can choose to first turn off the
    light before you fully activate the screensaver. Use the
    QWSServer::setScreenSaverIntervals() to specify the time intervals
    between the different levels.

    This function should return true if the screensaver successfully
    enters the given \a level; otherwise it should return false.

    \sa restore(), QWSServer::screenSaverActivate()
*/

class QWSWindowPrivate
{
public:
    QWSWindowPrivate();

#ifdef QT_QWS_CLIENTBLIT
    QRegion directPaintRegion;
#endif
    QRegion allocatedRegion;
#ifndef QT_NO_QWSEMBEDWIDGET
    QList<QWSWindow*> embedded;
    QWSWindow *embedder;
#endif
    QWSWindow::State state;
    Qt::WindowFlags windowFlags;
    QRegion dirtyOnScreen;
    bool painted;
};

QWSWindowPrivate::QWSWindowPrivate()
    :
#ifndef QT_NO_QWSEMBEDWIDGET
    embedder(0), state(QWSWindow::NoState),
#endif
    painted(false)
{
}

/*!
    \class QWSWindow
    \ingroup qws

    \brief The QWSWindow class encapsulates a top-level window in
    Qt for Embedded Linux.

    When you run a \l{Qt for Embedded Linux} application, it either runs as a
    server or connects to an existing server. As applications add and
    remove windows, the server process maintains information about
    each window. In \l{Qt for Embedded Linux}, top-level windows are
    encapsulated as QWSWindow objects. Note that you should never
    construct the QWSWindow class yourself; the current top-level
    windows can be retrieved using the QWSServer::clientWindows()
    function.

    With a window at hand, you can retrieve its caption, name, opacity
    and ID using the caption(), name(), opacity() and winId()
    functions, respectively. Use the client() function to retrieve a
    pointer to the client that owns the window.

    Use the isVisible() function to find out if the window is
    visible. You can find out if the window is completely obscured by
    another window or by the bounds of the screen, using the
    isFullyObscured() function. The isOpaque() function returns true
    if the window has an alpha channel equal to 255. Finally, the
    requestedRegion() function returns the region of the display the
    window wants to draw on.

    \sa QWSServer, QWSClient, {Qt for Embedded Linux Architecture}
*/

/*!
    \fn int QWSWindow::winId() const

    Returns the window's ID.

    \sa name(), caption()
*/

/*!
    \fn const QString &QWSWindow::name() const

    Returns the window's name, which is taken from the \l {QWidget::}{objectName()}
    at the time of \l {QWidget::}{show()}.

    \sa caption(), winId()
*/

/*!
    \fn const QString &QWSWindow::caption() const

    Returns the window's caption.

    \sa name(), winId()
*/

/*!
    \fn QWSClient* QWSWindow::client() const

    Returns a reference to the QWSClient object that owns this window.

    \sa requestedRegion()
*/

/*!
    \fn QRegion QWSWindow::requestedRegion() const

    Returns the region that the window has requested to draw onto,
    including any window decorations.

    \sa client()
*/

/*!
    \fn bool QWSWindow::isVisible() const

    Returns true if the window is visible; otherwise returns false.

    \sa isFullyObscured()
*/

/*!
    \fn bool QWSWindow::isOpaque() const

    Returns true if the window is opaque, i.e., if its alpha channel
    equals 255; otherwise returns false.

    \sa opacity()
*/

/*!
    \fn uint QWSWindow::opacity () const

    Returns the window's alpha channel value.

    \sa isOpaque()
*/

/*!
    \fn bool QWSWindow::isPartiallyObscured() const
    \internal

    Returns true if the window is partially obsured by another window
    or by the bounds of the screen; otherwise returns false.
*/

/*!
    \fn bool QWSWindow::isFullyObscured() const

    Returns true if the window is completely obsured by another window
    or by the bounds of the screen; otherwise returns false.

    \sa isVisible()
*/

/*!
    \fn QWSWindowSurface* QWSWindow::windowSurface() const
    \internal
*/

QWSWindow::QWSWindow(int i, QWSClient* client)
        : id(i), modified(false),
          onTop(false), c(client), last_focus_time(0), _opacity(255),
          opaque(true), d(new QWSWindowPrivate)
{
    surface = 0;
}


/*!
    \enum QWSWindow::State

    This enum describes the state of a window. Most of the
    transitional states are set just before a call to
    QScreen::exposeRegion() and reset immediately afterwards.

    \value NoState Initial state before the window is properly initialized.
    \value Hidden The window is not visible.
    \value Showing The window is being shown.
    \value Visible The window is visible, and not in a transition.
    \value Hiding The window is being hidden.
    \value Raising The windoe is being raised.
    \value Lowering The window is being raised.
    \value Moving The window is being moved.
    \value ChangingGeometry The window's geometry is being changed.
    \value Destroyed  The window is destroyed.

    \sa state(), QScreen::exposeRegion()
*/

/*!
  Returns the current state of the window.

  \since 4.3
*/
QWSWindow::State QWSWindow::state() const
{
    return d->state;
}

/*!
  Returns the window flags of the window. This value is only available
  after the first paint event.

  \since 4.3
*/
Qt::WindowFlags QWSWindow::windowFlags() const
{
    return d->windowFlags;
}

/*!
  Returns the region that has been repainted since the previous
  QScreen::exposeRegion(), and needs to be copied to the screen.
  \since 4.3
*/
QRegion QWSWindow::dirtyOnScreen() const
{
    return d->dirtyOnScreen;
}

void QWSWindow::createSurface(const QString &key, const QByteArray &data)
{
#ifndef QT_NO_QWS_MULTIPROCESS
    if (surface && !surface->isBuffered())
        c->removeUnbufferedSurface();
#endif

    delete surface;
    surface = qt_screen->createSurface(key);
    surface->setPermanentState(data);

#ifndef QT_NO_QWS_MULTIPROCESS
    if (!surface->isBuffered())
        c->addUnbufferedSurface();
#endif
}

/*!
    \internal
    Raises the window above all other windows except "Stay on top" windows.
*/
void QWSWindow::raise()
{
    qwsServerPrivate->raiseWindow(this);
#ifndef QT_NO_QWSEMBEDWIDGET
    const int n = d->embedded.size();
    for (int i = 0; i < n; ++i)
        d->embedded.at(i)->raise();
#endif
}

/*!
    \internal
    Lowers the window below other windows.
*/
void QWSWindow::lower()
{
    qwsServerPrivate->lowerWindow(this);
#ifndef QT_NO_QWSEMBEDWIDGET
    const int n = d->embedded.size();
    for (int i = 0; i < n; ++i)
        d->embedded.at(i)->lower();
#endif
}

/*!
    \internal
    Shows the window.
*/
void QWSWindow::show()
{
    operation(QWSWindowOperationEvent::Show);
#ifndef QT_NO_QWSEMBEDWIDGET
    const int n = d->embedded.size();
    for (int i = 0; i < n; ++i)
        d->embedded.at(i)->show();
#endif
}

/*!
    \internal
    Hides the window.
*/
void QWSWindow::hide()
{
    operation(QWSWindowOperationEvent::Hide);
#ifndef QT_NO_QWSEMBEDWIDGET
    const int n = d->embedded.size();
    for (int i = 0; i < n; ++i)
        d->embedded.at(i)->hide();
#endif
}

/*!
    \internal
    Make this the active window (i.e., sets the keyboard focus to this
    window).
*/
void QWSWindow::setActiveWindow()
{
    qwsServerPrivate->setFocus(this, true);
#ifndef QT_NO_QWSEMBEDWIDGET
    const int n = d->embedded.size();
    for (int i = 0; i < n; ++i)
        d->embedded.at(i)->setActiveWindow();
#endif
}

void QWSWindow::setName(const QString &n)
{
    rgnName = n;
}

/*!
  \internal
  Sets the window's caption to \a c.
*/
void QWSWindow::setCaption(const QString &c)
{
    rgnCaption = c;
}


static int global_focus_time_counter=100;

void QWSWindow::focus(bool get)
{
    if (get)
        last_focus_time = global_focus_time_counter++;
    if (c) {
        QWSFocusEvent event;
        event.simpleData.window = id;
        event.simpleData.get_focus = get;
        c->sendEvent(&event);
    }
}

void QWSWindow::operation(QWSWindowOperationEvent::Operation o)
{
    if (!c)
        return;
    QWSWindowOperationEvent event;
    event.simpleData.window = id;
    event.simpleData.op = o;
    c->sendEvent(&event);
}

/*!
    \internal
    Destructor.
*/
QWSWindow::~QWSWindow()
{
#ifndef QT_NO_QWS_INPUTMETHODS
    if (current_IM_composing_win == this)
        current_IM_composing_win = 0;
#endif
#ifndef QT_NO_QWSEMBEDWIDGET
    QWSWindow *embedder = d->embedder;
    if (embedder) {
        embedder->d->embedded.removeAll(this);
        d->embedder = 0;
    }
    while (!d->embedded.isEmpty())
        stopEmbed(d->embedded.first());
#endif

#ifndef QT_NO_QWS_MULTIPROCESS
    if (surface && !surface->isBuffered()) {
        if (c && c->d_func()) // d_func() will be 0 if client is deleted
            c->removeUnbufferedSurface();
    }
#endif

    delete surface;
    delete d;
}

/*!
    \internal

    Returns the region that the window is allowed to draw onto,
    including any window decorations but excluding regions covered by
    other windows.

    \sa paintedRegion(), requestedRegion()
*/
QRegion QWSWindow::allocatedRegion() const
{
    return d->allocatedRegion;
}

#ifdef QT_QWS_CLIENTBLIT
QRegion QWSWindow::directPaintRegion() const
{
    return d->directPaintRegion;
}

inline void QWSWindow::setDirectPaintRegion(const QRegion &r)
{
    d->directPaintRegion = r;
}
#endif

/*!
    \internal

    Returns the region that the window is known to have drawn into.

    \sa allocatedRegion(), requestedRegion()
*/
QRegion QWSWindow::paintedRegion() const
{
    return (d->painted ? d->allocatedRegion : QRegion());
}

inline void QWSWindow::setAllocatedRegion(const QRegion &region)
{
    d->allocatedRegion = region;
}

#ifndef QT_NO_QWSEMBEDWIDGET
inline void QWSWindow::startEmbed(QWSWindow *w)
{
    d->embedded.append(w);
    w->d->embedder = this;
}

inline void QWSWindow::stopEmbed(QWSWindow *w)
{
    w->d->embedder = 0;
    w->client()->sendEmbedEvent(w->winId(), QWSEmbedEvent::Region, QRegion());
    d->embedded.removeAll(w);
}
#endif // QT_NO_QWSEMBEDWIDGET

/*********************************************************************
 *
 * Class: QWSClient
 *
 *********************************************************************/

class QWSClientPrivate : public QObjectPrivate
{
    Q_DECLARE_PUBLIC(QWSClient)

public:
    QWSClientPrivate();
    ~QWSClientPrivate();

    void setLockId(int id);
    void unlockCommunication();

private:
#ifndef QT_NO_QWS_MULTIPROCESS
    QWSLock *clientLock;
    bool shutdown;
    int numUnbufferedSurfaces;
#endif
    QSet<QByteArray> usedFonts;
    friend class QWSServerPrivate;
};

QWSClientPrivate::QWSClientPrivate()
{
#ifndef QT_NO_QWS_MULTIPROCESS
    clientLock = 0;
    shutdown = false;
    numUnbufferedSurfaces = 0;
#endif
}

QWSClientPrivate::~QWSClientPrivate()
{
#ifndef QT_NO_QWS_MULTIPROCESS
    delete clientLock;
#endif
}

void QWSClientPrivate::setLockId(int id)
{
#ifdef QT_NO_QWS_MULTIPROCESS
    Q_UNUSED(id);
#else
    clientLock = new QWSLock(id);
#endif
}

void QWSClientPrivate::unlockCommunication()
{
#ifndef QT_NO_QWS_MULTIPROCESS
    if (clientLock)
        clientLock->unlock(QWSLock::Communication);
#endif
}

/*!
    \class QWSClient
    \ingroup qws

    \brief The QWSClient class encapsulates a client process in Qt for Embedded Linux.

    When you run a \l{Qt for Embedded Linux} application, it either runs as a
    server or connects to an existing server. The server and client
    processes have different responsibilities: The client process
    performs all application specific operations. The server process
    is responsible for managing the clients as well as taking care of
    the pointer handling, character input, and screen output. In
    addition, the server provides functionality to handle input
    methods.

    As applications add and remove windows, the server process
    maintains information about each window. In \l{Qt for Embedded Linux},
    top-level windows are encapsulated as QWSWindow objects. A list of
    the current windows can be retrieved using the
    QWSServer::clientWindows() function, and each window can tell
    which client that owns it through its QWSWindow::client()
    function.

    A QWSClient object has an unique ID that can be retrieved using
    its clientId() function. QWSClient also provides the identity()
    function which typically returns the name of this client's running
    application.

    \sa QWSServer, QWSWindow, {Qt for Embedded Linux Architecture}
*/

/*!
   \internal
*/
//always use frame buffer
QWSClient::QWSClient(QObject* parent, QWS_SOCK_BASE* sock, int id)
    : QObject(*new QWSClientPrivate, parent), command(0), cid(id)
{
#ifdef QT_NO_QWS_MULTIPROCESS
    Q_UNUSED(sock);
    isClosed = false;
#else
    csocket = 0;
    if (!sock) {
        socketDescriptor = -1;
        isClosed = false;
    } else {
        csocket = static_cast<QWSSocket*>(sock); //###
        isClosed = false;

        csocket->flush();
        socketDescriptor = csocket->socketDescriptor();
        connect(csocket, SIGNAL(readyRead()), this, SIGNAL(readyRead()));
        connect(csocket, SIGNAL(disconnected()), this, SLOT(closeHandler()));
        connect(csocket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(errorHandler()));
    }
#endif //QT_NO_QWS_MULTIPROCESS
}

/*!
   \internal
*/
QWSClient::~QWSClient()
{
    qDeleteAll(cursors);
    delete command;
#ifndef QT_NO_QWS_MULTIPROCESS
    delete csocket;
#endif
}

#ifndef QT_NO_QWS_MULTIPROCESS
void QWSClient::removeUnbufferedSurface()
{
    Q_D(QWSClient);
    --d->numUnbufferedSurfaces;
}

void QWSClient::addUnbufferedSurface()
{
    Q_D(QWSClient);
    ++d->numUnbufferedSurfaces;
}
#endif // QT_NO_QWS_MULTIPROCESS

/*!
   \internal
*/
void QWSClient::setIdentity(const QString& i)
{
    id = i;
}

void QWSClient::closeHandler()
{
    isClosed = true;
    emit connectionClosed();
}

void QWSClient::errorHandler()
{
#if defined(QWS_SOCKET_DEBUG)
    qDebug("Client %p error %s", this, csocket ? csocket->errorString().toLatin1().constData() : "(no socket)");
#endif
    isClosed = true;
//####Do we need to clean out the pipes?

    emit connectionClosed();
}

/*!
   \internal
*/
int QWSClient::socket() const
{
    return socketDescriptor;
}

/*!
   \internal
*/
void QWSClient::sendEvent(QWSEvent* event)
{
#ifndef QT_NO_QWS_MULTIPROCESS
    if (csocket) {
        // qDebug() << "QWSClient::sendEvent type " << event->type << " socket state " << csocket->state();
        if ((QAbstractSocket::SocketState)(csocket->state()) == QAbstractSocket::ConnectedState) {
            event->write(csocket);
        }
    }
    else
#endif
    {
        qt_client_enqueue(event);
    }
}

/*!
   \internal
*/
void QWSClient::sendRegionEvent(int winid, QRegion rgn, int type
#ifdef QT_QWS_CLIENTBLIT
        , int id
#endif
        )
{
#ifndef QT_NO_QWS_MULTIPROCESS
    Q_D(QWSClient);
    if (d->clientLock)
        d->clientLock->lock(QWSLock::RegionEvent);
#endif

    QWSRegionEvent event;
    event.setData(winid, rgn, type);
#ifdef QT_QWS_CLIENTBLIT
    event.simpleData.id = id;
#endif

//    qDebug() << "Sending Region event to" << winid << "rgn" << rgn << "type" << type;

    sendEvent(&event);
}

extern int qt_servershmid;

/*!
   \internal
*/
void QWSClient::sendConnectedEvent(const char *display_spec)
{
    QWSConnectedEvent event;
    event.simpleData.window = 0;
    event.simpleData.len = strlen(display_spec) + 1;
    event.simpleData.clientId = cid;
    event.simpleData.servershmid = qt_servershmid;
    char * tmp=(char *)display_spec;
    event.setData(tmp, event.simpleData.len);
    sendEvent(&event);
}

/*!
   \internal
*/
void QWSClient::sendMaxWindowRectEvent(const QRect &rect)
{
    QWSMaxWindowRectEvent event;
    event.simpleData.window = 0;
    event.simpleData.rect = rect;
    sendEvent(&event);
}

/*!
   \internal
*/
#ifndef QT_NO_QWS_PROPERTIES
void QWSClient::sendPropertyNotifyEvent(int property, int state)
{
    QWSPropertyNotifyEvent event;
    event.simpleData.window = 0; // not used yet
    event.simpleData.property = property;
    event.simpleData.state = state;
    sendEvent(&event);
}

/*!
   \internal
*/
void QWSClient::sendPropertyReplyEvent(int property, int len, const char *data)
{
    QWSPropertyReplyEvent event;
    event.simpleData.window = 0; // not used yet
    event.simpleData.property = property;
    event.simpleData.len = len;
    event.setData(data, len);
    sendEvent(&event);
}
#endif //QT_NO_QWS_PROPERTIES

/*!
   \internal
*/
void QWSClient::sendSelectionClearEvent(int windowid)
{
    QWSSelectionClearEvent event;
    event.simpleData.window = windowid;
    sendEvent(&event);
}

/*!
   \internal
*/
void QWSClient::sendSelectionRequestEvent(QWSConvertSelectionCommand *cmd, int windowid)
{
    QWSSelectionRequestEvent event;
    event.simpleData.window = windowid;
    event.simpleData.requestor = cmd->simpleData.requestor;
    event.simpleData.property = cmd->simpleData.selection;
    event.simpleData.mimeTypes = cmd->simpleData.mimeTypes;
    sendEvent(&event);
}

#ifndef QT_NO_QWSEMBEDWIDGET
/*!
   \internal
*/
void QWSClient::sendEmbedEvent(int windowid, QWSEmbedEvent::Type type,
                               const QRegion &region)
{
    QWSEmbedEvent event;
    event.setData(windowid, type, region);
    sendEvent(&event);
}
#endif // QT_NO_QWSEMBEDWIDGET

/*!
   \fn void QWSClient::connectionClosed()
   \internal
*/

/*!
    \fn void QWSClient::readyRead();
    \internal
*/

/*!
   \fn int QWSClient::clientId () const

   Returns an integer uniquely identfying this client.
*/

/*!
   \fn QString QWSClient::identity () const

   Returns the name of this client's running application.
*/
/*********************************************************************
 *
 * Class: QWSServer
 *
 *********************************************************************/

/*!
    \class QWSServer
    \brief The QWSServer class encapsulates a server process in Qt for Embedded Linux.

    \ingroup qws

    When you run a \l{Qt for Embedded Linux} application, it either runs as a
    server or connects to an existing server. The server and client
    processes have different responsibilities: The client process
    performs all application specific operations. The server process
    is responsible for managing the clients as well as taking care of
    the pointer handling, character input, and screen output. In
    addition, the server provides functionality to handle input
    methods.

    In \l{Qt for Embedded Linux}, all system generated events are passed to the
    server application which then propagates the event to the
    appropriate client. See the \l{Qt for Embedded Linux Architecture}
    documentation for details.

    Note that this class is instantiated by QApplication for
    \l{Qt for Embedded Linux} server processes; you should never construct this
    class yourself. Use the instance() function to retrieve a pointer
    to the server object.

    Note that the static functions of the QWSServer class can only be
    used in the server process.

    \tableofcontents

    \section1 Client Administration

    As applications add and remove windows, the server process
    maintains information about each window. In \l{Qt for Embedded Linux},
    top-level windows are encapsulated as QWSWindow objects. Each
    window can tell which client that owns it through its
    QWSWindow::client() function. Use the clientWindows() function to
    retrieve a list of the current top-level windows. Given a
    particular position on the display, the window containing it can
    be retrieved using the windowAt() function.

    QWSServer also provides the windowEvent() signal which is emitted
    whenever something happens to a top level window; the WindowEvent
    enum describes the various types of events that the signal
    recognizes. In addition, the server class provides the
    markedText() signal which is emitted whenever some text has been
    selected in any of the windows, passing the selection as
    parameter.

    The QCopChannel class and the QCOP communication protocol enable
    transfer of messages between clients. QWSServer provides the
    newChannel() and removedChannel() signals that is emitted whenever
    a new QCopChannel object is created or destroyed, respectively.

    See also: QWSWindow, QWSClient and QCopChannel.


    \section1 Mouse Handling

    The mouse driver (represented by an instance of the
    QWSMouseHandler class) is loaded by the server application when it
    starts running, using Qt's \l {How to Create Qt Plugins}{plugin
    system}. A mouse driver receives mouse events from the device and
    encapsulates each event with an instance of the QWSEvent class
    which it then passes to the server.

    The openMouse() function opens the mouse devices specified by the
    QWS_MOUSE_PROTO environment variable, and the setMouseHandler()
    functions sets the primary mouse driver. Alternatively, the static
    setDefaultMouse() function provides means of specifying the mouse
    driver to use if the QWS_MOUSE_PROTO variable is not defined (note
    that the default is otherwise platform dependent). The primary
    mouse driver can be retrieved using the static mouseHandler()
    function. Use the closeMouse() function to delete the mouse
    drivers.

    In addition, the QWSServer class can control the flow of mouse
    input using the suspendMouse() and resumeMouse() functions.

    See also: QWSMouseHandler and \l{Qt for Embedded Linux Pointer Handling}.

    \section1 Keyboard Handling

    The keyboard driver (represented by an instance of the
    QWSKeyboardHandler class) is loaded by the server application when
    it starts running, using Qt's \l {How to Create Qt Plugins}{plugin
    system}. A keyboard driver receives keyboard events from the
    device and encapsulates each event with an instance of the
    QWSEvent class which it then passes to the server.

    The openKeyboard() function opens the keyboard devices specified
    by the QWS_KEYBOARD environment variable, and the
    setKeyboardHandler() functions sets the primary keyboard
    driver. Alternatively, the static setDefaultKeyboard() function
    provides means of specifying the keyboard driver to use if the
    QWS_KEYBOARD variable is not defined (note again that the default
    is otherwise platform dependent). The primary keyboard driver can
    be retrieved using the static keyboardHandler() function. Use the
    closeKeyboard() function to delete the keyboard drivers.

    In addition, the QWSServer class can handle key events from both
    physical and virtual keyboards using the processKeyEvent() and
    sendKeyEvent() functions, respectively. Use the
    addKeyboardFilter() function to filter the key events from
    physical keyboard drivers, the most recently added filter can be
    removed and deleted using the removeKeyboardFilter() function.

    See also: QWSKeyboardHandler and \l{Qt for Embedded Linux Character Input}.

    \section1 Display Handling

    When a screen update is required, the server runs through all the
    top-level windows that intersect with the region that is about to
    be updated, and ensures that the associated clients have updated
    their memory buffer. Then the server uses the screen driver
    (represented by an instance of the QScreen class) to copy the
    content of the memory to the screen.

    In addition, the QWSServer class provides some means of managing
    the screen output: Use the refresh() function to refresh the
    entire display, or alternatively a specified region of it. The
    enablePainting() function can be used to disable (and enable)
    painting onto the screen. QWSServer also provide the
    setMaxWindowRect() function restricting the area of the screen
    which \l{Qt for Embedded Linux} applications will consider to be the
    maximum area to use for windows. To set the brush used as the
    background in the absence of obscuring windows, QWSServer provides
    the static setBackground() function. The corresponding
    backgroundBrush() function returns the currently set brush.

    QWSServer also controls the screen saver: Use the setScreenSaver()
    to install a custom screen saver derived from the QWSScreenSaver
    class. Once installed, the screensaver can be activated using the
    screenSaverActivate() function, and the screenSaverActive()
    function returns its current status. Use the
    setScreenSaverInterval() function to specify the timeout interval.
    \l{Qt for Embedded Linux} also supports multilevel screen saving, use the
    setScreenSaverIntervals() function to specify the various levels
    and their timeout intervals.

    Finally, the QWSServer class controls the cursor's appearance,
    i.e., use the setCursorVisible() function to hide or show the
    cursor, and the isCursorVisible() function to determine whether
    the cursor is visible on the display or not.

    See also: QScreen and \l{Qt for Embedded Linux Display Management}.

    \section1 Input Method Handling

    Whenever the server receives an event, it queries its stack of
    top-level windows to find the window containing the event's
    position (each window can identify the client application that
    created it). Then the server forwards the event to the appropriate
    client. If an input method is installed, it is used as a filter
    between the server and the client application.

    Derive from the QWSInputMethod class to create custom input
    methods, and use the server's setCurrentInputMethod() function to
    install it. Use the sendIMEvent() and sendIMQuery() functions to
    send input method events and queries.

    QWSServer provides the IMMouse enum describing the various mouse
    events recognized by the QWSInputMethod::mouseHandler()
    function. The latter function allows subclasses of QWSInputMethod
    to handle mouse events within the preedit text.

    \sa QWSInputMethod
*/

/*!
    \enum QWSServer::IMState
    \obsolete

    This enum describes the various states of an input method.

    \value IMCompose Composing.
    \value IMStart Equivalent to IMCompose.
    \value IMEnd Finished composing.

    \sa QWSInputMethod::sendIMEvent()
*/

/*!
    \enum QWSServer::IMMouse

    This enum describes the various types of mouse events recognized
    by the QWSInputMethod::mouseHandler() function.

    \value MousePress An event generated by pressing a mouse button.
    \value MouseRelease An event generated by relasing a mouse button.
    \value MouseMove An event generated by moving the mouse cursor.
    \value MouseOutside This value is only reserved, i.e., it is not used in
                                    current implementations.

    \sa QWSInputMethod, setCurrentInputMethod()
*/

/*!
    \enum QWSServer::ServerFlags
    \internal

    This enum is used to pass various options to the window system
    server.

    \value DisableKeyboard Ignore all keyboard input.
    \value DisableMouse Ignore all mouse input.
*/

/*!
    \enum QWSServer::WindowEvent

    This enum specifies the various events that can occur in a
    top-level window.

    \value Create A new window has been created (by the QWidget constructor).
    \value Destroy The window has been closed and deleted (by the QWidget destructor).
    \value Hide The window has been hidden using the QWidget::hide() function.
    \value Show The window has been shown using the QWidget::show() function or similar.
    \value Raise The window has been raised to the top of the desktop.
    \value Lower The window has been lowered.
    \value Geometry The window has changed size or position.
    \value Active The window has become the active window (i.e., it has keyboard focus).
    \value Name The window has been named.

    \sa windowEvent()
*/

/*!
    \fn void QWSServer::markedText(const QString &selection)

    This signal is emitted whenever some text is selected in any of
    the running applications, passing the selected text in the \a
    selection parameter.

    \sa windowEvent()
*/

/*!
    \fn const QList<QWSWindow*> &QWSServer::clientWindows()

    Returns the list of current top-level windows.

    Note that the collection of top-level windows changes as
    applications add and remove widgets so it should not be stored for
    future use. The windows are sorted in stacking order from top-most
    to bottom-most.

    Use the QWSWindow::client() function to retrieve the client
    application that owns a given window.

    \sa windowAt(), instance()
*/

/*!
    \fn void QWSServer::newChannel(const QString& channel)

    This signal is emitted whenever a new QCopChannel object is
    created, passing the channel's name in the \a channel parameter.

    \sa removedChannel()
*/

/*!
    \fn void QWSServer::removedChannel(const QString& channel)

    This signal is emitted immediately after the given the QCopChannel
    object specified by \a channel, is destroyed.

    Note that a channel is not destroyed until all its listeners have
    been unregistered.

    \sa newChannel()
*/

/*!
    \fn QWSServer::QWSServer(int flags, QObject *parent)
    \internal

    Construct a QWSServer object with the given \a parent.  The \a
    flags are used for keyboard and mouse settings.

    \warning This class is instantiated by QApplication for
    \l{Qt for Embedded Linux} server processes. You should never construct
    this class yourself.

    \sa {Running Applications}
*/

/*!
    \fn static QWSServer* QWSServer::instance()
    \since 4.2

    Returns a pointer to the server instance.

    Note that the pointer will be 0 if the application is not the
    server, i.e., if the QApplication::type() function doesn't return
    QApplication::GuiServer.

    \sa clientWindows(), windowAt()
*/

struct QWSCommandStruct
{
    QWSCommandStruct(QWSCommand *c, QWSClient *cl) :command(c),client(cl){}
    ~QWSCommandStruct() { delete command; }

    QWSCommand *command;
    QWSClient *client;

};

QWSServer::QWSServer(int flags, QObject *parent) :
    QObject(*new QWSServerPrivate, parent)
{
    Q_D(QWSServer);
    QT_TRY {
        d->initServer(flags);
    } QT_CATCH(...) {
        qwsServer = 0;
        qwsServerPrivate = 0;
        QT_RETHROW;
    }
}

#ifdef QT3_SUPPORT
/*!
    Use the two-argument overload and call the
    QObject::setObjectName() function instead.
*/
QWSServer::QWSServer(int flags, QObject *parent, const char *name) :
    QObject(*new QWSServerPrivate, parent)
{
    Q_D(QWSServer);
    setObjectName(QString::fromAscii(name));
    d->initServer(flags);
}
#endif


#ifndef QT_NO_QWS_MULTIPROCESS
static void ignoreSignal(int) {} // Used to eat SIGPIPE signals below
#endif

bool QWSServerPrivate::screensaverblockevent( int index, int *screensaverinterval, bool isDown )
{
    static bool ignoreEvents[2] = { false, false };
    if ( isDown ) {
        if ( !ignoreEvents[index] ) {
            bool wake = false;
            if ( screensaverintervals ) {
                if ( screensaverinterval != screensaverintervals ) {
                    wake = true;
                }
            }
            if ( screensaverblockevents && wake ) {
#ifdef EVENT_BLOCK_DEBUG
                qDebug( "waking the screen" );
#endif
                ignoreEvents[index] = true;
            } else if ( !screensaverblockevents ) {
#ifdef EVENT_BLOCK_DEBUG
                qDebug( "the screen was already awake" );
#endif
                ignoreEvents[index] = false;
            }
        }
    } else {
        if ( ignoreEvents[index] ) {
#ifdef EVENT_BLOCK_DEBUG
            qDebug( "mouseup?" );
#endif
            ignoreEvents[index] = false;
            return true;
        }
    }
    return ignoreEvents[index];
}

void QWSServerPrivate::initServer(int flags)
{
    Q_Q(QWSServer);
    Q_ASSERT(!qwsServer);
    qwsServer = q;
    qwsServerPrivate = this;
    disablePainting = false;
#ifndef QT_NO_QWS_MULTIPROCESS
    ssocket = new QWSServerSocket(qws_qtePipeFilename(), q);
    QObject::connect(ssocket, SIGNAL(newConnection()), q, SLOT(_q_newConnection()));

    if ( !ssocket->isListening()) {
        perror("QWSServerPrivate::initServer: server socket not listening");
        qFatal("Failed to bind to %s", qws_qtePipeFilename().toLatin1().constData());
    }

    struct linger tmp;
    tmp.l_onoff=1;
    tmp.l_linger=0;
    setsockopt(ssocket->socketDescriptor(),SOL_SOCKET,SO_LINGER,(char *)&tmp,sizeof(tmp));


    signal(SIGPIPE, ignoreSignal); //we get it when we read
#endif
    focusw = 0;
    mouseGrabber = 0;
    mouseGrabbing = false;
    inputMethodMouseGrabbed = false;
    keyboardGrabber = 0;
    keyboardGrabbing = false;
#ifndef QT_NO_QWS_CURSOR
    haveviscurs = false;
    cursor = 0;
    nextCursor = 0;
#endif

#ifndef QT_NO_QWS_MULTIPROCESS

    if (!geteuid()) {
#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
        if(mount(0,"/var/shm", "shm", 0, 0)) {
            /* This just confuses people with 2.2 kernels
            if (errno != EBUSY)
                qDebug("Failed mounting shm fs on /var/shm: %s",strerror(errno));
            */
        }
#endif
    }
#endif

    // no selection yet
    selectionOwner.windowid = -1;
    selectionOwner.time.set(-1, -1, -1, -1);

    cleanupFontsDir();

    // initialize the font database
    // from qfontdatabase_qws.cpp
    extern void qt_qws_init_fontdb();
    qt_qws_init_fontdb();

    openDisplay();

    screensavertimer = new QTimer(q);
    screensavertimer->setSingleShot(true);
    QObject::connect(screensavertimer, SIGNAL(timeout()), q, SLOT(_q_screenSaverTimeout()));
    _q_screenSaverWake();

    clientMap[-1] = new QWSClient(q, 0, 0);

    if (!bgBrush)
        bgBrush = new QBrush(QColor(0x20, 0xb0, 0x50));

    initializeCursor();

    // input devices
    if (!(flags&QWSServer::DisableMouse)) {
        q->openMouse();
    }
#ifndef QT_NO_QWS_KEYBOARD
    if (!(flags&QWSServer::DisableKeyboard)) {
        q->openKeyboard();
    }
#endif

#if !defined(QT_NO_SOUND) && !defined(QT_EXTERNAL_SOUND_SERVER) && !defined(Q_OS_DARWIN)
    soundserver = new QWSSoundServer(q);
#endif
}

/*!
    \internal
    Destructs this server.
*/
QWSServer::~QWSServer()
{
    closeMouse();
#ifndef QT_NO_QWS_KEYBOARD
    closeKeyboard();
#endif
    d_func()->cleanupFonts(/*force =*/true);
}

/*!
  \internal
 */
void QWSServer::timerEvent(QTimerEvent *e)
{
    Q_D(QWSServer);
    if (e->timerId() == d->fontCleanupTimer.timerId()) {
        d->cleanupFonts();
        d->fontCleanupTimer.stop();
    } else {
        QObject::timerEvent(e);
    }
}

const QList<QWSWindow*> &QWSServer::clientWindows()
{
    Q_D(QWSServer);
    return d->windows;
}

/*!
  \internal
*/
void QWSServerPrivate::releaseMouse(QWSWindow* w)
{
    if (w && mouseGrabber == w) {
        mouseGrabber = 0;
        mouseGrabbing = false;
#ifndef QT_NO_QWS_CURSOR
        if (nextCursor) {
            // Not grabbing -> set the correct cursor
            setCursor(nextCursor);
            nextCursor = 0;
        }
#endif
    }
}

/*!
  \internal
*/
void QWSServerPrivate::releaseKeyboard(QWSWindow* w)
{
    if (keyboardGrabber == w) {
        keyboardGrabber = 0;
        keyboardGrabbing = false;
    }
}

void QWSServerPrivate::handleWindowClose(QWSWindow *w)
{
    w->shuttingDown();
    if (focusw == w)
        setFocus(w,false);
    if (mouseGrabber == w)
        releaseMouse(w);
    if (keyboardGrabber == w)
        releaseKeyboard(w);
}


#ifndef QT_NO_QWS_MULTIPROCESS
/*!
  \internal
*/
void QWSServerPrivate::_q_newConnection()
{
    Q_Q(QWSServer);
    while (QWS_SOCK_BASE *sock = ssocket->nextPendingConnection()) {
        int socket = sock->socketDescriptor();
        sock->setParent(0);

        QWSClient *client = new QWSClient(q,sock, get_object_id());
        clientMap[socket] = client;

#ifndef QT_NO_SXE
#ifdef QTRANSPORTAUTH_DEBUG
        qDebug( "Transport auth connected: unix stream socket %d", socket );
#endif
        // get a handle to the per-process authentication service
        QTransportAuth *a = QTransportAuth::getInstance();

        // assert that this transport is trusted
        QTransportAuth::Data *d = a->connectTransport(
                QTransportAuth::UnixStreamSock |
                QTransportAuth::Trusted, socket );

        QAuthDevice *ad = a->recvBuf( d, sock );
        ad->setClient(client);

        QObject::connect(ad, SIGNAL(readyRead()),
                q, SLOT(_q_doClient()));

        QObject::connect(client, SIGNAL(connectionClosed()),
                q, SLOT(_q_clientClosed()));
#else
        QObject::connect(client, SIGNAL(readyRead()),
                         q, SLOT(_q_doClient()));
        QObject::connect(client, SIGNAL(connectionClosed()),
                         q, SLOT(_q_clientClosed()));
#endif // QT_NO_SXE

        client->sendConnectedEvent(qws_display_spec.constData());

        if (clientMap.contains(socket)) {
            QList<QScreen*> screens = qt_screen->subScreens();
            if (screens.isEmpty())
                screens.append(qt_screen);
            for (int i = 0; i < screens.size(); ++i) {
                const QApplicationPrivate *ap = QApplicationPrivate::instance();
                QScreen *screen = screens.at(i);
                const QRect rect = ap->maxWindowRect(screen);
                if (!rect.isEmpty())
                    client->sendMaxWindowRectEvent(rect);
                if (screen->isTransformed()) {
                    QWSScreenTransformationEvent event;
                    event.simpleData.screen = i;
                    event.simpleData.transformation = screen->transformOrientation();
                    client->sendEvent(&event);
                }
            }
        }

        // pre-provide some object id's
        QWSCreateCommand cmd(30);
        invokeCreate(&cmd, client);
    }
}
/*!
  \internal
*/
void QWSServerPrivate::_q_clientClosed()
{
    Q_Q(QWSServer);
    QWSClient* cl = (QWSClient*)q->sender();

    // Remove any queued commands for this client
    int i = 0;
    while (i < commandQueue.size()) {
        QWSCommandStruct *cs = commandQueue.at(i);
        if (cs->client == cl) {
            commandQueue.removeAt(i);
            delete cs;
        } else {
            ++i;
        }
    }

#ifndef QT_NO_COP
    // Enfore unsubscription from all channels.
    QCopChannel::detach(cl);
#endif

    // Shut down all windows for this client
    for (int i = 0; i < windows.size(); ++i) {
        QWSWindow* w = windows.at(i);
        if (w->forClient(cl))
            w->shuttingDown();
    }

    // Delete all windows for this client
    QRegion exposed;
    i = 0;
    while (i < windows.size()) {
        QWSWindow* w = windows.at(i);
        if (w->forClient(cl)) {
            windows.takeAt(i);
            w->c = 0; //so we don't send events to it anymore
            releaseMouse(w);
            releaseKeyboard(w);
            exposed += w->allocatedRegion();
//                rgnMan->remove(w->allocationIndex());
            if (focusw == w)
                setFocus(focusw,0);
            if (mouseGrabber == w)
                releaseMouse(w);
            if (i < nReserved)
                --nReserved;
#ifndef QT_NO_QWS_PROPERTIES
            propertyManager.removeProperties(w->winId());
#endif
            emit q->windowEvent(w, QWSServer::Destroy);
            w->d->state = QWSWindow::Destroyed; //???
            deletedWindows.append(w);
        } else {
            ++i;
        }
    }
    if (deletedWindows.count())
        QTimer::singleShot(0, q, SLOT(_q_deleteWindowsLater()));

    QWSClientPrivate *clientPrivate = cl->d_func();
    if (!clientPrivate->shutdown) {
#if defined(QWS_DEBUG_FONTCLEANUP)
        qDebug() << "client" << cl->clientId() << "crashed";
#endif
        // this would be the place to emit a signal to notify about the
        // crash of a client
        crashedClientIds.append(cl->clientId());
        fontCleanupTimer.start(10, q_func());
    }
    clientPrivate->shutdown = true;

    while (!clientPrivate->usedFonts.isEmpty()) {
        const QByteArray font = *clientPrivate->usedFonts.begin();
#if defined(QWS_DEBUG_FONTCLEANUP)
        qDebug() << "dereferencing font" << font << "from disconnected client";
#endif
        dereferenceFont(clientPrivate, font);
    }
    clientPrivate->usedFonts.clear();

    //qDebug("removing client %d with socket %d", cl->clientId(), cl->socket());
    clientMap.remove(cl->socket());
    if (cl == cursorClient)
        cursorClient = 0;
    if (qt_screen->clearCacheFunc)
        (qt_screen->clearCacheFunc)(qt_screen, cl->clientId());  // remove any remaining cache entries.
    cl->deleteLater();

    update_regions();
    exposeRegion(exposed);
}

void QWSServerPrivate::_q_deleteWindowsLater()
{
    qDeleteAll(deletedWindows);
    deletedWindows.clear();
}

#endif //QT_NO_QWS_MULTIPROCESS

void QWSServerPrivate::referenceFont(QWSClientPrivate *client, const QByteArray &font)
{
    if (!client->usedFonts.contains(font)) {
        client->usedFonts.insert(font);

        ++fontReferenceCount[font];
#if defined(QWS_DEBUG_FONTCLEANUP)
        qDebug() << "Client" << client->q_func()->clientId() << "added font" << font;
        qDebug() << "Refcount is" << fontReferenceCount[font];
#endif
    }
}

void QWSServerPrivate::dereferenceFont(QWSClientPrivate *client, const QByteArray &font)
{
    if (client->usedFonts.contains(font)) {
        client->usedFonts.remove(font);

        Q_ASSERT(fontReferenceCount[font]);
        if (!--fontReferenceCount[font] && !fontCleanupTimer.isActive())
            fontCleanupTimer.start(FontCleanupInterval, q_func());

#if defined(QWS_DEBUG_FONTCLEANUP)
        qDebug() << "Client" << client->q_func()->clientId() << "removed font" << font;
        qDebug() << "Refcount is" << fontReferenceCount[font];
#endif
    }
}

static void cleanupFontsDir()
{
    static bool dontDelete = !qgetenv("QWS_KEEP_FONTS").isEmpty();
    if (dontDelete)
        return;

    extern QString qws_fontCacheDir();
    QDir dir(qws_fontCacheDir(), QLatin1String("*.qsf"));
    for (uint i = 0; i < dir.count(); ++i) {
#if defined(QWS_DEBUG_FONTCLEANUP)
        qDebug() << "removing stale font file" << dir[i];
#endif
        dir.remove(dir[i]);
    }
}

void QWSServerPrivate::cleanupFonts(bool force)
{
    static bool dontDelete = !qgetenv("QWS_KEEP_FONTS").isEmpty();
    if (dontDelete)
        return;

#if defined(QWS_DEBUG_FONTCLEANUP)
    qDebug() << "cleanupFonts()";
#endif
    if (!fontReferenceCount.isEmpty()) {
        QMap<QByteArray, int>::Iterator it = fontReferenceCount.begin();
        while (it != fontReferenceCount.end()) {
            if (it.value() && !force) {
                ++it;
                continue;
            }

            const QByteArray &fontName = it.key();
#if defined(QWS_DEBUG_FONTCLEANUP)
            qDebug() << "removing unused font file" << fontName;
#endif
            QT_TRY {
                QFile::remove(QFile::decodeName(fontName));
                sendFontRemovedEvent(fontName);

                it = fontReferenceCount.erase(it);
            } QT_CATCH(...) {
                // so we were not able to remove the font.
                // don't be angry and just continue with the next ones.
                ++it;
            }
        }
    }

    if (crashedClientIds.isEmpty())
        return;

    QList<QByteArray> removedFonts;
#if !defined(QT_NO_QWS_QPF2) && !defined(QT_FONTS_ARE_RESOURCES)
    removedFonts = QFontEngineQPF::cleanUpAfterClientCrash(crashedClientIds);
#endif
    crashedClientIds.clear();

    for (int i = 0; i < removedFonts.count(); ++i)
        sendFontRemovedEvent(removedFonts.at(i));
}

void QWSServerPrivate::sendFontRemovedEvent(const QByteArray &font)
{
    QWSFontEvent event;
    event.simpleData.type = QWSFontEvent::FontRemoved;
    event.setData(font.constData(), font.length(), false);

    QMap<int,QWSClient*>::const_iterator it = clientMap.constBegin();
    for (; it != clientMap.constEnd(); ++it)
        (*it)->sendEvent(&event);
}

/*!
   \internal
*/
QWSCommand* QWSClient::readMoreCommand()
{
#ifndef QT_NO_QWS_MULTIPROCESS
    QIODevice *socket = 0;
#endif
#ifndef QT_NO_SXE
    if (socketDescriptor != -1)  // not server socket
        socket = QTransportAuth::getInstance()->passThroughByClient( this );
#if QTRANSPORTAUTH_DEBUG
    if (socket) {
        char displaybuf[1024];
        qint64 bytes = socket->bytesAvailable();
        if ( bytes > 511 ) bytes = 511;
        hexstring( displaybuf, ((unsigned char *)(reinterpret_cast<QAuthDevice*>(socket)->buffer().constData())), bytes );
        qDebug( "readMoreCommand: %lli bytes - %s", socket->bytesAvailable(), displaybuf );
    }
#endif
#endif // QT_NO_SXE

#ifndef QT_NO_QWS_MULTIPROCESS
    if (!socket)
        socket = csocket;   // server socket
    if (socket) {
        // read next command
        if (!command) {
            int command_type = qws_read_uint(socket);

            if (command_type >= 0)
                command = QWSCommand::factory(command_type);
        }
        if (command) {
            if (command->read(socket)) {
                // Finished reading a whole command.
                QWSCommand* result = command;
                command = 0;
                return result;
            }
        }

        // Not finished reading a whole command.
        return 0;
    } else
#endif // QT_NO_QWS_MULTIPROCESS
    {
        QList<QWSCommand*> *serverQueue = qt_get_server_queue();
        return serverQueue->isEmpty() ? 0 : serverQueue->takeFirst();
    }
}


/*!
  \internal
*/
void QWSServer::processEventQueue()
{
    if (qwsServerPrivate)
        qwsServerPrivate->doClient(qwsServerPrivate->clientMap.value(-1));
}


#ifndef QT_NO_QWS_MULTIPROCESS
void QWSServerPrivate::_q_doClient()
{
    Q_Q(QWSServer);

    QWSClient* client;
#ifndef QT_NO_SXE
    QAuthDevice *ad = qobject_cast<QAuthDevice*>(q->sender());
    if (ad)
        client = (QWSClient*)ad->client();
    else
#endif
        client = (QWSClient*)q->sender();

    if (doClientIsActive) {
        pendingDoClients.append(client);
        return;
    }
    doClientIsActive = true;

    doClient(client);

    while (!pendingDoClients.isEmpty()) {
        doClient(pendingDoClients.takeFirst());
    }

    doClientIsActive = false;
}
#endif // QT_NO_QWS_MULTIPROCESS

void QWSServerPrivate::doClient(QWSClient *client)
{
    QWSCommand* command=client->readMoreCommand();

    while (command) {
        QWSCommandStruct *cs = new QWSCommandStruct(command, client);
        commandQueue.append(cs);
        // Try for some more...
        command=client->readMoreCommand();
    }

    while (!commandQueue.isEmpty()) {
        QWSCommandStruct *cs = commandQueue.takeAt(0);
        switch (cs->command->type) {
        case QWSCommand::Identify:
            invokeIdentify((QWSIdentifyCommand*)cs->command, cs->client);
            break;
        case QWSCommand::Create:
            invokeCreate((QWSCreateCommand*)cs->command, cs->client);
            break;
#ifndef QT_NO_QWS_MULTIPROCESS
        case QWSCommand::Shutdown:
            cs->client->d_func()->shutdown = true;
            break;
#endif
        case QWSCommand::RegionName:
            invokeRegionName((QWSRegionNameCommand*)cs->command, cs->client);
            break;
        case QWSCommand::Region:
            invokeRegion((QWSRegionCommand*)cs->command, cs->client);
            cs->client->d_func()->unlockCommunication();
            break;
        case QWSCommand::RegionMove:
            invokeRegionMove((QWSRegionMoveCommand*)cs->command, cs->client);
            cs->client->d_func()->unlockCommunication();
            break;
        case QWSCommand::RegionDestroy:
            invokeRegionDestroy((QWSRegionDestroyCommand*)cs->command, cs->client);
            break;
#ifndef QT_NO_QWS_PROPERTIES
        case QWSCommand::AddProperty:
            invokeAddProperty((QWSAddPropertyCommand*)cs->command);
            break;
        case QWSCommand::SetProperty:
            invokeSetProperty((QWSSetPropertyCommand*)cs->command);
            break;
        case QWSCommand::RemoveProperty:
            invokeRemoveProperty((QWSRemovePropertyCommand*)cs->command);
            break;
        case QWSCommand::GetProperty:
            invokeGetProperty((QWSGetPropertyCommand*)cs->command, cs->client);
            break;
#endif
        case QWSCommand::SetSelectionOwner:
            invokeSetSelectionOwner((QWSSetSelectionOwnerCommand*)cs->command);
            break;
        case QWSCommand::RequestFocus:
            invokeSetFocus((QWSRequestFocusCommand*)cs->command, cs->client);
            break;
        case QWSCommand::ChangeAltitude:
            invokeSetAltitude((QWSChangeAltitudeCommand*)cs->command,
                               cs->client);
            cs->client->d_func()->unlockCommunication();
            break;
        case QWSCommand::SetOpacity:
            invokeSetOpacity((QWSSetOpacityCommand*)cs->command,
                               cs->client);
            break;

#ifndef QT_NO_QWS_CURSOR
        case QWSCommand::DefineCursor:
            invokeDefineCursor((QWSDefineCursorCommand*)cs->command, cs->client);
            break;
        case QWSCommand::SelectCursor:
            invokeSelectCursor((QWSSelectCursorCommand*)cs->command, cs->client);
            break;
        case QWSCommand::PositionCursor:
            invokePositionCursor((QWSPositionCursorCommand*)cs->command, cs->client);
            break;
#endif
        case QWSCommand::GrabMouse:
            invokeGrabMouse((QWSGrabMouseCommand*)cs->command, cs->client);
            break;
        case QWSCommand::GrabKeyboard:
            invokeGrabKeyboard((QWSGrabKeyboardCommand*)cs->command, cs->client);
            break;
#if !defined(QT_NO_SOUND) && !defined(Q_OS_DARWIN)
        case QWSCommand::PlaySound:
            invokePlaySound((QWSPlaySoundCommand*)cs->command, cs->client);
            break;
#endif
#ifndef QT_NO_COP
        case QWSCommand::QCopRegisterChannel:
            invokeRegisterChannel((QWSQCopRegisterChannelCommand*)cs->command,
                                   cs->client);
            break;
        case QWSCommand::QCopSend:
            invokeQCopSend((QWSQCopSendCommand*)cs->command, cs->client);
            break;
#endif
#ifndef QT_NO_QWS_INPUTMETHODS
        case QWSCommand::IMUpdate:
            invokeIMUpdate((QWSIMUpdateCommand*)cs->command, cs->client);
            break;
        case QWSCommand::IMResponse:
            invokeIMResponse((QWSIMResponseCommand*)cs->command, cs->client);
            break;
        case QWSCommand::IMMouse:
            {
                if (current_IM) {
                    QWSIMMouseCommand *cmd = (QWSIMMouseCommand *) cs->command;
                    current_IM->mouseHandler(cmd->simpleData.index,
                                              cmd->simpleData.state);
                }
            }
            break;
#endif
        case QWSCommand::Font:
            invokeFont((QWSFontCommand *)cs->command, cs->client);
            break;
        case QWSCommand::RepaintRegion:
            invokeRepaintRegion((QWSRepaintRegionCommand*)cs->command,
                                cs->client);
            cs->client->d_func()->unlockCommunication();
            break;
#ifndef QT_NO_QWSEMBEDWIDGET
        case QWSCommand::Embed:
            invokeEmbed(static_cast<QWSEmbedCommand*>(cs->command),
                        cs->client);
            break;
#endif
        case QWSCommand::ScreenTransform:
            invokeScreenTransform(static_cast<QWSScreenTransformCommand*>(cs->command),
                                  cs->client);
            break;
        }
        delete cs;
    }
}


void QWSServerPrivate::showCursor()
{
#ifndef QT_NO_QWS_CURSOR
    if (qt_screencursor)
        qt_screencursor->show();
#endif
}

void QWSServerPrivate::hideCursor()
{
#ifndef QT_NO_QWS_CURSOR
    if (qt_screencursor)
        qt_screencursor->hide();
#endif
}

/*!
    \fn void QWSServer::enablePainting(bool enable)

    Enables painting onto the screen if \a enable is true; otherwise
    painting is disabled.

    \sa {Qt for Embedded Linux Architecture#Drawing on Screen}{Qt for Embedded Linux
    Architecture}
*/
void QWSServer::enablePainting(bool enable)
{
    Q_D(QWSServer);

    if (d->disablePainting == !enable)
        return;

    d->disablePainting = !enable;

    if (enable) {
        // Reset the server side allocated regions to ensure update_regions()
        // will send out region events.
        for (int i = 0; i < d->windows.size(); ++i) {
            QWSWindow *w = d->windows.at(i);
            w->setAllocatedRegion(QRegion());
#ifdef QT_QWS_CLIENTBLIT
            w->setDirectPaintRegion(QRegion());
#endif
        }
        d->update_regions();
        d->showCursor();
    } else {
        // Disable painting by clients by taking away their allocated region.
        // To ensure mouse events are still delivered to the correct windows,
        // the allocated regions are not modified on the server.
        for (int i = 0; i < d->windows.size(); ++i) {
            QWSWindow *w = d->windows.at(i);
            w->client()->sendRegionEvent(w->winId(), QRegion(),
                                         QWSRegionEvent::Allocation);
#ifdef QT_QWS_CLIENTBLIT
            w->client()->sendRegionEvent(w->winId(), QRegion(),
                                         QWSRegionEvent::DirectPaint);
#endif
        }
        d->hideCursor();
    }
}

/*!
    Refreshes the display by making the screen driver update the
    entire display.

    \sa QScreen::exposeRegion()
*/
void QWSServer::refresh()
{
    Q_D(QWSServer);
    d->exposeRegion(QScreen::instance()->region());
//### send repaint to non-buffered windows
}

/*!
    \fn void QWSServer::refresh(QRegion & region)
    \overload

    Refreshes the given \a region of the display.
*/
void QWSServer::refresh(QRegion & r)
{
    Q_D(QWSServer);
    d->exposeRegion(r);
//### send repaint to non-buffered windows
}

/*!
    \fn void QWSServer::setMaxWindowRect(const QRect& rectangle)

    Sets the maximum area of the screen that \l{Qt for Embedded Linux}
    applications can use, to be the given \a rectangle.

    Note that this function can only be used in the server process.

    \sa QWidget::showMaximized()
*/
void QWSServer::setMaxWindowRect(const QRect &rect)
{
    QList<QScreen*> subScreens = qt_screen->subScreens();
    if (subScreens.isEmpty() && qt_screen != 0)
        subScreens.append(qt_screen);

    for (int i = 0; i < subScreens.size(); ++i) {
        const QScreen *screen = subScreens.at(i);
        const QRect r = (screen->region() & rect).boundingRect();
        if (r.isEmpty())
            continue;

        QApplicationPrivate *ap = QApplicationPrivate::instance();
        if (ap->maxWindowRect(screen) != r) {
            ap->setMaxWindowRect(screen, i, r);
            qwsServerPrivate->sendMaxWindowRectEvents(r);
        }
    }
}

/*!
  \internal
*/
void QWSServerPrivate::sendMaxWindowRectEvents(const QRect &rect)
{
    QMap<int,QWSClient*>::const_iterator it = clientMap.constBegin();
    for (; it != clientMap.constEnd(); ++it)
        (*it)->sendMaxWindowRectEvent(rect);
}

/*!
    \fn void QWSServer::setDefaultMouse(const char *mouseDriver)

    Sets the mouse driver that will be used if the QWS_MOUSE_PROTO
    environment variable is not defined, to be the given \a
    mouseDriver.

    Note that the default is platform-dependent. This function can
    only be used in the server process.


    \sa setMouseHandler(), {Qt for Embedded Linux Pointer Handling}
*/
void QWSServer::setDefaultMouse(const char *m)
{
    *defaultMouse() = QString::fromAscii(m);
}

/*!
    \fn void QWSServer::setDefaultKeyboard(const char *keyboardDriver)

    Sets the keyboard driver that will be used if the QWS_KEYBOARD
    environment variable is not defined, to be the given \a
    keyboardDriver.

    Note that the default is platform-dependent. This function can
    only be used in the server process.

    \sa setKeyboardHandler(), {Qt for Embedded Linux Character Input}
*/
void QWSServer::setDefaultKeyboard(const char *k)
{
    *defaultKeyboard() = QString::fromAscii(k);
}

#ifndef QT_NO_QWS_CURSOR
static bool prevWin;
#endif


extern int *qt_last_x,*qt_last_y;


/*!
  \internal

  Send a mouse event. \a pos is the screen position where the mouse
  event occurred and \a state is a mask indicating which buttons are
  pressed.

  \a pos is in device coordinates
*/
void QWSServer::sendMouseEvent(const QPoint& pos, int state, int wheel)
{
    bool block = qwsServerPrivate->screensaverblockevent(MOUSE, qwsServerPrivate->screensaverinterval, state);
#ifdef EVENT_BLOCK_DEBUG
    qDebug() << "sendMouseEvent" << pos.x() << pos.y() << state << (block ? "block" : "pass");
#endif

    if (state || wheel)
        qwsServerPrivate->_q_screenSaverWake();

    if ( block )
        return;

    QPoint tpos;
    // transformations
    if (qt_screen->isTransformed()) {
	QSize s = QSize(qt_screen->deviceWidth(), qt_screen->deviceHeight());
	tpos = qt_screen->mapFromDevice(pos, s);
    } else {
	tpos = pos;
    }

    if (qt_last_x) {
         *qt_last_x = tpos.x();
         *qt_last_y = tpos.y();
    }
    QWSServer::mousePosition = tpos;
    qwsServerPrivate->mouseState = state;

#ifndef QT_NO_QWS_INPUTMETHODS
    const int btnMask = Qt::LeftButton | Qt::RightButton | Qt::MidButton;
    int stroke_count; // number of strokes to keep shown.
    if (force_reject_strokeIM || !current_IM)
    {
	stroke_count = 0;
    } else {
	stroke_count = current_IM->filter(tpos, state, wheel);
    }

    if (stroke_count == 0) {
	if (state&btnMask)
	    force_reject_strokeIM = true;
        QWSServerPrivate::sendMouseEventUnfiltered(tpos, state, wheel);
    }
    // stop force reject after stroke ends.
    if (state&btnMask && force_reject_strokeIM)
	force_reject_strokeIM = false;
    // on end of stroke, force_rejct
    // and once a stroke is rejected, do not try again till pen is lifted
#else
    QWSServerPrivate::sendMouseEventUnfiltered(tpos, state, wheel);
#endif // end QT_NO_QWS_FSIM
}

void QWSServerPrivate::sendMouseEventUnfiltered(const QPoint &pos, int state, int wheel)
{
    const int btnMask = Qt::LeftButton | Qt::RightButton | Qt::MidButton;
    QWSMouseEvent event;

    QWSWindow *win = qwsServer->windowAt(pos);

    QWSClient *serverClient = qwsServerPrivate->clientMap.value(-1);
    QWSClient *winClient = win ? win->client() : 0;


    bool imMouse = false;
#ifndef QT_NO_QWS_INPUTMETHODS
    // check for input method window
    if (current_IM && current_IM_winId != -1) {
        QWSWindow *kbw = keyboardGrabber ? keyboardGrabber :
                         qwsServerPrivate->focusw;

        imMouse = kbw == win;
        if ( !imMouse ) {
            QWidget *target = winClient == serverClient ?
                              QApplication::widgetAt(pos) : 0;
            imMouse = target && (target->testAttribute(Qt::WA_InputMethodTransparent));
        }
    }
#endif

    //If grabbing window disappears, grab is still active until
    //after mouse release.
    if ( qwsServerPrivate->mouseGrabber && (!imMouse || qwsServerPrivate->inputMethodMouseGrabbed)) {
        win = qwsServerPrivate->mouseGrabber;
        winClient = win ? win->client() : 0;
    }
    event.simpleData.window = win ? win->id : 0;

#ifndef QT_NO_QWS_CURSOR
    if (qt_screencursor)
        qt_screencursor->move(pos.x(),pos.y());

    // Arrow cursor over desktop
    // prevWin remembers if the last event was over a window
    if (!win && prevWin) {
        if (!qwsServerPrivate->mouseGrabber)
            qwsServerPrivate->setCursor(QWSCursor::systemCursor(Qt::ArrowCursor));
        else
            qwsServerPrivate->nextCursor = QWSCursor::systemCursor(Qt::ArrowCursor);
        prevWin = false;
    }
    // reset prevWin
    if (win && !prevWin)
        prevWin = true;
#endif

    if ((state&btnMask) && !qwsServerPrivate->mouseGrabbing) {
        qwsServerPrivate->mouseGrabber = win;
        if (imMouse)
            qwsServerPrivate->inputMethodMouseGrabbed = true;
    }
    if (!(state&btnMask))
        qwsServerPrivate->inputMethodMouseGrabbed = false;

    event.simpleData.x_root=pos.x();
    event.simpleData.y_root=pos.y();
    event.simpleData.state=state | qws_keyModifiers;
    event.simpleData.delta = wheel;
    event.simpleData.time=qwsServerPrivate->timer.elapsed();

    static int oldstate = 0;

#ifndef QT_NO_QWS_INPUTMETHODS
    //tell the input method if we click on a different window that is not IM transparent
    bool isPress = state > oldstate;
    if (isPress && !imMouse && current_IM && current_IM_winId != -1)
        current_IM->mouseHandler(-1, QWSServer::MouseOutside);
#endif

    if (serverClient)
       serverClient->sendEvent(&event);
    if (winClient && winClient != serverClient)
       winClient->sendEvent(&event);

    if ( !imMouse ) {
        // Make sure that if we leave a window, that window gets one last mouse
        // event so that it knows the mouse has left.
        QWSClient *oldClient = qwsServer->d_func()->cursorClient;
        if (oldClient && oldClient != winClient && oldClient != serverClient) {
            event.simpleData.state = oldstate | qws_keyModifiers;
            oldClient->sendEvent(&event);
        }
    }

    oldstate = state;
    if ( !imMouse )
        qwsServer->d_func()->cursorClient = winClient;

    if (!(state&btnMask) && !qwsServerPrivate->mouseGrabbing)
        qwsServerPrivate->releaseMouse(qwsServerPrivate->mouseGrabber);
}

/*!
    Returns the primary mouse driver.

    Note that this function can only be used in the server process.

    \sa setMouseHandler(), openMouse(), closeMouse()
*/
QWSMouseHandler *QWSServer::mouseHandler()
{
    if (qwsServerPrivate->mousehandlers.empty())
        return 0;
    return qwsServerPrivate->mousehandlers.first();
}

/*!
    \since 4.5

    Returns list of all mouse handlers

    Note that this function can only be used in the server process.

    \sa mouseHandler(), setMouseHandler(), openMouse(), closeMouse()
*/
const QList<QWSMouseHandler*>& QWSServer::mouseHandlers()
{
    return qwsServerPrivate->mousehandlers;
}


// called by QWSMouseHandler constructor, not user code.
/*!
    \fn void QWSServer::setMouseHandler(QWSMouseHandler* driver)

    Sets the primary mouse driver to be the given \a driver.

    \l{Qt for Embedded Linux} provides several ready-made mouse drivers, and
    custom drivers are typically added using Qt's plugin
    mechanism. See the \l{Qt for Embedded Linux Pointer Handling} documentation
    for details.

    Note that this function can only be used in the server process.

    \sa mouseHandler(), setDefaultMouse()
*/
void QWSServer::setMouseHandler(QWSMouseHandler* mh)
{
    if (!mh)
        return;
    qwsServerPrivate->mousehandlers.removeAll(mh);
    qwsServerPrivate->mousehandlers.prepend(mh);
}

/*!
  \internal
  \obsolete
  Caller owns data in list, and must delete contents
*/
QList<QWSInternalWindowInfo*> * QWSServer::windowList()
{
    QList<QWSInternalWindowInfo*> * ret=new QList<QWSInternalWindowInfo*>;
    for (int i=0; i < qwsServerPrivate->windows.size(); ++i) {
        QWSWindow *window = qwsServerPrivate->windows.at(i);
        QWSInternalWindowInfo * qwi=new QWSInternalWindowInfo();
        qwi->winid=window->winId();
        qwi->clientid=window->client()->clientId();
        ret->append(qwi);
    }
    return ret;
}

#ifndef QT_NO_COP
/*!
  \internal
*/
void QWSServerPrivate::sendQCopEvent(QWSClient *c, const QString &ch,
                               const QString &msg, const QByteArray &data,
                               bool response)
{
    Q_ASSERT(c);

    QWSQCopMessageEvent event;
    event.channel = ch.toLatin1();
    event.message = msg.toLatin1();
    event.data = data;
    event.simpleData.is_response = response;
    event.simpleData.lchannel = ch.length();
    event.simpleData.lmessage = msg.length();
    event.simpleData.ldata = data.size();
    int l = event.simpleData.lchannel + event.simpleData.lmessage +
            event.simpleData.ldata;

    // combine channel, message and data into one block of raw bytes
    char *tmp = new char [l];
    char *d = tmp;
    memcpy(d, event.channel.constData(), event.simpleData.lchannel);
    d += event.simpleData.lchannel;
    memcpy(d, event.message.constData(), event.simpleData.lmessage);
    d += event.simpleData.lmessage;
    memcpy(d, data.constData(), event.simpleData.ldata);

    event.setDataDirect(tmp, l);

    c->sendEvent(&event);
}
#endif

/*!
    \fn QWSWindow *QWSServer::windowAt(const QPoint& position)

    Returns the window containing the given \a position.

    Note that if there is no window under the specified point this
    function returns 0.

    \sa clientWindows(), instance()
*/
QWSWindow *QWSServer::windowAt(const QPoint& pos)
{
    Q_D(QWSServer);
    for (int i=0; i<d->windows.size(); ++i) {
        QWSWindow* w = d->windows.at(i);
        if (w->allocatedRegion().contains(pos))
            return w;
    }
    return 0;
}

#ifndef QT_NO_QWS_KEYBOARD
static int keyUnicode(int keycode)
{
    int code = 0xffff;

    if (keycode >= Qt::Key_A && keycode <= Qt::Key_Z)
        code = keycode - Qt::Key_A + 'a';
    else if (keycode >= Qt::Key_0 && keycode <= Qt::Key_9)
        code = keycode - Qt::Key_0 + '0';

    return code;
}
#endif

/*!
    Sends the given key event. The key is identified by its \a unicode
    value and the given \a keycode, \a modifiers, \a isPress and \a
    autoRepeat parameters.

    Use this function to send key events generated by "virtual
    keyboards" (note that the processKeyEvent() function is
    impelemented using this function).

    The \a keycode parameter is the Qt keycode value as defined by the
    Qt::Key enum. The \a modifiers is an OR combination of
    Qt::KeyboardModifier values, indicating whether \gui
    Shift/Alt/Ctrl keys are pressed. The \a isPress parameter is true
    if the event is a key press event and \a autoRepeat is true if the
    event is caused by an auto-repeat mechanism and not an actual key
    press.

    Note that this function can only be used in the server process.

    \sa processKeyEvent(), {Qt for Embedded Linux Character Input}
*/
void QWSServer::sendKeyEvent(int unicode, int keycode, Qt::KeyboardModifiers modifiers,
                             bool isPress, bool autoRepeat)
{
    qws_keyModifiers = modifiers;

    if (isPress) {
        if (keycode != Qt::Key_F34 && keycode != Qt::Key_F35)
            qwsServerPrivate->_q_screenSaverWake();
    }

#ifndef QT_NO_QWS_INPUTMETHODS

    if (!current_IM || !current_IM->filter(unicode, keycode, modifiers, isPress, autoRepeat))
        QWSServerPrivate::sendKeyEventUnfiltered(unicode, keycode, modifiers, isPress, autoRepeat);
#else
    QWSServerPrivate::sendKeyEventUnfiltered(unicode, keycode, modifiers, isPress, autoRepeat);
#endif
}

void QWSServerPrivate::sendKeyEventUnfiltered(int unicode, int keycode, Qt::KeyboardModifiers modifiers,
                                       bool isPress, bool autoRepeat)
{

    QWSKeyEvent event;
    QWSWindow *win = keyboardGrabber ? keyboardGrabber :
        qwsServerPrivate->focusw;

    event.simpleData.window = win ? win->winId() : 0;

    event.simpleData.unicode =
#ifndef QT_NO_QWS_KEYBOARD
        unicode < 0 ? keyUnicode(keycode) :
#endif
        unicode;
    event.simpleData.keycode = keycode;
    event.simpleData.modifiers = modifiers;
    event.simpleData.is_press = isPress;
    event.simpleData.is_auto_repeat = autoRepeat;

    QWSClient *serverClient = qwsServerPrivate->clientMap.value(-1);
    QWSClient *winClient = win ? win->client() : 0;
    if (serverClient)
        serverClient->sendEvent(&event);
    if (winClient && winClient != serverClient)
        winClient->sendEvent(&event);
}

/*!
    \internal
*/
void QWSServer::beginDisplayReconfigure()
{
    qwsServer->enablePainting(false);
#ifndef QT_NO_QWS_CURSOR
    if (qt_screencursor)
        qt_screencursor->hide();
#endif
    QWSDisplay::grab(true);
    qt_screen->disconnect();
}

/*!
    \internal
*/
void QWSServer::endDisplayReconfigure()
{
    qt_screen->connect(QString());
    qwsServerPrivate->swidth = qt_screen->deviceWidth();
    qwsServerPrivate->sheight = qt_screen->deviceHeight();

    QWSDisplay::ungrab();
#ifndef QT_NO_QWS_CURSOR
    if (qt_screencursor)
        qt_screencursor->show();
#endif
    QApplicationPrivate *ap = QApplicationPrivate::instance();
    ap->setMaxWindowRect(qt_screen, 0,
                         QRect(0, 0, qt_screen->width(), qt_screen->height()));
    QSize olds = qApp->desktop()->size();
    qApp->desktop()->resize(qt_screen->width(), qt_screen->height());
    qApp->postEvent(qApp->desktop(), new QResizeEvent(qApp->desktop()->size(), olds));
    qwsServer->enablePainting(true);
    qwsServer->refresh();
    qDebug("Desktop size: %dx%d", qApp->desktop()->width(), qApp->desktop()->height());
}

void QWSServerPrivate::resetEngine()
{
#ifndef QT_NO_QWS_CURSOR
    if (!qt_screencursor)
        return;
    qt_screencursor->hide();
    qt_screencursor->show();
#endif
}


#ifndef QT_NO_QWS_CURSOR
/*!
    \fn void QWSServer::setCursorVisible(bool visible)

    Shows the cursor if \a visible is true: otherwise the cursor is
    hidden.

    Note that this function can only be used in the server process.

    \sa isCursorVisible()
*/
void QWSServer::setCursorVisible(bool vis)
{
    if (qwsServerPrivate && qwsServerPrivate->haveviscurs != vis) {
        QWSCursor* c = qwsServerPrivate->cursor;
        qwsServerPrivate->setCursor(QWSCursor::systemCursor(Qt::BlankCursor));
        qwsServerPrivate->haveviscurs = vis;
        qwsServerPrivate->setCursor(c);
    }
}

/*!
    Returns true if the cursor is visible; otherwise returns false.

    Note that this function can only be used in the server process.

    \sa setCursorVisible()
*/
bool QWSServer::isCursorVisible()
{
    return qwsServerPrivate ? qwsServerPrivate->haveviscurs : true;
}
#endif

#ifndef QT_NO_QWS_INPUTMETHODS


/*!
    \fn void QWSServer::sendIMEvent(const QInputMethodEvent *event)

    Sends the given input method \a event.

    The \c QInputMethodEvent class is derived from QWSEvent, i.e., it
    is a QWSEvent object of the QWSEvent::IMEvent type.

    If there is a window actively composing the preedit string, the
    event is sent to that window. Otherwise, the event is sent to the
    window currently in focus.

    \sa sendIMQuery(), QWSInputMethod::sendEvent()
*/
void QWSServer::sendIMEvent(const QInputMethodEvent *ime)
{
    QWSIMEvent event;

    QWSWindow *win = keyboardGrabber ? keyboardGrabber :
                     qwsServerPrivate->focusw;

    //if currently composing then event must go to the composing window

    if (current_IM_composing_win)
        win = current_IM_composing_win;

    event.simpleData.window = win ? win->winId() : 0;
    event.simpleData.replaceFrom = ime->replacementStart();;
    event.simpleData.replaceLength = ime->replacementLength();

    QBuffer buffer;
    buffer.open(QIODevice::WriteOnly);
    QDataStream out(&buffer);

    out << ime->preeditString();
    out << ime->commitString();

    const QList<QInputMethodEvent::Attribute> &attributes = ime->attributes();
    for (int i = 0; i < attributes.count(); ++i) {
        const QInputMethodEvent::Attribute &a = attributes.at(i);
        out << a.type << a.start << a.length << a.value;
    }
    event.setData(buffer.data(), buffer.size());
    QWSClient *serverClient = qwsServerPrivate->clientMap.value(-1);
    if (serverClient)
        serverClient->sendEvent(&event);
    if (win && win->client() && win->client() != serverClient)
        win->client()->sendEvent(&event);

    current_IM_composing_win = ime->preeditString().isEmpty() ? 0 : win;
    current_IM_winId = win ? win->winId() : 0;
}


/*!
    Sends an input method query for the given \a property.

    To receive responses to input method queries, the virtual
    QWSInputMethod::queryResponse() function must be reimplemented in
    a QWSInputMethod subclass that is activated using the
    setCurrentInputMethod() function.

    \sa sendIMEvent(), setCurrentInputMethod()
*/
void QWSServer::sendIMQuery(int property)
{
    QWSIMQueryEvent event;

    QWSWindow *win = keyboardGrabber ? keyboardGrabber :
                     qwsServerPrivate->focusw;
    if (current_IM_composing_win)
        win = current_IM_composing_win;

    event.simpleData.window = win ? win->winId() : 0;
    event.simpleData.property = property;
    if (win && win->client())
        win->client()->sendEvent(&event);
}



/*!
    \fn void QWSServer::setCurrentInputMethod(QWSInputMethod *method)

    Sets the current input method to be the given \a method.

    Note that this function can only be used in the server process.

    \sa sendIMQuery(), sendIMEvent()
*/
void QWSServer::setCurrentInputMethod(QWSInputMethod *im)
{
    if (current_IM)
        current_IM->reset(); //??? send an update event instead ?
    current_IM = im;
}

/*!
    \fn static void QWSServer::resetInputMethod()

    \internal
*/

#endif //QT_NO_QWS_INPUTMETHODS

#ifndef QT_NO_QWS_PROPERTIES
/*!
  \internal
*/
void QWSServer::sendPropertyNotifyEvent(int property, int state)
{
    Q_D(QWSServer);
    QWSServerPrivate::ClientIterator it = d->clientMap.begin();
    while (it != d->clientMap.end()) {
        QWSClient *cl = *it;
        ++it;
        cl->sendPropertyNotifyEvent(property, state);
    }
}
#endif

void QWSServerPrivate::invokeIdentify(const QWSIdentifyCommand *cmd, QWSClient *client)
{
    client->setIdentity(cmd->id);
#ifndef QT_NO_QWS_MULTIPROCESS
    if (client->clientId() > 0)
        client->d_func()->setLockId(cmd->simpleData.idLock);
#endif
}

void QWSServerPrivate::invokeCreate(QWSCreateCommand *cmd, QWSClient *client)
{
    QWSCreationEvent event;
    event.simpleData.objectid = get_object_id(cmd->count);
    event.simpleData.count = cmd->count;
    client->sendEvent(&event);
}

void QWSServerPrivate::invokeRegionName(const QWSRegionNameCommand *cmd, QWSClient *client)
{
    Q_Q(QWSServer);
    QWSWindow* changingw = findWindow(cmd->simpleData.windowid, client);
    if (changingw && (changingw->name() != cmd->name || changingw->caption() !=cmd->caption)) {
        changingw->setName(cmd->name);
        changingw->setCaption(cmd->caption);
        emit q->windowEvent(changingw, QWSServer::Name);
    }
}

void QWSServerPrivate::invokeRegion(QWSRegionCommand *cmd, QWSClient *client)
{
#ifdef QWS_REGION_DEBUG
    qDebug("QWSServer::invokeRegion %d rects (%d)",
            cmd->simpleData.nrectangles, cmd->simpleData.windowid);
#endif

    QWSWindow* changingw = findWindow(cmd->simpleData.windowid, 0);
    if (!changingw) {
        qWarning("Invalid window handle %08x",cmd->simpleData.windowid);
        return;
    }
    if (!changingw->forClient(client)) {
        qWarning("Disabled: clients changing other client's window region");
        return;
    }

    request_region(cmd->simpleData.windowid, cmd->surfaceKey, cmd->surfaceData,
                   cmd->region);
}

void QWSServerPrivate::invokeRegionMove(const QWSRegionMoveCommand *cmd, QWSClient *client)
{
    Q_Q(QWSServer);
    QWSWindow* changingw = findWindow(cmd->simpleData.windowid, 0);
    if (!changingw) {
        qWarning("invokeRegionMove: Invalid window handle %d",cmd->simpleData.windowid);
        return;
    }
    if (!changingw->forClient(client)) {
        qWarning("Disabled: clients changing other client's window region");
        return;
    }

//    changingw->setNeedAck(true);
    moveWindowRegion(changingw, cmd->simpleData.dx, cmd->simpleData.dy);
    emit q->windowEvent(changingw, QWSServer::Geometry);
}

void QWSServerPrivate::invokeRegionDestroy(const QWSRegionDestroyCommand *cmd, QWSClient *client)
{
    Q_Q(QWSServer);
    QWSWindow* changingw = findWindow(cmd->simpleData.windowid, 0);
    if (!changingw) {
        qWarning("invokeRegionDestroy: Invalid window handle %d",cmd->simpleData.windowid);
        return;
    }
    if (!changingw->forClient(client)) {
        qWarning("Disabled: clients changing other client's window region");
        return;
    }

    setWindowRegion(changingw, QRegion());
//    rgnMan->remove(changingw->allocationIndex());
    for (int i = 0; i < windows.size(); ++i) {
        if (windows.at(i) == changingw) {
            windows.takeAt(i);
            if (i < nReserved)
                --nReserved;
            break;
        }
    }

    handleWindowClose(changingw);
#ifndef QT_NO_QWS_PROPERTIES
    propertyManager.removeProperties(changingw->winId());
#endif
    emit q->windowEvent(changingw, QWSServer::Destroy);
    delete changingw;
}

void QWSServerPrivate::invokeSetFocus(const QWSRequestFocusCommand *cmd, QWSClient *client)
{
    int winId = cmd->simpleData.windowid;
    int gain = cmd->simpleData.flag;

    if (gain != 0 && gain != 1) {
        qWarning("Only 0(lose) and 1(gain) supported");
        return;
    }

    QWSWindow* changingw = findWindow(winId, 0);
    if (!changingw)
        return;

    if (!changingw->forClient(client)) {
       qWarning("Disabled: clients changing other client's focus");
        return;
    }

    setFocus(changingw, gain);
}

void QWSServerPrivate::setFocus(QWSWindow* changingw, bool gain)
{
    Q_Q(QWSServer);
#ifndef QT_NO_QWS_INPUTMETHODS
    /*
      This is the logic:
      QWSWindow *loser = 0;
      if (gain && focusw != changingw)
         loser = focusw;
      else if (!gain && focusw == changingw)
         loser = focusw;
      But these five lines can be reduced to one:
    */
    if (current_IM) {
        QWSWindow *loser =  (!gain == (focusw==changingw)) ? focusw : 0;
        if (loser && loser->winId() == current_IM_winId)
            current_IM->updateHandler(QWSInputMethod::FocusOut);
    }
#endif
    if (gain) {
        if (focusw != changingw) {
            if (focusw) focusw->focus(0);
            focusw = changingw;
            focusw->focus(1);
            emit q->windowEvent(focusw, QWSServer::Active);
        }
    } else if (focusw == changingw) {
        if (changingw->client())
            changingw->focus(0);
        focusw = 0;
        // pass focus to window which most recently got it...
        QWSWindow* bestw=0;
        for (int i=0; i<windows.size(); ++i) {
            QWSWindow* w = windows.at(i);
            if (w != changingw && !w->hidden() &&
                    (!bestw || bestw->focusPriority() < w->focusPriority()))
                bestw = w;
        }
        if (!bestw && changingw->focusPriority()) { // accept focus back?
            bestw = changingw; // must be the only one
        }
        focusw = bestw;
        if (focusw) {
            focusw->focus(1);
            emit q->windowEvent(focusw, QWSServer::Active);
        }
    }
}



void QWSServerPrivate::invokeSetOpacity(const QWSSetOpacityCommand *cmd, QWSClient *client)
{
    Q_UNUSED( client );
    int winId = cmd->simpleData.windowid;
    int opacity = cmd->simpleData.opacity;

    QWSWindow* changingw = findWindow(winId, 0);

    if (!changingw) {
        qWarning("invokeSetOpacity: Invalid window handle %d", winId);
        return;
    }

    int altitude = windows.indexOf(changingw);
    const bool wasOpaque = changingw->isOpaque();
    changingw->_opacity = opacity;
    if (wasOpaque != changingw->isOpaque())
        update_regions();
    exposeRegion(changingw->allocatedRegion(), altitude);
}

void QWSServerPrivate::invokeSetAltitude(const QWSChangeAltitudeCommand *cmd,
                                   QWSClient *client)
{
    Q_UNUSED(client);

    int winId = cmd->simpleData.windowid;
    int alt = cmd->simpleData.altitude;
    bool fixed = cmd->simpleData.fixed;
#if 0
    qDebug("QWSServer::invokeSetAltitude winId %d alt %d)", winId, alt);
#endif

    if (alt < -1 || alt > 1) {
        qWarning("QWSServer::invokeSetAltitude Only lower, raise and stays-on-top supported");
        return;
    }

    QWSWindow* changingw = findWindow(winId, 0);
    if (!changingw) {
        qWarning("invokeSetAltitude: Invalid window handle %d", winId);
        return;
    }

    if (fixed && alt >= 1) {
        changingw->onTop = true;
    }
    if (alt == QWSChangeAltitudeCommand::Lower)
        changingw->lower();
    else
        changingw->raise();

//      if (!changingw->forClient(client)) {
//         refresh();
//     }
}

#ifndef QT_NO_QWS_PROPERTIES
void QWSServerPrivate::invokeAddProperty(QWSAddPropertyCommand *cmd)
{
    propertyManager.addProperty(cmd->simpleData.windowid, cmd->simpleData.property);
}

void QWSServerPrivate::invokeSetProperty(QWSSetPropertyCommand *cmd)
{
    Q_Q(QWSServer);
    if (propertyManager.setProperty(cmd->simpleData.windowid,
                                    cmd->simpleData.property,
                                    cmd->simpleData.mode,
                                    cmd->data,
                                    cmd->rawLen)) {
        q->sendPropertyNotifyEvent(cmd->simpleData.property,
                                 QWSPropertyNotifyEvent::PropertyNewValue);
#ifndef QT_NO_QWS_INPUTMETHODS
        if (cmd->simpleData.property == QT_QWS_PROPERTY_MARKEDTEXT) {
            QString s((const QChar*)cmd->data, cmd->rawLen/2);
            emit q->markedText(s);
        }
#endif
    }
}

void QWSServerPrivate::invokeRemoveProperty(QWSRemovePropertyCommand *cmd)
{
    Q_Q(QWSServer);
    if (propertyManager.removeProperty(cmd->simpleData.windowid,
                                       cmd->simpleData.property)) {
        q->sendPropertyNotifyEvent(cmd->simpleData.property,
                                 QWSPropertyNotifyEvent::PropertyDeleted);
    }
}


bool QWSServerPrivate:: get_property(int winId, int property, const char *&data, int &len)
{
    return propertyManager.getProperty(winId, property, data, len);
}


void QWSServerPrivate::invokeGetProperty(QWSGetPropertyCommand *cmd, QWSClient *client)
{
    const char *data;
    int len;

    if (propertyManager.getProperty(cmd->simpleData.windowid,
                                    cmd->simpleData.property,
                                    data, len)) {
        client->sendPropertyReplyEvent(cmd->simpleData.property, len, data);
    } else {
        client->sendPropertyReplyEvent(cmd->simpleData.property, -1, 0);
    }
}
#endif //QT_NO_QWS_PROPERTIES

void QWSServerPrivate::invokeSetSelectionOwner(QWSSetSelectionOwnerCommand *cmd)
{
    qDebug("QWSServer::invokeSetSelectionOwner");

    SelectionOwner so;
    so.windowid = cmd->simpleData.windowid;
    so.time.set(cmd->simpleData.hour, cmd->simpleData.minute,
                 cmd->simpleData.sec, cmd->simpleData.ms);

    if (selectionOwner.windowid != -1) {
        QWSWindow *win = findWindow(selectionOwner.windowid, 0);
        if (win)
            win->client()->sendSelectionClearEvent(selectionOwner.windowid);
        else
            qDebug("couldn't find window %d", selectionOwner.windowid);
    }

    selectionOwner = so;
}

void QWSServerPrivate::invokeConvertSelection(QWSConvertSelectionCommand *cmd)
{
    qDebug("QWSServer::invokeConvertSelection");

    if (selectionOwner.windowid != -1) {
        QWSWindow *win = findWindow(selectionOwner.windowid, 0);
        if (win)
            win->client()->sendSelectionRequestEvent(cmd, selectionOwner.windowid);
        else
            qDebug("couldn't find window %d", selectionOwner.windowid);
    }
}

#ifndef QT_NO_QWS_CURSOR
void QWSServerPrivate::invokeDefineCursor(QWSDefineCursorCommand *cmd, QWSClient *client)
{
    if (cmd->simpleData.height > 64 || cmd->simpleData.width > 64) {
        qDebug("Cannot define cursor size > 64x64");
        return;
    }

    delete client->cursors.take(cmd->simpleData.id);

    int dataLen = cmd->simpleData.height * ((cmd->simpleData.width+7) / 8);

    if (dataLen > 0 && cmd->data) {
        QWSCursor *curs = new QWSCursor(cmd->data, cmd->data + dataLen,
                                        cmd->simpleData.width, cmd->simpleData.height,
                                        cmd->simpleData.hotX, cmd->simpleData.hotY);
        client->cursors.insert(cmd->simpleData.id, curs);
    }
}

void QWSServerPrivate::invokeSelectCursor(QWSSelectCursorCommand *cmd, QWSClient *client)
{
    int id = cmd->simpleData.id;
    QWSCursor *curs = 0;
    if (id <= Qt::LastCursor) {
        curs = QWSCursor::systemCursor(id);
    }
    else {
        QWSCursorMap cursMap = client->cursors;
        QWSCursorMap::Iterator it = cursMap.find(id);
        if (it != cursMap.end()) {
            curs = it.value();
        }
    }
    if (curs == 0) {
        curs = QWSCursor::systemCursor(Qt::ArrowCursor);
    }

    QWSWindow* win = findWindow(cmd->simpleData.windowid, 0);
    if (mouseGrabber) {
        // If the mouse is being grabbed, we don't want just anyone to
        // be able to change the cursor.  We do want the cursor to be set
        // correctly once mouse grabbing is stopped though.
        if (win != mouseGrabber)
            nextCursor = curs;
        else
            setCursor(curs);
    } else if (win && win->allocatedRegion().contains(QWSServer::mousePosition)) { //##################### cursor
        // A non-grabbing window can only set the cursor shape if the
        // cursor is within its allocated region.
        setCursor(curs);
    }
}

void QWSServerPrivate::invokePositionCursor(QWSPositionCursorCommand *cmd, QWSClient *)
{
    Q_Q(QWSServer);
    QPoint newPos(cmd->simpleData.newX, cmd->simpleData.newY);
    if (newPos != QWSServer::mousePosition)
        q->sendMouseEvent(newPos, qwsServer->d_func()->mouseState);
}
#endif

void QWSServerPrivate::invokeGrabMouse(QWSGrabMouseCommand *cmd, QWSClient *client)
{
    QWSWindow* win = findWindow(cmd->simpleData.windowid, 0);
    if (!win)
        return;

    if (cmd->simpleData.grab) {
        if (!mouseGrabber || mouseGrabber->client() == client) {
            mouseGrabbing = true;
            mouseGrabber = win;
        }
    } else {
        releaseMouse(mouseGrabber);
    }
}

void QWSServerPrivate::invokeGrabKeyboard(QWSGrabKeyboardCommand *cmd, QWSClient *client)
{
    QWSWindow* win = findWindow(cmd->simpleData.windowid, 0);
    if (!win)
        return;

    if (cmd->simpleData.grab) {
        if (!keyboardGrabber || (keyboardGrabber->client() == client)) {
            keyboardGrabbing = true;
            keyboardGrabber = win;
        }
    } else {
        releaseKeyboard(keyboardGrabber);
    }
}

#if !defined(QT_NO_SOUND)
void QWSServerPrivate::invokePlaySound(QWSPlaySoundCommand *cmd, QWSClient *)
{
#if !defined(QT_EXTERNAL_SOUND_SERVER) && !defined(Q_OS_DARWIN)
    soundserver->playFile( 1, cmd->filename );
#else
    Q_UNUSED(cmd);
#endif
}
#endif

#ifndef QT_NO_COP
void QWSServerPrivate::invokeRegisterChannel(QWSQCopRegisterChannelCommand *cmd,
                                       QWSClient *client)
{
  // QCopChannel will force us to emit the newChannel signal if this channel
  // didn't already exist.
  QCopChannel::registerChannel(cmd->channel, client);
}

void QWSServerPrivate::invokeQCopSend(QWSQCopSendCommand *cmd, QWSClient *client)
{
    QCopChannel::answer(client, cmd->channel, cmd->message, cmd->data);
}

#endif

#ifndef QT_NO_QWS_INPUTMETHODS
void QWSServer::resetInputMethod()
{
    if (current_IM && qwsServer) {
      current_IM->reset();
    }
}

void QWSServerPrivate::invokeIMResponse(const QWSIMResponseCommand *cmd,
                                 QWSClient *)
{
    if (current_IM)
        current_IM->queryResponse(cmd->simpleData.property, cmd->result);
}

void QWSServerPrivate::invokeIMUpdate(const QWSIMUpdateCommand *cmd,
                                 QWSClient *)
{
    if (cmd->simpleData.type == QWSInputMethod::FocusIn)
        current_IM_winId = cmd->simpleData.windowid;

    if (current_IM && (current_IM_winId == cmd->simpleData.windowid || cmd->simpleData.windowid == -1))
        current_IM->updateHandler(cmd->simpleData.type);
}

#endif

void QWSServerPrivate::invokeFont(const QWSFontCommand *cmd, QWSClient *client)
{
    QWSClientPrivate *priv = client->d_func();
    if (cmd->simpleData.type == QWSFontCommand::StartedUsingFont) {
        referenceFont(priv, cmd->fontName);
    } else if (cmd->simpleData.type == QWSFontCommand::StoppedUsingFont) {
        dereferenceFont(priv, cmd->fontName);
    }
}

void QWSServerPrivate::invokeRepaintRegion(QWSRepaintRegionCommand * cmd,
                                           QWSClient *)
{
    QRegion r;
    r.setRects(cmd->rectangles,cmd->simpleData.nrectangles);
    repaint_region(cmd->simpleData.windowid, cmd->simpleData.windowFlags, cmd->simpleData.opaque, r);
}

#ifndef QT_NO_QWSEMBEDWIDGET
void QWSServerPrivate::invokeEmbed(QWSEmbedCommand *cmd, QWSClient *client)
{
    // Should find these two windows in a single loop
    QWSWindow *embedder = findWindow(cmd->simpleData.embedder, client);
    QWSWindow *embedded = findWindow(cmd->simpleData.embedded);

    if (!embedder) {
        qWarning("QWSServer: Embed command from window %i failed: No such id.",
                 static_cast<int>(cmd->simpleData.embedder));
        return;
    }

    if (!embedded) {
        qWarning("QWSServer: Embed command on window %i failed: No such id.",
                 static_cast<int>(cmd->simpleData.embedded));
        return;
    }

    switch (cmd->simpleData.type) {
    case QWSEmbedEvent::StartEmbed:
        embedder->startEmbed(embedded);
        windows.removeAll(embedded);
        windows.insert(windows.indexOf(embedder), embedded);
        break;
    case QWSEmbedEvent::StopEmbed:
        embedder->stopEmbed(embedded);
        break;
    case QWSEmbedEvent::Region:
        break;
    }

    embedded->client()->sendEmbedEvent(embedded->winId(),
                                       cmd->simpleData.type, cmd->region);
    const QRegion oldAllocated = embedded->allocatedRegion();
    update_regions();
    exposeRegion(oldAllocated - embedded->allocatedRegion(),
                 windows.indexOf(embedded));
}
#endif // QT_NO_QWSEMBEDWIDGET

void QWSServerPrivate::invokeScreenTransform(const QWSScreenTransformCommand *cmd,
                                             QWSClient *client)
{
    Q_UNUSED(client);

    QWSScreenTransformationEvent event;
    event.simpleData.screen = cmd->simpleData.screen;
    event.simpleData.transformation = cmd->simpleData.transformation;

    QMap<int, QWSClient*>::const_iterator it = clientMap.constBegin();
    for (; it != clientMap.constEnd(); ++it)
        (*it)->sendEvent(&event);
}

QWSWindow* QWSServerPrivate::newWindow(int id, QWSClient* client)
{
    Q_Q(QWSServer);
    // Make a new window, put it on top.
    QWSWindow* w = new QWSWindow(id,client);

    // insert after "stays on top" windows
    bool added = false;
    for (int i = nReserved; i < windows.size(); ++i) {
        QWSWindow *win = windows.at(i);
        if (!win->onTop) {
            windows.insert(i, w);
            added = true;
            break;
        }
    }
    if (!added)
        windows.append(w);
    emit q->windowEvent(w, QWSServer::Create);
    return w;
}

QWSWindow* QWSServerPrivate::findWindow(int windowid, QWSClient* client)
{
    for (int i=0; i<windows.size(); ++i) {
        QWSWindow* w = windows.at(i);
        if (w->winId() == windowid)
            return w;
    }
    if (client)
        return newWindow(windowid,client);
    else
        return 0;
}

void QWSServerPrivate::raiseWindow(QWSWindow *changingw, int /*alt*/)
{
    Q_Q(QWSServer);
    if (changingw == windows.first())
        return;
    QWSWindow::State oldstate = changingw->d->state;
    changingw->d->state = QWSWindow::Raising;
    // Expose regions previously overlapped by transparent windows
    const QRegion bound = changingw->allocatedRegion();
    QRegion expose;
    int windowPos = 0;

    //change position in list:
    for (int i = 0; i < windows.size(); ++i) {
        QWSWindow *w = windows.at(i);
        if (w == changingw) {
            windowPos = i;
            windows.takeAt(i);
            break;
        }
        if (!w->isOpaque())
            expose += (w->allocatedRegion() & bound);
    }

    bool onTop = changingw->onTop;

#ifndef QT_NO_QWSEMBEDWIDGET
    // an embedded window is on top if the embedder is on top
    QWSWindow *embedder = changingw->d->embedder;
    while (!onTop && embedder) {
        onTop = embedder->onTop;
        embedder = embedder->d->embedder;
    }
#endif

    int newPos = -1;
    if (onTop) {
        windows.insert(nReserved, changingw);
        newPos = nReserved;
    } else {
        // insert after "stays on top" windows
        bool in = false;
        for (int i = nReserved; i < windows.size(); ++i) {
            QWSWindow *w = windows.at(i);
            if (!w->onTop) {
                windows.insert(i, changingw);
                in = true;
                newPos = i;
                break;
            }
        }
        if (!in) {
            windows.append(changingw);
            newPos = windows.size()-1;
        }
    }

    if (windowPos != newPos) {
        update_regions();
        if (!expose.isEmpty())
            exposeRegion(expose, newPos);
    }
    changingw->d->state = oldstate;
    emit q->windowEvent(changingw, QWSServer::Raise);
}

void QWSServerPrivate::lowerWindow(QWSWindow *changingw, int /*alt*/)
{
    Q_Q(QWSServer);
    if (changingw == windows.last())
        return;
    QWSWindow::State oldstate = changingw->d->state;
    changingw->d->state = QWSWindow::Lowering;

    int i = windows.indexOf(changingw);
    int newIdx = windows.size()-1;
    windows.move(i, newIdx);

    const QRegion bound = changingw->allocatedRegion();

    update_regions();

    // Expose regions previously overlapped by transparent window
    if (!changingw->isOpaque()) {
        QRegion expose;
        for (int j = i; j < windows.size() - 1; ++j)
            expose += (windows.at(j)->allocatedRegion() & bound);
        if (!expose.isEmpty())
            exposeRegion(expose, newIdx);
    }

    changingw->d->state = oldstate;
    emit q->windowEvent(changingw, QWSServer::Lower);
}

void QWSServerPrivate::update_regions()
{
    if (disablePainting)
        return;

    QRegion available = QRect(0, 0, qt_screen->width(), qt_screen->height());
    QRegion transparentRegion;

    // only really needed if there are unbuffered surfaces...
    const bool doLock = (clientMap.size() > 1);
    if (doLock)
        QWSDisplay::grab(true);

    for (int i = 0; i < windows.count(); ++i) {
        QWSWindow *w = windows.at(i);
        QRegion r = (w->requested_region & available);

#ifndef QT_NO_QWSEMBEDWIDGET
        // Subtract regions needed for embedded windows
        const int n = w->d->embedded.size();
        for (int i = 0; i < n; ++i)
            r -= w->d->embedded.at(i)->allocatedRegion();

        // Limited to the embedder region
        if (w->d->embedder)
            r &= w->d->embedder->requested_region;
#endif // QT_NO_QWSEMBEDWIDGET

        QWSWindowSurface *surface = w->windowSurface();
        const bool opaque = w->isOpaque()
                            && (w->d->painted || !surface || !surface->isBuffered());

        if (!opaque) {
            transparentRegion += r;
        } else {
            if (surface && (surface->isRegionReserved() || !surface->isBuffered()))
                r -= transparentRegion;
            available -= r;
        }

        if (r != w->allocatedRegion()) {
            w->setAllocatedRegion(r);
            w->client()->sendRegionEvent(w->winId(), r,
                                         QWSRegionEvent::Allocation);
        }

#ifdef QT_QWS_CLIENTBLIT
#ifdef QT_NO_QWS_CURSOR
        // This optimization only really works when there isn't a crazy cursor
        // wizzing around.
        QRegion directPaint = (r - transparentRegion); // in gloal coords
        if(directPaint != w->directPaintRegion()) {
            w->setDirectPaintRegion(directPaint);
            static int id = 0;
            surface->setDirectRegion(directPaint, ++id);
            w->client()->sendRegionEvent(w->winId(), directPaint,
                                         QWSRegionEvent::DirectPaint, id);
        }
#endif
#endif
    }

    if (doLock)
        QWSDisplay::ungrab();
}

void QWSServerPrivate::moveWindowRegion(QWSWindow *changingw, int dx, int dy)
{
    if (!changingw)
        return;

    QWSWindow::State oldState = changingw->d->state;
    changingw->d->state = QWSWindow::Moving;
    const QRegion oldRegion(changingw->allocatedRegion());
    changingw->requested_region.translate(dx, dy);

    // hw: Even if the allocated region doesn't change, the requested region
    // region has changed and we need to send region events.
    // Resetting the allocated region to force update_regions to send events.
    changingw->setAllocatedRegion(QRegion());
    update_regions();
    const QRegion newRegion(changingw->allocatedRegion());

    QWSWindowSurface *surface = changingw->windowSurface();
    QRegion expose;
    if (surface)
        expose = surface->move(QPoint(dx, dy), changingw->allocatedRegion());
    else
        expose = oldRegion + newRegion;

    if (!changingw->d->painted && !expose.isEmpty())
        expose = oldRegion - newRegion;

    int idx = windows.indexOf(changingw);
    exposeRegion(expose, idx);
    changingw->d->state = oldState;
}

/*!
    Changes the requested region of window \a changingw to \a r
    If \a changingw is 0, the server's reserved region is changed.
*/
void QWSServerPrivate::setWindowRegion(QWSWindow* changingw, const QRegion &r)
{
    if (!changingw) {
        qWarning("Not implemented in this release");
        return;
    }

    if (changingw->requested_region == r)
        return;

    const QRegion oldRegion(changingw->allocatedRegion());
    changingw->requested_region = r;
    update_regions();
    const QRegion newRegion(changingw->allocatedRegion());

    int idx = windows.indexOf(changingw);
    exposeRegion(oldRegion - newRegion, idx);
}


void QWSServerPrivate::exposeRegion(const QRegion &r, int changing)
{
    if (disablePainting)
        return;

    if (r.isEmpty())
        return;

    static bool initial = true;
    if (initial) {
        changing = 0;
        initial = false;
        qt_screen->exposeRegion(qt_screen->region(), changing);
    } else {
        qt_screen->exposeRegion(r, changing);
    }
}

/*!
    Closes all pointer devices (specified by the QWS_MOUSE_PROTO
    environment variable) by deleting the associated mouse drivers.

    \sa openMouse(), mouseHandler()
*/
void QWSServer::closeMouse()
{
    Q_D(QWSServer);
    qDeleteAll(d->mousehandlers);
    d->mousehandlers.clear();
}

/*!
    Opens the mouse devices specified by the QWS_MOUSE_PROTO
    environment variable. Be advised that closeMouse() is called first
    to delete all the existing mouse handlers. This behaviour could be
    the cause of problems if you were not expecting it.

    \sa closeMouse(), mouseHandler()
*/
void QWSServer::openMouse()
{
    Q_D(QWSServer);
    QString mice = QString::fromLatin1(qgetenv("QWS_MOUSE_PROTO"));
#if defined(QT_QWS_CASSIOPEIA)
    if (mice.isEmpty())
        mice = QLatin1String("TPanel:/dev/tpanel");
#endif
    if (mice.isEmpty())
        mice = *defaultMouse();
    closeMouse();
    bool needviscurs = true;
    if (mice != QLatin1String("None")) {
        const QStringList mouse = mice.split(QLatin1Char(' '));
        for (int i = mouse.size() - 1; i >= 0; --i) {
            QWSMouseHandler *handler = d->newMouseHandler(mouse.at(i));
            setMouseHandler(handler);
            /* XXX handle mouse cursor visibility sensibly
               if (!h->inherits("QCalibratedMouseHandler"))
               needviscurs = true;
            */
        }
    }
#ifndef QT_NO_QWS_CURSOR
    setCursorVisible(needviscurs);
#else
    Q_UNUSED(needviscurs)
#endif
}

/*!
    Suspends pointer handling by deactivating all the mouse drivers
    registered by the QWS_MOUSE_PROTO environment variable.


    \sa resumeMouse(), QWSMouseHandler::suspend()
*/
void QWSServer::suspendMouse()
{
    Q_D(QWSServer);
    for (int i=0; i < d->mousehandlers.size(); ++i)
        d->mousehandlers.at(i)->suspend();
}

/*!
    Resumes pointer handling by reactivating all the mouse drivers
    registered by the QWS_MOUSE_PROTO environment variable.

    \sa suspendMouse(), QWSMouseHandler::resume()
*/
void QWSServer::resumeMouse()
{
    Q_D(QWSServer);
    for (int i=0; i < d->mousehandlers.size(); ++i)
        d->mousehandlers.at(i)->resume();
}



QWSMouseHandler* QWSServerPrivate::newMouseHandler(const QString& spec)
{
    int c = spec.indexOf(QLatin1Char(':'));
    QString mouseProto;
    QString mouseDev;
    if (c >= 0) {
        mouseProto = spec.left(c);
        mouseDev = spec.mid(c+1);
    } else {
        mouseProto = spec;
    }

    int screen = -1;
    const QList<QRegExp> regexps = QList<QRegExp>()
                                   << QRegExp(QLatin1String(":screen=(\\d+)\\b"))
                                   << QRegExp(QLatin1String("\\bscreen=(\\d+):"));
    for (int i = 0; i < regexps.size(); ++i) {
        QRegExp regexp = regexps.at(i);
        if (regexp.indexIn(mouseDev) == -1)
            continue;
        screen = regexp.cap(1).toInt();
        mouseDev.remove(regexp.pos(0), regexp.matchedLength());
        break;
    }

    QWSMouseHandler *handler = 0;
    handler = QMouseDriverFactory::create(mouseProto, mouseDev);
    if (screen != -1)
        handler->setScreen(qt_screen->subScreens().at(screen));

    return handler;
}

#ifndef QT_NO_QWS_KEYBOARD

/*!
    Closes all the keyboard devices (specified by the QWS_KEYBOARD
    environment variable) by deleting the associated keyboard
    drivers.

    \sa openKeyboard(),  keyboardHandler()
*/
void QWSServer::closeKeyboard()
{
    Q_D(QWSServer);
    qDeleteAll(d->keyboardhandlers);
    d->keyboardhandlers.clear();
}

/*!
    Returns the primary keyboard driver.

    Note that this function can only be used in the server process.

    \sa setKeyboardHandler(), openKeyboard(), closeKeyboard()
*/
QWSKeyboardHandler* QWSServer::keyboardHandler()
{
    return qwsServerPrivate->keyboardhandlers.first();
}

/*!
    \fn void QWSServer::setKeyboardHandler(QWSKeyboardHandler* driver)

    Sets the primary keyboard driver to be the given \a driver.

    \l{Qt for Embedded Linux} provides several ready-made keyboard drivers, and
    custom drivers are typically added using Qt's plugin
    mechanism. See the \l{Qt for Embedded Linux Character Input} documentation
    for details.

    Note that this function can only be used in the server process.

    \sa keyboardHandler(), setDefaultKeyboard()
*/
void QWSServer::setKeyboardHandler(QWSKeyboardHandler* kh)
{
    if (!kh)
        return;
    qwsServerPrivate->keyboardhandlers.removeAll(kh);
    qwsServerPrivate->keyboardhandlers.prepend(kh);
}

/*!
    Opens the keyboard devices specified by the QWS_KEYBOARD
    environment variable.

    \sa closeKeyboard(), keyboardHandler()
*/
void QWSServer::openKeyboard()
{
    QString keyboards = QString::fromLatin1(qgetenv("QWS_KEYBOARD"));
#if defined(QT_QWS_CASSIOPEIA)
    if (keyboards.isEmpty())
        keyboards = QLatin1String("Buttons");
#endif
    if (keyboards.isEmpty())
        keyboards = *defaultKeyboard();

    closeKeyboard();
    if (keyboards == QLatin1String("None"))
        return;

    QString device;
    QString type;
    QStringList keyboard = keyboards.split(QLatin1Char(' '));
    for (int i = keyboard.size() - 1; i >= 0; --i) {
        const QString spec = keyboard.at(i);
        int colon=spec.indexOf(QLatin1Char(':'));
        if (colon>=0) {
            type = spec.left(colon);
            device = spec.mid(colon+1);
        } else {
            type = spec;
            device = QString();
        }
        QWSKeyboardHandler *handler = QKbdDriverFactory::create(type, device);
        setKeyboardHandler(handler);
    }
}

#endif //QT_NO_QWS_KEYBOARD

QPoint QWSServer::mousePosition;
QBrush *QWSServerPrivate::bgBrush = 0;

void QWSServerPrivate::move_region(const QWSRegionMoveCommand *cmd)
{
    QWSClient *serverClient = clientMap.value(-1);
    invokeRegionMove(cmd, serverClient);
}

void QWSServerPrivate::set_altitude(const QWSChangeAltitudeCommand *cmd)
{
    QWSClient *serverClient = clientMap.value(-1);
    invokeSetAltitude(cmd, serverClient);
}

void QWSServerPrivate::set_opacity(const QWSSetOpacityCommand *cmd)
{
    QWSClient *serverClient = clientMap.value(-1);
    invokeSetOpacity(cmd, serverClient);
}


void QWSServerPrivate::request_focus(const QWSRequestFocusCommand *cmd)
{
    invokeSetFocus(cmd, clientMap.value(-1));
}

void QWSServerPrivate::set_identity(const QWSIdentifyCommand *cmd)
{
    invokeIdentify(cmd, clientMap.value(-1));
}

void QWSServerPrivate::repaint_region(int wid, int windowFlags, bool opaque,
                                      const QRegion &region)
{
    QWSWindow* changingw = findWindow(wid, 0);
    if (!changingw) {
        return;
    }

    const bool isOpaque = changingw->opaque;
    const bool wasPainted = changingw->d->painted;
    changingw->opaque = opaque;
    changingw->d->windowFlags = QFlag(windowFlags);
    changingw->d->dirtyOnScreen |= region;
    changingw->d->painted = true;
    if (isOpaque != opaque || !wasPainted)
        update_regions();

    int level = windows.indexOf(changingw);
    exposeRegion(region, level);
    changingw->d->dirtyOnScreen = QRegion();
}

QRegion QWSServerPrivate::reserve_region(QWSWindow *win, const QRegion &region)
{
    QRegion r = region;

    int oldPos = windows.indexOf(win);
    int newPos = oldPos < nReserved ? nReserved - 1 : nReserved;
    for (int i = 0; i < nReserved; ++i) {
        if (i != oldPos) {
            QWSWindow *w = windows.at(i);
            r -= w->requested_region;
        }
    }
    windows.move(oldPos, newPos);
    nReserved = newPos + 1;

    return r;
}

void QWSServerPrivate::request_region(int wid, const QString &surfaceKey,
                                      const QByteArray &surfaceData,
                                      const QRegion &region)
{
    QWSWindow *changingw = findWindow(wid, 0);
    if (!changingw)
        return;

    Q_Q(QWSServer);
    QWSWindow::State windowState = QWSWindow::NoState;

    if (region.isEmpty()) {
        windowState = QWSWindow::Hiding;
        emit q->windowEvent(changingw, QWSServer::Hide);
    }

    const bool wasOpaque = changingw->opaque;

    changingw->createSurface(surfaceKey, surfaceData);
    QWSWindowSurface *surface = changingw->windowSurface();

    changingw->opaque = surface->isOpaque();

    QRegion r;
    if (surface->isRegionReserved())
        r = reserve_region(changingw, region);
    else
        r = region;

    if (!region.isEmpty())  {
        if (changingw->isVisible())
            windowState = QWSWindow::ChangingGeometry;
        else
            windowState = QWSWindow::Showing;
    }
    changingw->d->state = windowState;

    if (!r.isEmpty() && wasOpaque != changingw->opaque && surface->isBuffered())
        changingw->requested_region = QRegion(); // XXX: force update_regions

    const QRegion oldAllocated = changingw->allocatedRegion();
    setWindowRegion(changingw, r);
    if (oldAllocated == changingw->allocatedRegion()) {
        // Always send region event to the requesting window even if the
        // region didn't change. This is necessary as the client will reset
        // the clip region until an event is received.
        changingw->client()->sendRegionEvent(wid, changingw->allocatedRegion(),
                                             QWSRegionEvent::Allocation);
    }

    surface->QWindowSurface::setGeometry(r.boundingRect());

    if (windowState == QWSWindow::Showing)
        emit q->windowEvent(changingw, QWSServer::Show);
    else if (windowState == QWSWindow::ChangingGeometry)
        emit q->windowEvent(changingw, QWSServer::Geometry);
    if (windowState == QWSWindow::Hiding) {
        handleWindowClose(changingw);
        changingw->d->state = QWSWindow::Hidden;
        changingw->d->painted = false;
    } else {
        changingw->d->state = QWSWindow::Visible;
    }
}

void QWSServerPrivate::destroy_region(const QWSRegionDestroyCommand *cmd)
{
    invokeRegionDestroy(cmd, clientMap.value(-1));
}

void QWSServerPrivate::name_region(const QWSRegionNameCommand *cmd)
{
    invokeRegionName(cmd, clientMap.value(-1));
}

#ifndef QT_NO_QWS_INPUTMETHODS
void QWSServerPrivate::im_response(const QWSIMResponseCommand *cmd)
 {
     invokeIMResponse(cmd, clientMap.value(-1));
}

void QWSServerPrivate::im_update(const QWSIMUpdateCommand *cmd)
{
    invokeIMUpdate(cmd, clientMap.value(-1));
}

void QWSServerPrivate::send_im_mouse(const QWSIMMouseCommand *cmd)
{
    if (current_IM)
        current_IM->mouseHandler(cmd->simpleData.index, cmd->simpleData.state);
}
#endif

void QWSServerPrivate::openDisplay()
{
    qt_init_display();

//    rgnMan = qt_fbdpy->regionManager();
    swidth = qt_screen->deviceWidth();
    sheight = qt_screen->deviceHeight();
}

void QWSServerPrivate::closeDisplay()
{
    if (qt_screen)
        qt_screen->shutdownDevice();
}

/*!
    Returns the brush used as background in the absence of obscuring
    windows.

    \sa setBackground()
*/
const QBrush &QWSServer::backgroundBrush() const
{
    return *QWSServerPrivate::bgBrush;
}

/*!
    Sets the brush used as background in the absence of obscuring
    windows, to be the given \a brush.

    Note that this function can only be used in the server process.

    \sa backgroundBrush()
*/
void QWSServer::setBackground(const QBrush &brush)
{
    if (!QWSServerPrivate::bgBrush)
        QWSServerPrivate::bgBrush = new QBrush(brush);
    else
        *QWSServerPrivate::bgBrush = brush;
    if (!qwsServer)
        return;
    qt_screen->exposeRegion(QRect(0,0,qt_screen->width(), qt_screen->height()), 0);
}


#ifdef QT3_SUPPORT
/*!
    \fn void QWSServer::setDesktopBackground(const QImage &image)

    Sets the image used as background in the absence of obscuring
    windows, to be the given \a image.

    Use the setBackground() function instead.

    \oldcode
        QImage image;
        setDesktopBackground(image);
    \newcode
        QImage image;
        setBackground(QBrush(image));
    \endcode
*/
void QWSServer::setDesktopBackground(const QImage &img)
{
    if (img.isNull())
        setBackground(Qt::NoBrush);
    else
        setBackground(QBrush(QPixmap::fromImage(img)));
}

/*!
    \fn void QWSServer::setDesktopBackground(const QColor &color)
    \overload

    Sets the color used as background in the absence of obscuring
    windows, to be the given \a color.

    Use the setBackground() function instead.

    \oldcode
        QColor color;
        setDesktopBackground(color);
    \newcode
        QColor color;
        setBackground(QBrush(color));
    \endcode
*/
void QWSServer::setDesktopBackground(const QColor &c)
{
    setBackground(QBrush(c));
}
#endif //QT3_SUPPORT

/*!
  \internal
 */
void QWSServer::startup(int flags)
{
    if (qwsServer)
        return;
    unlink(qws_qtePipeFilename().toLatin1().constData());
    (void)new QWSServer(flags);
}

/*!
  \internal
*/

void QWSServer::closedown()
{
    QScopedPointer<QWSServer> server(qwsServer);
    qwsServer = 0;
    QT_TRY {
        unlink(qws_qtePipeFilename().toLatin1().constData());
    } QT_CATCH(const std::bad_alloc &) {
        // ### TODO - what to do when we run out of memory
        // when calling toLatin1?
    }
}

void QWSServerPrivate::emergency_cleanup()
{
#ifndef QT_NO_QWS_KEYBOARD
    if (qwsServer)
        qwsServer->closeKeyboard();
#endif
}

#ifndef QT_NO_QWS_KEYBOARD
static QList<QWSServer::KeyboardFilter*> *keyFilters = 0;

/*!
    Processes the given key event. The key is identified by its \a
    unicode value and the given \a keycode, \a modifiers, \a isPress
    and \a autoRepeat parameters.

    The \a keycode parameter is the Qt keycode value as defined by the
    Qt::Key enum. The \a modifiers is an OR combination of
    Qt::KeyboardModifier values, indicating whether \gui
    Shift/Alt/Ctrl keys are pressed. The \a isPress parameter is true
    if the event is a key press event and \a autoRepeat is true if the
    event is caused by an auto-repeat mechanism and not an actual key
    press.

    This function is typically called internally by keyboard drivers.
    Note that this function can only be used in the server process.

    \sa sendKeyEvent(), {Qt for Embedded Linux Character Input}
*/
void QWSServer::processKeyEvent(int unicode, int keycode, Qt::KeyboardModifiers modifiers,
                                bool isPress, bool autoRepeat)
{
    bool block;
    // Don't block the POWER or LIGHT keys
    if ( keycode == Qt::Key_F34 || keycode == Qt::Key_F35 )
        block = false;
    else
        block = qwsServerPrivate->screensaverblockevent(KEY, qwsServerPrivate->screensaverinterval, isPress);

#ifdef EVENT_BLOCK_DEBUG
    qDebug() << "processKeyEvent" << unicode << keycode << modifiers << isPress << autoRepeat << (block ? "block" : "pass");
#endif

    // If we press a key and it's going to be blocked, wake up the screen
    if ( block && isPress )
        qwsServerPrivate->_q_screenSaverWake();

    if ( block )
        return;

    if (keyFilters) {
        for (int i = 0; i < keyFilters->size(); ++i) {
            QWSServer::KeyboardFilter *keyFilter = keyFilters->at(i);
            if (keyFilter->filter(unicode, keycode, modifiers, isPress, autoRepeat))
                return;
        }
    }
    sendKeyEvent(unicode, keycode, modifiers, isPress, autoRepeat);
}

/*!
    \fn void QWSServer::addKeyboardFilter(KeyboardFilter *filter)

    Activates the given keyboard \a filter all key events generated by
    physical keyboard drivers (i.e., events sent using the
    processKeyEvent() function).

    Note that the filter is not invoked for keys generated by \e
    virtual keyboard drivers (i.e., events sent using the
    sendKeyEvent() function).

    Note that this function can only be used in the server process.

    \sa removeKeyboardFilter()
*/
void QWSServer::addKeyboardFilter(KeyboardFilter *f)
{
     if (!keyFilters)
        keyFilters = new QList<QWSServer::KeyboardFilter*>;
     if (f) {
        keyFilters->prepend(f);
     }
}

/*
//#######
 We should probably obsolete the whole keyboard filter thing since
 it's not useful for input methods anyway

 We could do removeKeyboardFilter(KeyboardFilter *f), but
 the "remove and delete the filter" concept does not match "user
 remembers the pointer".
*/

/*!
    Removes and deletes the most recently added filter.

    Note that the programmer is responsible for removing each added
    keyboard filter.

    Note that this function can only be used in the server process.

    \sa addKeyboardFilter()
*/
void QWSServer::removeKeyboardFilter()
{
     if (!keyFilters || keyFilters->isEmpty())
         return;
     delete keyFilters->takeAt(0);
}
#endif // QT_NO_QWS_KEYBOARD

/*!
    \fn void QWSServer::setScreenSaverIntervals(int* intervals)

    Specifies the time \a intervals (in milliseconds) between the
    different levels of screen responsiveness.

    \l{Qt for Embedded Linux} supports multilevel screen saving, i.e., it is
    possible to specify several different levels of screen
    responsiveness by implementing the QWSScreenSaver::save()
    function. For example, you can choose to first turn off the light
    before you fully activate the screensaver. See the QWSScreenSaver
    documentation for details.

    Note that an interval of 0 milliseconds will turn off the
    screensaver, and that the \a intervals array must be 0-terminated.
    This function can only be used in the server process.

    \sa setScreenSaverInterval(), setScreenSaverBlockLevel()
*/
void QWSServer::setScreenSaverIntervals(int* ms)
{
    if (!qwsServerPrivate)
        return;

    delete [] qwsServerPrivate->screensaverintervals;
    if (ms) {
        int* t=ms;
        int n=0;
        while (*t++) n++;
        if (n) {
            n++; // the 0
            qwsServerPrivate->screensaverintervals = new int[n];
            memcpy(qwsServerPrivate->screensaverintervals, ms, n*sizeof(int));
        } else {
            qwsServerPrivate->screensaverintervals = 0;
        }
    } else {
        qwsServerPrivate->screensaverintervals = 0;
    }
    qwsServerPrivate->screensaverinterval = 0;

    qwsServerPrivate->screensavertimer->stop();
    qt_screen->blank(false);
    qwsServerPrivate->_q_screenSaverWake();
}

/*!
    \fn void QWSServer::setScreenSaverInterval(int milliseconds)

    Sets the timeout interval for the screensaver to the specified \a
    milliseconds. To turn off the screensaver, set the timout interval
    to 0.

    Note that this function can only be used in the server process.

    \sa setScreenSaverIntervals(), setScreenSaverBlockLevel()
*/
void QWSServer::setScreenSaverInterval(int ms)
{
    int v[2];
    v[0] = ms;
    v[1] = 0;
    setScreenSaverIntervals(v);
}

/*!
  Block the key or mouse event that wakes the system from level \a eventBlockLevel or higher.
  To completely disable event blocking (the default behavior), set \a eventBlockLevel to -1.

  The algorithm blocks the "down", "up" as well as any "repeat" events for the same key
  but will not block other key events after the initial "down" event. For mouse events, the
  algorithm blocks all mouse events until an event with no buttons pressed is received.

  There are 2 keys that are never blocked, Qt::Key_F34 (POWER) and Qt::Key_F35 (LIGHT).

  Example usage:

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

    Note that this function can only be used in the server process.

  \sa setScreenSaverIntervals(), setScreenSaverInterval()
*/
void QWSServer::setScreenSaverBlockLevel(int eventBlockLevel)
{
    if (!qwsServerPrivate)
        return;
    qwsServerPrivate->screensavereventblocklevel = eventBlockLevel;
#ifdef EVENT_BLOCK_DEBUG
    qDebug() << "QWSServer::setScreenSaverBlockLevel() " << eventBlockLevel;
#endif
}

extern bool qt_disable_lowpriority_timers; //in qeventloop_unix.cpp

void QWSServerPrivate::_q_screenSaverWake()
{
    if (screensaverintervals) {
        if (screensaverinterval != screensaverintervals) {
            if (saver) saver->restore();
            screensaverinterval = screensaverintervals;
            screensaverblockevents = false;
        } else {
            if (!screensavertimer->isActive()) {
                qt_screen->blank(false);
                if (saver) saver->restore();
            }
        }
        screensavertimer->start(*screensaverinterval);
        screensavertime.start();
    }
    qt_disable_lowpriority_timers=false;
}

void QWSServerPrivate::_q_screenSaverSleep()
{
    qt_screen->blank(true);
#if !defined(QT_QWS_IPAQ) && !defined(QT_QWS_EBX)
    screensavertimer->stop();
#else
    if (screensaverinterval) {
        screensavertimer->start(*screensaverinterval);
        screensavertime.start();
    } else {
        screensavertimer->stop();
    }
#endif
    qt_disable_lowpriority_timers=true;
}

/*!
    \fn void QWSServer::setScreenSaver(QWSScreenSaver* screenSaver)

    Installs the given \a screenSaver, deleting the current screen
    saver.

    Note that this function can only be used in the server process.

    \sa screenSaverActivate(), setScreenSaverInterval(), setScreenSaverIntervals(), setScreenSaverBlockLevel()
*/
void QWSServer::setScreenSaver(QWSScreenSaver* ss)
{
    QWSServerPrivate *qd = qwsServer->d_func();
    delete qd->saver;
    qd->saver = ss;
}

void QWSServerPrivate::screenSave(int level)
{
    if (saver) {
        // saver->save() may call QCoreApplication::processEvents,
        // block event before calling saver->save().
        bool oldScreensaverblockevents = screensaverblockevents;
        if (*screensaverinterval >= 1000) {
            screensaverblockevents = (screensavereventblocklevel >= 0 && screensavereventblocklevel <= level);
#ifdef EVENT_BLOCK_DEBUG
            if (screensaverblockevents)
                qDebug("ready to block events");
#endif
        }
        int *oldScreensaverinterval = screensaverinterval;
        if (saver->save(level)) {
            // only update screensaverinterval if it hasn't already changed
            if (oldScreensaverinterval == screensaverinterval) {
                if (screensaverinterval && screensaverinterval[1]) {
                    screensavertimer->start(*++screensaverinterval);
                    screensavertime.start();
                } else {
                    screensaverinterval = 0;
                }
            }
        } else {
            // restore previous state
            screensaverblockevents = oldScreensaverblockevents;

            // for some reason, the saver don't want us to change to the
            // next level, so we'll stay at this level for another interval
            if (screensaverinterval && *screensaverinterval) {
                screensavertimer->start(*screensaverinterval);
                screensavertime.start();
            }
        }
    } else {
        screensaverinterval = 0;//screensaverintervals;
        screensaverblockevents = false;
        _q_screenSaverSleep();
    }
}

void QWSServerPrivate::_q_screenSaverTimeout()
{
    if (screensaverinterval) {
        if (screensavertime.elapsed() > *screensaverinterval*2) {
            // bogus (eg. unsuspend, system time changed)
            _q_screenSaverWake(); // try again
            return;
        }
        screenSave(screensaverinterval - screensaverintervals);
    }
}

/*!
    Returns true if the screen saver is active; otherwise returns
    false.

    Note that this function can only be used in the server process.

    \sa screenSaverActivate()
*/
bool QWSServer::screenSaverActive()
{
    return qwsServerPrivate->screensaverinterval
        && !qwsServerPrivate->screensavertimer->isActive();
}

/*!
    \internal
*/
void QWSServer::updateWindowRegions() const
{
    qwsServerPrivate->update_regions();
}

/*!
    Activates the screen saver if \a activate is true; otherwise it is
    deactivated.

    Note that this function can only be used in the server process.

    \sa screenSaverActive(), setScreenSaver()
*/
void QWSServer::screenSaverActivate(bool activate)
{
    if (activate)
        qwsServerPrivate->_q_screenSaverSleep();
    else
        qwsServerPrivate->_q_screenSaverWake();
}

void QWSServerPrivate::disconnectClient(QWSClient *c)
{
    QTimer::singleShot(0, c, SLOT(closeHandler()));
}

void QWSServerPrivate::updateClientCursorPos()
{
    Q_Q(QWSServer);
    QWSWindow *win = qwsServerPrivate->mouseGrabber ? qwsServerPrivate->mouseGrabber : qwsServer->windowAt(QWSServer::mousePosition);
    QWSClient *winClient = win ? win->client() : 0;
    if (winClient && winClient != cursorClient)
        q->sendMouseEvent(QWSServer::mousePosition, mouseState);
}

#ifndef QT_NO_QWS_INPUTMETHODS

/*!
    \class QWSInputMethod
    \preliminary
    \ingroup qws

    \brief The QWSInputMethod class provides international input methods
    in Qt for Embedded Linux.

    Note that this class is only available in \l{Qt for Embedded Linux}.

    A \l{Qt for Embedded Linux} application requires a server application to be
    running, or to be the server application itself. All system
    generated events, including keyboard and mouse events, are passed
    to the server application which then propagates the event to the
    appropriate client.

    An input method consists of a filter and optionally a graphical
    interface, and is used to filter input events between the server
    and the client application.

    \tableofcontents

    \section1 Creating Custom Input Methods

    To implement a custom input method, derive from the QWSInputMethod
    class, and use the server's \l
    {QWSServer::}{setCurrentInputMethod()} function to install it.

    When subclassing QWSInputMethod, you can reimplement the filter()
    functions to handle input from both physical and virtual keyboards
    as well as mouse devices. Note that the default implementations do
    nothing. Use the setInputResolution() function to control the
    number of bits shifted when filtering mouse input, i.e., when
    going from pointer resolution to screen resolution (the current
    resolution can be retrieved using the inputResolutionShift()
    function).

    Reimplement the reset() function to restore the state of the input
    method. Note that the default implementation calls the sendEvent()
    function with empty preedit and commit strings if the input method
    is in compose mode (i.e., if the input method is actively
    composing a preedit string).

    To receive replies to an input method query (sent using the
    sendQuery() function), you must reimplement the queryResponse()
    function, while the mouseHandler() function must be reimplemented
    if you want to handle mouse events within the preedit
    text. Reimplement the updateHandler() function to handle update
    events including resets and focus changes. The UpdateType enum
    describes the various types of update events recognized by the
    input method.

    \section1 Using Input Methods

    In addition to the filter(), reset(), queryResponse(),
    mouseHandler() and updateHandler() function mentioned in the
    previous section, the QWSInputMethod provides several other
    functions helping the window system to manage the installed input
    methods.

    The sendEvent() function sends the given event to the focus
    widget, while the sendPreeditString() function sends the given
    preedit text (encapsulated by an event). QWSInputMethod also
    provides the sendCommitString() convenience function which sends
    an event encapsulating the given commit string to the current
    focus widget, and the sendMouseEvent() function which sends the
    given mouse event.

    Finally, the QWSInputMethod class provides the sendQuery()
    function for sending input method queries. This function
    encapsulates the event with a QWSEvent instance of the \l
    {QWSEvent::}{IMQuery} type.

    \sa QWSServer, {Qt for Embedded Linux Architecture}
*/

/*!
    Constructs a new input method.

    Use the QWSServer::setCurrentInputMethod() function to install it.
*/

QWSInputMethod::QWSInputMethod()
{

}

/*!
    Destroys this input method, uninstalling it if it is installed.
*/
QWSInputMethod::~QWSInputMethod()
{
    if (current_IM == this)
        current_IM = 0;
}

/*!
    Filters the key input identified by the given \a unicode, \a
    keycode, \a modifiers, \a isPress and \a autoRepeat parameters.

    Note that the default implementation does nothing; reimplement
    this function to handle input from both physical and virtual
    devices.

    The \a keycode is a Qt::Key value, and the \a modifiers is an OR
    combination of Qt::KeyboardModifiers. The \a isPress parameter is
    telling whether the input is a key press or key release, and the
    \a autoRepeat parameter determines whether the input is
    autorepeated ( i.e., in which case the
    QWSKeyboardHandler::beginAutoRepeat() function has been called).

    To block the event from further processing, return true when
    reimplementing this function; the default implementation returns
    false.

    \sa setInputResolution(), inputResolutionShift()
*/
bool QWSInputMethod::filter(int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat)
{
    Q_UNUSED(unicode);
    Q_UNUSED(keycode);
    Q_UNUSED(modifiers);
    Q_UNUSED(isPress);
    Q_UNUSED(autoRepeat);
    return false;
}

/*!
    \overload

    Filters the mouse input identified by the given \a position, \a
    state, and \a wheel parameters.
*/
bool QWSInputMethod::filter(const QPoint &position, int state, int wheel)
{
    Q_UNUSED(position);
    Q_UNUSED(state);
    Q_UNUSED(wheel);
    return false;
}

/*!
    Resets the state of the input method.

    If the input method is in compose mode, i.e., the input method is
    actively composing a preedit string, the default implementation
    calls sendEvent() with empty preedit and commit strings; otherwise
    it does nothing. Reimplement this function to alter this behavior.

    \sa sendEvent()
*/
void QWSInputMethod::reset()
{
    if (current_IM_composing_win) {
        QInputMethodEvent ime;
        sendEvent(&ime);
    }
}

/*!
    \enum QWSInputMethod::UpdateType

    This enum describes the various types of update events recognized
    by the input method.

    \value Update    The input widget is updated in some way; use sendQuery() with
                            Qt::ImMicroFocus as an argument for more information.
    \value FocusIn   A new input widget receives focus.
    \value FocusOut  The input widget loses focus.
    \value Reset       The input method should be reset.
    \value Destroyed The input widget is destroyed.

    \sa updateHandler()
*/

/*!
    Handles update events including resets and focus changes. The
    update events are specified by the given \a type which is one of
    the UpdateType enum values.

    Note that reimplementations of this function must call the base
    implementation for all cases that it does not handle itself.

    \sa UpdateType
*/
void QWSInputMethod::updateHandler(int type)
{
    switch (type) {
    case FocusOut:
    case Reset:
        reset();
        break;

    default:
        break;
    }
}


/*!
    Receive replies to an input method query.

    Note that the default implementation does nothing; reimplement
    this function to receive such replies.

    Internally, an input method query is passed encapsulated by an \l
    {QWSEvent::IMQuery}{IMQuery} event generated by the sendQuery()
    function. The queried property and the result is passed in the \a
    property and \a result parameters.

    \sa sendQuery(), QWSServer::sendIMQuery()
*/
void QWSInputMethod::queryResponse(int property, const QVariant &result)
{
    Q_UNUSED(property);
    Q_UNUSED(result);
}



/*!
    \fn void QWSInputMethod::mouseHandler(int offset, int state)

    Handles mouse events within the preedit text.

    Note that the default implementation resets the input method on
    all mouse presses; reimplement this function to alter this
    behavior.

    The \a offset parameter specifies the position of the mouse event
    within the string, and \a state specifies the type of the mouse
    event as described by the QWSServer::IMMouse enum. If \a state is
    less than 0, the mouse event is inside the associated widget, but
    outside the preedit text. When clicking in a different widget, the
    \a state is QWSServer::MouseOutside.

    \sa sendPreeditString(), reset()
*/
void QWSInputMethod::mouseHandler(int, int state)
{
    if (state == QWSServer::MousePress || state == QWSServer::MouseOutside)
        reset();
}


/*!
    Sends an event encapsulating the given \a preeditString, to the
    focus widget.

    The specified \a selectionLength is the number of characters to be
    marked as selected (starting at the given \a cursorPosition). If
    \a selectionLength is negative, the text \e before \a
    cursorPosition is marked.

    The preedit string is marked with QInputContext::PreeditFormat,
    and the selected part is marked with
    QInputContext::SelectionFormat.

    Sending an input method event with a non-empty preedit string will
    cause the input method to enter compose mode.  Sending an input
    method event with an empty preedit string will cause the input
    method to leave compose mode, i.e., the input method will no longer
    be actively composing the preedit string.

    Internally, the event is represented by a QWSEvent object of the
    \l {QWSEvent::IMEvent}{IMEvent} type.

    \sa sendEvent(), sendCommitString()
*/

void QWSInputMethod::sendPreeditString(const QString &preeditString, int cursorPosition, int selectionLength)
{
    QList<QInputMethodEvent::Attribute> attributes;

    int selPos = cursorPosition;
    if (selectionLength == 0) {
        selPos = 0;
    } else if (selectionLength < 0) {
        selPos += selectionLength;
        selectionLength = -selectionLength;
    }
    if (selPos > 0)
        attributes += QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, 0, selPos,
                                                   QVariant(int(QInputContext::PreeditFormat)));

    if (selectionLength)
        attributes += QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, selPos, selectionLength,
                                                   QVariant(int(QInputContext::SelectionFormat)));

    if (selPos + selectionLength < preeditString.length())
        attributes += QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,
                                                   selPos + selectionLength,
                                                   preeditString.length() - selPos - selectionLength,
                                                   QVariant(int(QInputContext::PreeditFormat)));

    attributes += QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, cursorPosition,  0, QVariant());

    QInputMethodEvent ime(preeditString, attributes);
    qwsServer->sendIMEvent(&ime);
}

/*!
    \fn void QWSInputMethod::sendCommitString(const QString &commitString, int replaceFromPosition, int replaceLength)

    Sends an event encapsulating the given \a commitString, to the
    focus widget.

    Note that this will cause the input method to leave compose mode,
    i.e., the input method will no longer be actively composing the
    preedit string.

    If the specified \a replaceLength is greater than 0, the commit
    string will replace the given number of characters of the
    receiving widget's previous text, starting at the given \a
    replaceFromPosition relative to the start of the current preedit
    string.

    Internally, the event is represented by a QWSEvent object of the
    \l {QWSEvent::IMEvent}{IMEvent} type.

    \sa sendEvent(), sendPreeditString()
*/
void QWSInputMethod::sendCommitString(const QString &commitString, int replaceFrom, int replaceLength)
{
    QInputMethodEvent ime;
    ime.setCommitString(commitString, replaceFrom, replaceLength);
    qwsServer->sendIMEvent(&ime);
}

/*!
    \fn QWSInputMethod::sendIMEvent(QWSServer::IMState state, const QString &text, int cursorPosition, int selectionLength)
    \obsolete

    Sends a QInputMethodEvent object to the focus widget.

    If the specified \a state is QWSServer::IMCompose, \a text is a
    preedit string, \a cursorPosition is the cursor's position within
    the preedit string, and \a selectionLength is the number of
    characters (starting at \a cursorPosition) that should be marked
    as selected by the input widget receiving the event. If the
    specified \a state is QWSServer::IMEnd, \a text is a commit
    string.

    Use sendEvent(), sendPreeditString() or sendCommitString() instead.
*/

/*!
    \fn QWSInputMethod::sendEvent(const QInputMethodEvent *event)

    Sends the given \a event to the focus widget.

    The \c QInputMethodEvent class is derived from QWSEvent, i.e., the
    given \a event is a QWSEvent object of the \l
    {QWSEvent::IMEvent}{IMEvent} type.

    \sa sendPreeditString(), sendCommitString(), reset()
*/


/*!
    \fn void QWSInputMethod::sendQuery(int property)

    Sends an input method query (internally encapsulated by a QWSEvent
    of the \l {QWSEvent::IMQuery}{IMQuery} type) for the specified \a
    property.

    To receive responses to input method queries, the virtual
    queryResponse() function must be reimplemented.

    \sa queryResponse(), QWSServer::sendIMQuery()
*/

/*!
    Sets and returns the number of bits shifted to go from pointer
    resolution to screen resolution when filtering mouse input.

    If \a isHigh is true and the device has a pointer device
    resolution twice or more of the screen resolution, the positions
    passed to the filter() function will be presented at the higher
    resolution; otherwise the resolution will be equal to that of the
    screen resolution.

    \sa inputResolutionShift(), filter()
*/
uint QWSInputMethod::setInputResolution(bool isHigh)
{
    mIResolution = isHigh;
    return inputResolutionShift();
}

/*!
    Returns the number of bits shifted to go from pointer resolution
    to screen resolution when filtering mouse input.

    \sa setInputResolution(), filter()
*/
uint QWSInputMethod::inputResolutionShift() const
{
    return 0; // default for devices with single resolution.
}

/*!
    \fn void QWSInputMethod::sendMouseEvent( const QPoint &position, int state, int wheel )

    Sends a mouse event specified by the given \a position, \a state
    and \a wheel parameters.

    The given \a position will be transformed if the screen
    coordinates do not match the pointer device coordinates.

    Note that the event will be not be tested by the active input
    method, but calling the QWSServer::sendMouseEvent() function will
    make the current input method filter the event.

    \sa mouseHandler(), sendEvent()
*/
void QWSInputMethod::sendMouseEvent( const QPoint &pos, int state, int wheel )
{
        if (qt_last_x) {
         *qt_last_x = pos.x();
         *qt_last_y = pos.y();
    }
    QWSServer::mousePosition = pos;
    qwsServerPrivate->mouseState = state;
    QWSServerPrivate::sendMouseEventUnfiltered(pos, state, wheel);
}
#endif // QT_NO_QWS_INPUTMETHODS

/*!
    \fn  QWSWindow::QWSWindow(int i, QWSClient * client)
    \internal

    Constructs a new top-level window, associated with the client \a
    client and giving it the id \a i.
*/

/*!
    \fn QWSServer::windowEvent(QWSWindow * window, QWSServer::WindowEvent eventType)

    This signal is emitted whenever something happens to a top-level
    window (e.g., it's created or destroyed), passing a pointer to the
    window and the event's type in the \a window and \a eventType
    parameters, respectively.

    \sa markedText()
*/

/*!
    \class QWSServer::KeyboardFilter
    \ingroup qws

    \brief The KeyboardFilter class is a base class for global
    keyboard event filters in Qt for Embedded Linux.

    Note that this class is only available in \l{Qt for Embedded Linux}.

    In \l{Qt for Embedded Linux}, all system generated events, including
    keyboard events, are passed to the server application which then
    propagates the event to the appropriate client. The KeyboardFilter
    class is used to implement a global, low-level filter on the
    server side. The server applies the filter to all keyboard events
    before passing them on to the clients:

    \image qwsserver_keyboardfilter.png

    This feature can, for example, be used to filter things like APM
    (advanced power management) suspended from a button without having
    to filter for it in all applications.

    To add a new keyboard filter you must first create the filter by
    deriving from this class, reimplementing the pure virtual filter()
    function. Then you can install the filter on the server using
    QWSServer's \l {QWSServer::}{addKeyboardFilter()}
    function. QWSServer also provides a \l
    {QWSServer::}{removeKeyboardFilter()} function.

    \sa {Qt for Embedded Linux Architecture}, QWSServer, QWSInputMethod
*/

/*!
    \fn QWSServer::KeyboardFilter::~KeyboardFilter()

    Destroys the keyboard filter.
*/

/*!
    \fn bool QWSServer::KeyboardFilter::filter(int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat)

    Implement this function to return true if a given key event should
    be stopped from being processed any further; otherwise it should
    return false.

    A key event can be identified by the given \a unicode value and
    the \a keycode, \a modifiers, \a isPress and \a autoRepeat
    parameters.

    The \a keycode parameter is the Qt keycode value as defined by the
    Qt::Key enum. The \a modifiers is an OR combination of
    Qt::KeyboardModifier values, indicating whether \gui
    Shift/Alt/Ctrl keys are pressed. The \a isPress parameter is true
    if the event is a key press event and \a autoRepeat is true if the
    event is caused by an auto-repeat mechanism and not an actual key
    press.
*/

QT_END_NAMESPACE

#include "moc_qwindowsystem_qws.cpp"
