summaryrefslogtreecommitdiffstats
path: root/src/kernel/qeventloop_x11.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/qeventloop_x11.cpp')
-rw-r--r--src/kernel/qeventloop_x11.cpp417
1 files changed, 417 insertions, 0 deletions
diff --git a/src/kernel/qeventloop_x11.cpp b/src/kernel/qeventloop_x11.cpp
new file mode 100644
index 000000000..76d2e62e0
--- /dev/null
+++ b/src/kernel/qeventloop_x11.cpp
@@ -0,0 +1,417 @@
+/****************************************************************************
+**
+** Implementation of TQEventLoop class
+**
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the kernel module of the TQt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at [email protected].
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+#include "qeventloop_p.h" // includes qplatformdefs.h
+#include "qeventloop.h"
+#include "qapplication.h"
+#include "qbitarray.h"
+#include "qcolor_p.h"
+#include "qt_x11_p.h"
+
+#if defined(QT_THREAD_SUPPORT)
+# include "qmutex.h"
+#endif // QT_THREAD_SUPPORT
+
+#include <errno.h>
+
+
+// resolve the conflict between X11's FocusIn and TQEvent::FocusIn
+#undef FocusOut
+#undef FocusIn
+
+static const int XKeyPress = KeyPress;
+static const int XKeyRelease = KeyRelease;
+#undef KeyPress
+#undef KeyRelease
+
+// from qapplication.cpp
+extern bool qt_is_gui_used;
+
+// from qeventloop_unix.cpp
+extern timeval *qt_wait_timer();
+extern void cleanupTimers();
+
+// ### this needs to go away at some point...
+typedef void (*VFPTR)();
+typedef TQValueList<VFPTR> TQVFuncList;
+void qt_install_preselect_handler( VFPTR );
+void qt_remove_preselect_handler( VFPTR );
+static TQVFuncList *qt_preselect_handler = 0;
+void qt_install_postselect_handler( VFPTR );
+void qt_remove_postselect_handler( VFPTR );
+static TQVFuncList *qt_postselect_handler = 0;
+
+void qt_install_preselect_handler( VFPTR handler )
+{
+ if ( !qt_preselect_handler )
+ qt_preselect_handler = new TQVFuncList;
+ qt_preselect_handler->append( handler );
+}
+void qt_remove_preselect_handler( VFPTR handler )
+{
+ if ( qt_preselect_handler ) {
+ TQVFuncList::Iterator it = qt_preselect_handler->find( handler );
+ if ( it != qt_preselect_handler->end() )
+ qt_preselect_handler->remove( it );
+ }
+}
+void qt_install_postselect_handler( VFPTR handler )
+{
+ if ( !qt_postselect_handler )
+ qt_postselect_handler = new TQVFuncList;
+ qt_postselect_handler->prepend( handler );
+}
+void qt_remove_postselect_handler( VFPTR handler )
+{
+ if ( qt_postselect_handler ) {
+ TQVFuncList::Iterator it = qt_postselect_handler->find( handler );
+ if ( it != qt_postselect_handler->end() )
+ qt_postselect_handler->remove( it );
+ }
+}
+
+
+void TQEventLoop::init()
+{
+ // initialize the common parts of the event loop
+ pipe( d->thread_pipe );
+ fcntl(d->thread_pipe[0], F_SETFD, FD_CLOEXEC);
+ fcntl(d->thread_pipe[1], F_SETFD, FD_CLOEXEC);
+
+ d->sn_highest = -1;
+
+ // intitialize the X11 parts of the event loop
+ d->xfd = -1;
+ if ( qt_is_gui_used )
+ d->xfd = XConnectionNumber( TQPaintDevice::x11AppDisplay() );
+}
+
+void TQEventLoop::cleanup()
+{
+ // cleanup the common parts of the event loop
+ close( d->thread_pipe[0] );
+ close( d->thread_pipe[1] );
+ cleanupTimers();
+
+ // cleanup the X11 parts of the event loop
+ d->xfd = -1;
+}
+
+bool TQEventLoop::processEvents( ProcessEventsFlags flags )
+{
+ // process events from the X server
+ XEvent event;
+ int nevents = 0;
+
+#if defined(QT_THREAD_SUPPORT)
+ TQMutexLocker locker( TQApplication::qt_mutex );
+#endif
+
+ // handle gui and posted events
+ if ( qt_is_gui_used ) {
+ TQApplication::sendPostedEvents();
+
+ // Two loops so that posted events accumulate
+ while ( XPending( TQPaintDevice::x11AppDisplay() ) ) {
+ // also flushes output buffer
+ while ( XPending( TQPaintDevice::x11AppDisplay() ) ) {
+ if ( d->shortcut ) {
+ return FALSE;
+ }
+
+ XNextEvent( TQPaintDevice::x11AppDisplay(), &event );
+
+ if ( flags & ExcludeUserInput ) {
+ switch ( event.type ) {
+ case ButtonPress:
+ case ButtonRelease:
+ case MotionNotify:
+ case XKeyPress:
+ case XKeyRelease:
+ case EnterNotify:
+ case LeaveNotify:
+ continue;
+
+ case ClientMessage:
+ {
+ // from qapplication_x11.cpp
+ extern Atom qt_wm_protocols;
+ extern Atom qt_wm_take_focus;
+ extern Atom qt_qt_scrolldone;
+
+ // only keep the wm_take_focus and
+ // qt_qt_scrolldone protocols, discard all
+ // other client messages
+ if ( event.xclient.format != 32 )
+ continue;
+
+ if ( event.xclient.message_type == qt_wm_protocols ||
+ (Atom) event.xclient.data.l[0] == qt_wm_take_focus )
+ break;
+ if ( event.xclient.message_type == qt_qt_scrolldone )
+ break;
+ }
+
+ default: break;
+ }
+ }
+
+ nevents++;
+ if ( qApp->x11ProcessEvent( &event ) == 1 )
+ return TRUE;
+ }
+ }
+ }
+
+ if ( d->shortcut ) {
+ return FALSE;
+ }
+
+ TQApplication::sendPostedEvents();
+
+ const uint exclude_all = ExcludeSocketNotifiers | 0x08;
+ // 0x08 == ExcludeTimers for X11 only
+ if ( nevents > 0 && ( flags & exclude_all ) == exclude_all &&
+ ( flags & WaitForMore ) ) {
+ return TRUE;
+ }
+
+ // don't block if exitLoop() or exit()/tquit() has been called.
+ bool canWait = d->exitloop || d->tquitnow ? FALSE : (flags & WaitForMore);
+
+ // Process timers and socket notifiers - the common UNIX stuff
+
+ // return the maximum time we can wait for an event.
+ static timeval zerotm;
+ timeval *tm = 0;
+ if ( ! ( flags & 0x08 ) ) { // 0x08 == ExcludeTimers for X11 only
+ tm = qt_wait_timer(); // wait for timer or X event
+ if ( !canWait ) {
+ if ( !tm )
+ tm = &zerotm;
+ tm->tv_sec = 0; // no time to wait
+ tm->tv_usec = 0;
+ }
+ }
+
+ int highest = 0;
+ if ( ! ( flags & ExcludeSocketNotifiers ) ) {
+ // return the highest fd we can wait for input on
+ if ( d->sn_highest >= 0 ) { // has socket notifier(s)
+ if ( d->sn_vec[0].list && ! d->sn_vec[0].list->isEmpty() )
+ d->sn_vec[0].select_fds = d->sn_vec[0].enabled_fds;
+ else
+ FD_ZERO( &d->sn_vec[0].select_fds );
+
+ if ( d->sn_vec[1].list && ! d->sn_vec[1].list->isEmpty() )
+ d->sn_vec[1].select_fds = d->sn_vec[1].enabled_fds;
+ else
+ FD_ZERO( &d->sn_vec[1].select_fds );
+
+ if ( d->sn_vec[2].list && ! d->sn_vec[2].list->isEmpty() )
+ d->sn_vec[2].select_fds = d->sn_vec[2].enabled_fds;
+ else
+ FD_ZERO( &d->sn_vec[2].select_fds );
+ } else {
+ FD_ZERO( &d->sn_vec[0].select_fds );
+
+ FD_ZERO( &d->sn_vec[1].select_fds );
+ FD_ZERO( &d->sn_vec[2].select_fds );
+ }
+
+ highest = d->sn_highest;
+ } else {
+ FD_ZERO( &d->sn_vec[0].select_fds );
+ FD_ZERO( &d->sn_vec[1].select_fds );
+ FD_ZERO( &d->sn_vec[2].select_fds );
+ }
+
+ if ( qt_is_gui_used ) {
+ // select for events on the event socket - only on X11
+ FD_SET( d->xfd, &d->sn_vec[0].select_fds );
+ highest = TQMAX( highest, d->xfd );
+ }
+
+ FD_SET( d->thread_pipe[0], &d->sn_vec[0].select_fds );
+ highest = TQMAX( highest, d->thread_pipe[0] );
+
+ if ( canWait )
+ emit aboutToBlock();
+
+ if ( qt_preselect_handler ) {
+ TQVFuncList::Iterator it, end = qt_preselect_handler->end();
+ for ( it = qt_preselect_handler->begin(); it != end; ++it )
+ (**it)();
+ }
+
+ // unlock the GUI mutex and select. when we return from this function, there is
+ // something for us to do
+#if defined(QT_THREAD_SUPPORT)
+ locker.mutex()->unlock();
+#endif
+
+ int nsel;
+ do {
+ nsel = select( highest + 1,
+ &d->sn_vec[0].select_fds,
+ &d->sn_vec[1].select_fds,
+ &d->sn_vec[2].select_fds,
+ tm );
+ } while (nsel == -1 && (errno == EINTR || errno == EAGAIN));
+
+ // relock the GUI mutex before processing any pending events
+#if defined(QT_THREAD_SUPPORT)
+ locker.mutex()->lock();
+#endif
+
+ // we are awake, broadcast it
+ emit awake();
+ emit qApp->guiThreadAwake();
+
+ if (nsel == -1) {
+ if (errno == EBADF) {
+ // it seems a socket notifier has a bad fd... find out
+ // which one it is and disable it
+ fd_set fdset;
+ zerotm.tv_sec = zerotm.tv_usec = 0l;
+
+ for (int type = 0; type < 3; ++type) {
+ TQPtrList<TQSockNot> *list = d->sn_vec[type].list;
+ if (!list) continue;
+
+ TQSockNot *sn = list->first();
+ while (sn) {
+ FD_ZERO(&fdset);
+ FD_SET(sn->fd, &fdset);
+
+ int ret = -1;
+ do {
+ switch (type) {
+ case 0: // read
+ ret = select(sn->fd + 1, &fdset, 0, 0, &zerotm);
+ break;
+ case 1: // write
+ ret = select(sn->fd + 1, 0, &fdset, 0, &zerotm);
+ break;
+ case 2: // except
+ ret = select(sn->fd + 1, 0, 0, &fdset, &zerotm);
+ break;
+ }
+ } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+
+ if (ret == -1 && errno == EBADF) {
+ // disable the invalid socket notifier
+ static const char *t[] = { "Read", "Write", "Exception" };
+ qWarning("TQSocketNotifier: invalid socket %d and type '%s', disabling...",
+ sn->fd, t[type]);
+ sn->obj->setEnabled(FALSE);
+ }
+
+ sn = list->next();
+ }
+ }
+ } else {
+ // EINVAL... shouldn't happen, so let's complain to stderr
+ // and hope someone sends us a bug report
+ perror( "select" );
+ }
+ }
+
+ // some other thread woke us up... consume the data on the thread pipe so that
+ // select doesn't immediately return next time
+ if ( nsel > 0 && FD_ISSET( d->thread_pipe[0], &d->sn_vec[0].select_fds ) ) {
+ char c;
+ ::read( d->thread_pipe[0], &c, 1 );
+ }
+
+ if ( qt_postselect_handler ) {
+ TQVFuncList::Iterator it, end = qt_postselect_handler->end();
+ for ( it = qt_postselect_handler->begin(); it != end; ++it )
+ (**it)();
+ }
+
+ // activate socket notifiers
+ if ( ! ( flags & ExcludeSocketNotifiers ) && nsel > 0 && d->sn_highest >= 0 ) {
+ // if select says data is ready on any socket, then set the socket notifier
+ // to pending
+ int i;
+ for ( i=0; i<3; i++ ) {
+ if ( ! d->sn_vec[i].list )
+ continue;
+
+ TQPtrList<TQSockNot> *list = d->sn_vec[i].list;
+ TQSockNot *sn = list->first();
+ while ( sn ) {
+ if ( FD_ISSET( sn->fd, &d->sn_vec[i].select_fds ) )
+ setSocketNotifierPending( sn->obj );
+ sn = list->next();
+ }
+ }
+
+ nevents += activateSocketNotifiers();
+ }
+
+ // activate timers
+ if ( ! ( flags & 0x08 ) ) {
+ // 0x08 == ExcludeTimers for X11 only
+ nevents += activateTimers();
+ }
+
+ // color approx. optimization - only on X11
+ qt_reset_color_avail();
+
+ // return true if we handled events, false otherwise
+ return (nevents > 0);
+}
+
+bool TQEventLoop::hasPendingEvents() const
+{
+ extern uint qGlobalPostedEventsCount(); // from qapplication.cpp
+ return ( qGlobalPostedEventsCount() || XPending( TQPaintDevice::x11AppDisplay() ) );
+}
+
+void TQEventLoop::appStartingUp()
+{
+ if ( qt_is_gui_used )
+ d->xfd = XConnectionNumber( TQPaintDevice::x11AppDisplay() );
+}
+
+void TQEventLoop::appClosingDown()
+{
+ d->xfd = -1;
+}