summaryrefslogtreecommitdiffstats
path: root/src/gui/embedded/qwindowsystem_qws.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/embedded/qwindowsystem_qws.cpp')
-rw-r--r--src/gui/embedded/qwindowsystem_qws.cpp4960
1 files changed, 4960 insertions, 0 deletions
diff --git a/src/gui/embedded/qwindowsystem_qws.cpp b/src/gui/embedded/qwindowsystem_qws.cpp
new file mode 100644
index 0000000000..0d1ae0d2d2
--- /dev/null
+++ b/src/gui/embedded/qwindowsystem_qws.cpp
@@ -0,0 +1,4960 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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"