/**************************************************************************** ** ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtGui module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "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 #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 #include "qkbddriverfactory_qws.h" #include "qmousedriverfactory_qws.h" #include #include #include #include #include "qwindowsystem_p.h" #include #include #include #ifndef QT_NO_QWS_MULTIPROCESS #include #include #endif #if !defined(QT_NO_SOUND) && !defined(Q_OS_DARWIN) #ifdef QT_USE_OLD_QWS_SOUND #include #include #include #include #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 *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 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 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(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 &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 &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 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::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 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::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(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 *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(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(cs->command), cs->client); break; #endif case QWSCommand::ScreenTransform: invokeScreenTransform(static_cast(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 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::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& 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 * QWSServer::windowList() { QList * ret=new QList; 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; iwindows.size(); ++i) { QWSWindow* w = d->windows.at(i); if (w->allocatedRegion().contains(pos)) return w; } return 0; } #ifndef QT_NO_QWS_KEYBOARD static inline 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) { QWSWindow *win = keyboardGrabber ? keyboardGrabber : qwsServerPrivate->focusw; #ifndef QT_NO_QWS_KEYBOARD if (unicode < 0) unicode = keyUnicode(keycode); #endif QWSKeyEvent event; event.simpleData.window = win ? win->winId() : 0; event.simpleData.unicode = 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 &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; ihidden() && (!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(cmd->simpleData.embedder)); return; } if (!embedded) { qWarning("QWSServer: Embed command on window %i failed: No such id.", static_cast(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::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; iwinId() == 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 regexps = QList() << 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; QWSWindowSurface *surface = changingw->windowSurface(); if (!surface) { changingw->createSurface(surfaceKey, surfaceData); surface = changingw->windowSurface(); } else { surface->setPermanentState(surfaceData); } 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 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 *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) { if (isPress) qwsServerPrivate->_q_screenSaverWake(); 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; 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 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"