/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qplatformdefs.h"
#include "qwindowsystem_qws.h"
#include "qwsevent_qws.h"
#include "qwscommand_qws_p.h"
#include "qtransportauth_qws_p.h"
#include "qwsutils_qws.h"
#include "qwscursor_qws.h"
#include "qwsdisplay_qws.h"
#include "qmouse_qws.h"
#include "qcopchannel_qws.h"
#include "qwssocket_qws.h"
#include "qapplication.h"
#include "private/qapplication_p.h"
#include "qsocketnotifier.h"
#include "qpolygon.h"
#include "qimage.h"
#include "qcursor.h"
#include <private/qpaintengine_raster_p.h>
#include "qscreen_qws.h"
#include "qwindowdefs.h"
#include "private/qlock_p.h"
#include "qwslock_p.h"
#include "qfile.h"
#include "qtimer.h"
#include "qpen.h"
#include "qdesktopwidget.h"
#include "qevent.h"
#include "qinputcontext.h"
#include "qpainter.h"
#include <qdebug.h>
#include "qkbddriverfactory_qws.h"
#include "qmousedriverfactory_qws.h"
#include <qbuffer.h>
#include <qdir.h>
#include <private/qwindowsurface_qws_p.h>
#include <private/qfontengine_qpf_p.h>
#include "qwindowsystem_p.h"
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#ifndef QT_NO_QWS_MULTIPROCESS
#include <sys/param.h>
#include <sys/mount.h>
#endif
#if !defined(QT_NO_SOUND) && !defined(Q_OS_DARWIN)
#ifdef QT_USE_OLD_QWS_SOUND
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/soundcard.h>
#else
#include "qsoundqss_qws.h"
#endif
#endif
//#define QWS_DEBUG_FONTCLEANUP
QT_BEGIN_NAMESPACE
QWSServer Q_GUI_EXPORT *qwsServer=0;
static QWSServerPrivate *qwsServerPrivate=0;
#define MOUSE 0
#define KEY 1
//#define EVENT_BLOCK_DEBUG
QWSScreenSaver::~QWSScreenSaver()
{
}
extern QByteArray qws_display_spec;
extern void qt_init_display(); //qapplication_qws.cpp
extern QString qws_qtePipeFilename();
extern void qt_client_enqueue(const QWSEvent *); //qapplication_qws.cpp
extern QList<QWSCommand*> *qt_get_server_queue();
Q_GLOBAL_STATIC_WITH_ARGS(QString, defaultMouse, (QLatin1String("Auto")))
Q_GLOBAL_STATIC_WITH_ARGS(QString, defaultKeyboard, (QLatin1String("TTY")))
static const int FontCleanupInterval = 60 * 1000;
static int qws_keyModifiers = 0;
static QWSWindow *keyboardGrabber;
static bool keyboardGrabbing;
static int get_object_id(int count = 1)
{
static int next=1000;
int n = next;
next += count;
return n;
}
#ifndef QT_NO_QWS_INPUTMETHODS
static QWSInputMethod *current_IM = 0;
static QWSWindow *current_IM_composing_win = 0;
static int current_IM_winId = -1;
static bool force_reject_strokeIM = false;
#endif
static void cleanupFontsDir();
//#define QWS_REGION_DEBUG
/*!
\class QWSScreenSaver
\ingroup qws
\brief The QWSScreenSaver class is a base class for screensavers
in Qt for Embedded Linux.
When running \l{Qt for Embedded Linux} applications, it is the server
application that installs and controls the screensaver.
\l{Qt for Embedded Linux} supports multilevel screen saving; i.e., it is possible to
specify several different levels of screen responsiveness. For
example, you can choose to first turn off the light before you
fully activate the screensaver.
Note that there exists no default screensaver implementation.
To create a custom screensaver, derive from this class and
reimplement the restore() and save() functions. These functions
are called whenever the screensaver is activated or deactivated,
respectively. Once an instance of your custom screensaver is
created, you can use the QWSServer::setScreenSaver() function to
install it.
\sa QWSServer, QScreen, {Qt for Embedded Linux}
*/
/*!
\fn QWSScreenSaver::~QWSScreenSaver()
Reimplement this function to destroy the screensaver.
*/
/*!
\fn QWSScreenSaver::restore()
Implement this function to deactivate the screensaver, restoring
the previously saved screen.
\sa save(), QWSServer::screenSaverActivate()
*/
/*!
\fn QWSScreenSaver::save(int level)
Implement this function to activate the screensaver, saving the
current screen.
\l{Qt for Embedded Linux} supports multilevel screen saving; i.e., it is
possible to specify several different levels of screen
responsiveness. For example, you can choose to first turn off the
light before you fully activate the screensaver. Use the
QWSServer::setScreenSaverIntervals() to specify the time intervals
between the different levels.
This function should return true if the screensaver successfully
enters the given \a level; otherwise it should return false.
\sa restore(), QWSServer::screenSaverActivate()
*/
class QWSWindowPrivate
{
public:
QWSWindowPrivate();
#ifdef QT_QWS_CLIENTBLIT
QRegion directPaintRegion;
#endif
QRegion allocatedRegion;
#ifndef QT_NO_QWSEMBEDWIDGET
QList<QWSWindow*> embedded;
QWSWindow *embedder;
#endif
QWSWindow::State state;
Qt::WindowFlags windowFlags;
QRegion dirtyOnScreen;
bool painted;
};
QWSWindowPrivate::QWSWindowPrivate()
:
#ifndef QT_NO_QWSEMBEDWIDGET
embedder(0), state(QWSWindow::NoState),
#endif
painted(false)
{
}
/*!
\class QWSWindow
\ingroup qws
\brief The QWSWindow class encapsulates a top-level window in
Qt for Embedded Linux.
When you run a \l{Qt for Embedded Linux} application, it either runs as a
server or connects to an existing server. As applications add and
remove windows, the server process maintains information about
each window. In \l{Qt for Embedded Linux}, top-level windows are
encapsulated as QWSWindow objects. Note that you should never
construct the QWSWindow class yourself; the current top-level
windows can be retrieved using the QWSServer::clientWindows()
function.
With a window at hand, you can retrieve its caption, name, opacity
and ID using the caption(), name(), opacity() and winId()
functions, respectively. Use the client() function to retrieve a
pointer to the client that owns the window.
Use the isVisible() function to find out if the window is
visible. You can find out if the window is completely obscured by
another window or by the bounds of the screen, using the
isFullyObscured() function. The isOpaque() function returns true
if the window has an alpha channel equal to 255. Finally, the
requestedRegion() function returns the region of the display the
window wants to draw on.
\sa QWSServer, QWSClient, {Qt for Embedded Linux Architecture}
*/
/*!
\fn int QWSWindow::winId() const
Returns the window's ID.
\sa name(), caption()
*/
/*!
\fn const QString &QWSWindow::name() const
Returns the window's name, which is taken from the \l {QWidget::}{objectName()}
at the time of \l {QWidget::}{show()}.
\sa caption(), winId()
*/
/*!
\fn const QString &QWSWindow::caption() const
Returns the window's caption.
\sa name(), winId()
*/
/*!
\fn QWSClient* QWSWindow::client() const
Returns a reference to the QWSClient object that owns this window.
\sa requestedRegion()
*/
/*!
\fn QRegion QWSWindow::requestedRegion() const
Returns the region that the window has requested to draw onto,
including any window decorations.
\sa client()
*/
/*!
\fn bool QWSWindow::isVisible() const
Returns true if the window is visible; otherwise returns false.
\sa isFullyObscured()
*/
/*!
\fn bool QWSWindow::isOpaque() const
Returns true if the window is opaque, i.e., if its alpha channel
equals 255; otherwise returns false.
\sa opacity()
*/
/*!
\fn uint QWSWindow::opacity () const
Returns the window's alpha channel value.
\sa isOpaque()
*/
/*!
\fn bool QWSWindow::isPartiallyObscured() const
\internal
Returns true if the window is partially obsured by another window
or by the bounds of the screen; otherwise returns false.
*/
/*!
\fn bool QWSWindow::isFullyObscured() const
Returns true if the window is completely obsured by another window
or by the bounds of the screen; otherwise returns false.
\sa isVisible()
*/
/*!
\fn QWSWindowSurface* QWSWindow::windowSurface() const
\internal
*/
QWSWindow::QWSWindow(int i, QWSClient* client)
: id(i), modified(false),
onTop(false), c(client), last_focus_time(0), _opacity(255),
opaque(true), d(new QWSWindowPrivate)
{
surface = 0;
}
/*!
\enum QWSWindow::State
This enum describes the state of a window. Most of the
transitional states are set just before a call to
QScreen::exposeRegion() and reset immediately afterwards.
\value NoState Initial state before the window is properly initialized.
\value Hidden The window is not visible.
\value Showing The window is being shown.
\value Visible The window is visible, and not in a transition.
\value Hiding The window is being hidden.
\value Raising The windoe is being raised.
\value Lowering The window is being raised.
\value Moving The window is being moved.
\value ChangingGeometry The window's geometry is being changed.
\value Destroyed The window is destroyed.
\sa state(), QScreen::exposeRegion()
*/
/*!
Returns the current state of the window.
\since 4.3
*/
QWSWindow::State QWSWindow::state() const
{
return d->state;
}
/*!
Returns the window flags of the window. This value is only available
after the first paint event.
\since 4.3
*/
Qt::WindowFlags QWSWindow::windowFlags() const
{
return d->windowFlags;
}
/*!
Returns the region that has been repainted since the previous
QScreen::exposeRegion(), and needs to be copied to the screen.
\since 4.3
*/
QRegion QWSWindow::dirtyOnScreen() const
{
return d->dirtyOnScreen;
}
void QWSWindow::createSurface(const QString &key, const QByteArray &data)
{
#ifndef QT_NO_QWS_MULTIPROCESS
if (surface && !surface->isBuffered())
c->removeUnbufferedSurface();
#endif
delete surface;
surface = qt_screen->createSurface(key);
surface->setPermanentState(data);
#ifndef QT_NO_QWS_MULTIPROCESS
if (!surface->isBuffered())
c->addUnbufferedSurface();
#endif
}
/*!
\internal
Raises the window above all other windows except "Stay on top" windows.
*/
void QWSWindow::raise()
{
qwsServerPrivate->raiseWindow(this);
#ifndef QT_NO_QWSEMBEDWIDGET
const int n = d->embedded.size();
for (int i = 0; i < n; ++i)
d->embedded.at(i)->raise();
#endif
}
/*!
\internal
Lowers the window below other windows.
*/
void QWSWindow::lower()
{
qwsServerPrivate->lowerWindow(this);
#ifndef QT_NO_QWSEMBEDWIDGET
const int n = d->embedded.size();
for (int i = 0; i < n; ++i)
d->embedded.at(i)->lower();
#endif
}
/*!
\internal
Shows the window.
*/
void QWSWindow::show()
{
operation(QWSWindowOperationEvent::Show);
#ifndef QT_NO_QWSEMBEDWIDGET
const int n = d->embedded.size();
for (int i = 0; i < n; ++i)
d->embedded.at(i)->show();
#endif
}
/*!
\internal
Hides the window.
*/
void QWSWindow::hide()
{
operation(QWSWindowOperationEvent::Hide);
#ifndef QT_NO_QWSEMBEDWIDGET
const int n = d->embedded.size();
for (int i = 0; i < n; ++i)
d->embedded.at(i)->hide();
#endif
}
/*!
\internal
Make this the active window (i.e., sets the keyboard focus to this
window).
*/
void QWSWindow::setActiveWindow()
{
qwsServerPrivate->setFocus(this, true);
#ifndef QT_NO_QWSEMBEDWIDGET
const int n = d->embedded.size();
for (int i = 0; i < n; ++i)
d->embedded.at(i)->setActiveWindow();
#endif
}
void QWSWindow::setName(const QString &n)
{
rgnName = n;
}
/*!
\internal
Sets the window's caption to \a c.
*/
void QWSWindow::setCaption(const QString &c)
{
rgnCaption = c;
}
static int global_focus_time_counter=100;
void QWSWindow::focus(bool get)
{
if (get)
last_focus_time = global_focus_time_counter++;
if (c) {
QWSFocusEvent event;
event.simpleData.window = id;
event.simpleData.get_focus = get;
c->sendEvent(&event);
}
}
void QWSWindow::operation(QWSWindowOperationEvent::Operation o)
{
if (!c)
return;
QWSWindowOperationEvent event;
event.simpleData.window = id;
event.simpleData.op = o;
c->sendEvent(&event);
}
/*!
\internal
Destructor.
*/
QWSWindow::~QWSWindow()
{
#ifndef QT_NO_QWS_INPUTMETHODS
if (current_IM_composing_win == this)
current_IM_composing_win = 0;
#endif
#ifndef QT_NO_QWSEMBEDWIDGET
QWSWindow *embedder = d->embedder;
if (embedder) {
embedder->d->embedded.removeAll(this);
d->embedder = 0;
}
while (!d->embedded.isEmpty())
stopEmbed(d->embedded.first());
#endif
#ifndef QT_NO_QWS_MULTIPROCESS
if (surface && !surface->isBuffered()) {
if (c && c->d_func()) // d_func() will be 0 if client is deleted
c->removeUnbufferedSurface();
}
#endif
delete surface;
delete d;
}
/*!
\internal
Returns the region that the window is allowed to draw onto,
including any window decorations but excluding regions covered by
other windows.
\sa paintedRegion(), requestedRegion()
*/
QRegion QWSWindow::allocatedRegion() const
{
return d->allocatedRegion;
}
#ifdef QT_QWS_CLIENTBLIT
QRegion QWSWindow::directPaintRegion() const
{
return d->directPaintRegion;
}
inline void QWSWindow::setDirectPaintRegion(const QRegion &r)
{
d->directPaintRegion = r;
}
#endif
/*!
\internal
Returns the region that the window is known to have drawn into.
\sa allocatedRegion(), requestedRegion()
*/
QRegion QWSWindow::paintedRegion() const
{
return (d->painted ? d->allocatedRegion : QRegion());
}
inline void QWSWindow::setAllocatedRegion(const QRegion ®ion)
{
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 ®ion)
{
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 ®ion)
{
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 ®ion)
{
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 ®ion)
{
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"