summaryrefslogtreecommitdiffstats
path: root/nsplugins/viewer/qxteventloop.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'nsplugins/viewer/qxteventloop.cpp')
-rw-r--r--nsplugins/viewer/qxteventloop.cpp472
1 files changed, 472 insertions, 0 deletions
diff --git a/nsplugins/viewer/qxteventloop.cpp b/nsplugins/viewer/qxteventloop.cpp
new file mode 100644
index 000000000..856cfe67c
--- /dev/null
+++ b/nsplugins/viewer/qxteventloop.cpp
@@ -0,0 +1,472 @@
+/****************************************************************************
+** Implementation of QWidget class
+**
+** Created : 931031
+**
+** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
+**
+** This file is part of the Xt extension of the Qt GUI Toolkit.
+**
+** This file may be distributed under the terms of the Q Public License
+** as defined by Trolltech AS of Norway and appearing in the file
+** LICENSE.QPL included in the packaging of this file.
+**
+** This file may be distributed and/or modified under the terms of the
+** GNU General Public License version 2 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.
+**
+** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
+** licenses may use this file in accordance with the Qt Commercial License
+** Agreement provided with the Software.
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+** See http://www.trolltech.com/pricing.html or email [email protected] for
+** information about Qt Commercial License Agreements.
+** See http://www.trolltech.com/qpl/ for QPL licensing information.
+** See http://www.trolltech.com/gpl/ for GPL licensing information.
+**
+** Contact [email protected] if any conditions of this licensing are
+** not clear to you.
+**
+**********************************************************************/
+
+#include <config.h>
+
+#include "qxteventloop.h"
+
+#if QT_VERSION >= 0x030100
+
+#include <qapplication.h>
+#include <qwidgetintdict.h>
+#include <kglobal.h>
+
+// resolve the conflict between X11's FocusIn and QEvent::FocusIn
+const int XFocusOut = FocusOut;
+const int XFocusIn = FocusIn;
+#undef FocusOut
+#undef FocusIn
+
+const int XKeyPress = KeyPress;
+const int XKeyRelease = KeyRelease;
+#undef KeyPress
+#undef KeyRelease
+
+Boolean qmotif_event_dispatcher( XEvent *event );
+
+class QXtEventLoopPrivate
+{
+public:
+ QXtEventLoopPrivate();
+
+ void hookMeUp();
+ void unhook();
+
+ XtAppContext appContext, ownContext;
+ QMemArray<XtEventDispatchProc> dispatchers;
+ QWidgetIntDict mapper;
+
+ QIntDict<QSocketNotifier> socknotDict;
+ bool activate_timers;
+ XtIntervalId timerid;
+
+ // arguments for Xt display initialization
+ const char* applicationClass;
+ XrmOptionDescRec* options;
+ int numOptions;
+};
+static QXtEventLoopPrivate *static_d = 0;
+static XEvent* last_xevent = 0;
+
+
+/*! \internal
+ Redeliver the given XEvent to Xt.
+
+ Rationale: An XEvent handled by Qt does not go through the Xt event
+ handlers, and the internal state of Xt/Motif widgets will not be
+ updated. This function should only be used if an event delivered by
+ Qt to a QWidget needs to be sent to an Xt/Motif widget.
+*/
+bool QXtEventLoop::redeliverEvent( XEvent *event )
+{
+ // redeliver the event to Xt, NOT through Qt
+ if ( static_d->dispatchers[ event->type ]( event ) )
+ return TRUE;
+ return FALSE;
+}
+
+
+/*!\internal
+ */
+XEvent* QXtEventLoop::lastEvent()
+{
+ return last_xevent;
+}
+
+
+QXtEventLoopPrivate::QXtEventLoopPrivate()
+ : appContext(NULL), ownContext(NULL),
+ activate_timers(FALSE), timerid(0)
+{
+}
+
+void QXtEventLoopPrivate::hookMeUp()
+{
+ // worker to plug Qt into Xt (event dispatchers)
+ // and Xt into Qt (QXtEventLoopEventLoop)
+
+ // ### TODO extensions?
+ dispatchers.resize( LASTEvent );
+ dispatchers.fill( 0 );
+ int et;
+ for ( et = 2; et < LASTEvent; et++ )
+ dispatchers[ et ] =
+ XtSetEventDispatcher( QPaintDevice::x11AppDisplay(),
+ et, ::qmotif_event_dispatcher );
+}
+
+void QXtEventLoopPrivate::unhook()
+{
+ // unhook Qt from Xt (event dispatchers)
+ // unhook Xt from Qt? (QXtEventLoopEventLoop)
+
+ // ### TODO extensions?
+ int et;
+ for ( et = 2; et < LASTEvent; et++ )
+ (void) XtSetEventDispatcher( QPaintDevice::x11AppDisplay(),
+ et, dispatchers[ et ] );
+ dispatchers.resize( 0 );
+
+ /*
+ We cannot destroy the app context here because it closes the X
+ display, something QApplication does as well a bit later.
+ if ( ownContext )
+ XtDestroyApplicationContext( ownContext );
+ */
+ appContext = ownContext = 0;
+}
+
+extern bool qt_try_modal( QWidget *, XEvent * ); // defined in qapplication_x11.cpp
+Boolean qmotif_event_dispatcher( XEvent *event )
+{
+ QApplication::sendPostedEvents();
+
+ QWidgetIntDict *mapper = &static_d->mapper;
+ QWidget* qMotif = mapper->find( event->xany.window );
+ if ( !qMotif && QWidget::find( event->xany.window) == 0 ) {
+ // event is not for Qt, try Xt
+ Display* dpy = QPaintDevice::x11AppDisplay();
+ Widget w = XtWindowToWidget( dpy, event->xany.window );
+ while ( w && ! ( qMotif = mapper->find( XtWindow( w ) ) ) ) {
+ if ( XtIsShell( w ) ) {
+ break;
+ }
+ w = XtParent( w );
+ }
+
+ if ( qMotif &&
+ ( event->type == XKeyPress || event->type == XKeyRelease ) ) {
+ // remap key events
+ event->xany.window = qMotif->winId();
+ }
+ }
+
+ last_xevent = event;
+ bool delivered = ( qApp->x11ProcessEvent( event ) != -1 );
+ last_xevent = 0;
+ if ( qMotif ) {
+ switch ( event->type ) {
+ case EnterNotify:
+ case LeaveNotify:
+ event->xcrossing.focus = False;
+ delivered = FALSE;
+ break;
+ case XKeyPress:
+ case XKeyRelease:
+ delivered = TRUE;
+ break;
+ case XFocusIn:
+ case XFocusOut:
+ delivered = FALSE;
+ break;
+ default:
+ delivered = FALSE;
+ break;
+ }
+ }
+
+ if ( delivered )
+ return True;
+
+
+ if ( QApplication::activePopupWidget() )
+ // we get all events through the popup grabs. discard the event
+ return True;
+
+ if ( qMotif && QApplication::activeModalWidget() ) {
+ if ( !qt_try_modal(qMotif, event) )
+ return True;
+
+ }
+
+ if ( static_d->dispatchers[ event->type ]( event ) )
+ // Xt handled the event.
+ return True;
+
+ return False;
+}
+
+
+
+/*!
+ \class QXtEventLoop
+ \brief The QXtEventLoop class is the core behind the Motif Extension.
+
+ \extension Motif
+
+ QXtEventLoop only provides a few public functions, but is the brains
+ behind the integration. QXtEventLoop is responsible for initializing
+ the Xt toolkit and the Xt application context. It does not open a
+ connection to the X server, this is done by using QApplication.
+
+ The only member function in QXtEventLoop that depends on an X server
+ connection is QXtEventLoop::initialize(). QXtEventLoop must be created before
+ QApplication.
+
+ Example usage of QXtEventLoop and QApplication:
+
+ \code
+ static char *resources[] = {
+ ...
+ };
+
+ int main(int argc, char **argv)
+ {
+ QXtEventLoop integrator( "AppClass" );
+ XtAppSetFallbackResources( integrator.applicationContext(),
+ resources );
+ QApplication app( argc, argv );
+
+ ...
+
+ return app.exec();
+ }
+ \endcode
+*/
+
+/*!
+ Creates QXtEventLoop, which allows Qt and Xt/Motif integration.
+
+ If \a context is NULL, QXtEventLoop creates a default application context
+ itself. The context is accessible through applicationContext().
+
+ All arguments passed to this function (\a applicationClass, \a
+ options and \a numOptions) are used to call XtDisplayInitialize()
+ after QApplication has been constructed.
+*/
+
+
+
+QXtEventLoop::QXtEventLoop( const char *applicationClass, XtAppContext context, XrmOptionDescRec *options , int numOptions)
+{
+#if defined(QT_CHECK_STATE)
+ if ( static_d )
+ qWarning( "QXtEventLoop: should only have one QXtEventLoop instance!" );
+#endif
+
+ d = static_d = new QXtEventLoopPrivate;
+ XtToolkitInitialize();
+ if ( context )
+ d->appContext = context;
+ else
+ d->ownContext = d->appContext = XtCreateApplicationContext();
+
+ d->applicationClass = applicationClass;
+ d->options = options;
+ d->numOptions = numOptions;
+}
+
+
+/*!
+ Destroys QXtEventLoop.
+*/
+QXtEventLoop::~QXtEventLoop()
+{
+ // d->unhook();
+ delete d;
+}
+
+/*!
+ Returns the application context.
+*/
+XtAppContext QXtEventLoop::applicationContext() const
+{
+ return d->appContext;
+}
+
+
+void QXtEventLoop::appStartingUp()
+{
+ int argc = qApp->argc();
+ XtDisplayInitialize( d->appContext,
+ QPaintDevice::x11AppDisplay(),
+ qApp->name(),
+ d->applicationClass,
+ d->options,
+ d->numOptions,
+ &argc,
+ qApp->argv() );
+ d->hookMeUp();
+}
+
+void QXtEventLoop::appClosingDown()
+{
+ d->unhook();
+}
+
+
+/*!\internal
+ */
+void QXtEventLoop::registerWidget( QWidget* w )
+{
+ if ( !static_d )
+ return;
+ static_d->mapper.insert( w->winId(), w );
+}
+
+
+/*!\internal
+ */
+void QXtEventLoop::unregisterWidget( QWidget* w )
+{
+ if ( !static_d )
+ return;
+ static_d->mapper.remove( w->winId() );
+}
+
+
+/*! \internal
+ */
+void qmotif_socknot_handler( XtPointer pointer, int *, XtInputId *id )
+{
+ QXtEventLoop *eventloop = (QXtEventLoop *) pointer;
+ QSocketNotifier *socknot = static_d->socknotDict.find( *id );
+ if ( ! socknot ) // this shouldn't happen
+ return;
+ eventloop->setSocketNotifierPending( socknot );
+}
+
+/*! \reimp
+ */
+void QXtEventLoop::registerSocketNotifier( QSocketNotifier *notifier )
+{
+ XtInputMask mask;
+ switch ( notifier->type() ) {
+ case QSocketNotifier::Read:
+ mask = XtInputReadMask;
+ break;
+
+ case QSocketNotifier::Write:
+ mask = XtInputWriteMask;
+ break;
+
+ case QSocketNotifier::Exception:
+ mask = XtInputExceptMask;
+ break;
+
+ default:
+ qWarning( "QXtEventLoopEventLoop: socket notifier has invalid type" );
+ return;
+ }
+
+ XtInputId id = XtAppAddInput( d->appContext,
+ notifier->socket(), (XtPointer) mask,
+ qmotif_socknot_handler, this );
+ d->socknotDict.insert( id, notifier );
+
+ QEventLoop::registerSocketNotifier( notifier );
+}
+
+/*! \reimp
+ */
+void QXtEventLoop::unregisterSocketNotifier( QSocketNotifier *notifier )
+{
+ QIntDictIterator<QSocketNotifier> it( d->socknotDict );
+ while ( it.current() && notifier != it.current() )
+ ++it;
+ if ( ! it.current() ) {
+ // this shouldn't happen
+ qWarning( "QXtEventLoopEventLoop: failed to unregister socket notifier" );
+ return;
+ }
+
+ XtRemoveInput( it.currentKey() );
+ d->socknotDict.remove( it.currentKey() );
+
+ QEventLoop::unregisterSocketNotifier( notifier );
+}
+
+/*! \internal
+ */
+void qmotif_timeout_handler( XtPointer, XtIntervalId * )
+{
+ static_d->activate_timers = TRUE;
+ static_d->timerid = 0;
+}
+
+/*! \reimp
+ */
+bool QXtEventLoop::processEvents( ProcessEventsFlags flags )
+{
+ // Qt uses posted events to do lots of delayed operations, like repaints... these
+ // need to be delivered before we go to sleep
+ QApplication::sendPostedEvents();
+
+ // make sure we fire off Qt's timers
+ int ttw = timeToWait();
+ if ( d->timerid != 0 ) {
+ XtRemoveTimeOut( d->timerid );
+ }
+ d->timerid = 0;
+ if ( ttw != -1 ) {
+ d->timerid =
+ XtAppAddTimeOut( d->appContext, ttw,
+ qmotif_timeout_handler, 0 );
+ }
+
+ // get the pending event mask from Xt and process the next event
+ XtInputMask pendingmask = XtAppPending( d->appContext );
+ XtInputMask mask = pendingmask;
+ if ( pendingmask & XtIMTimer ) {
+ mask &= ~XtIMTimer;
+ // zero timers will starve the Xt X event dispatcher... so process
+ // something *instead* of a timer first...
+ if ( mask != 0 )
+ XtAppProcessEvent( d->appContext, mask );
+ // and process a timer afterwards
+ mask = pendingmask & XtIMTimer;
+ }
+
+ if ( ( flags & WaitForMore ) )
+ XtAppProcessEvent( d->appContext, XtIMAll );
+ else
+ XtAppProcessEvent( d->appContext, mask );
+
+ int nevents = 0;
+ if ( ! ( flags & ExcludeSocketNotifiers ) )
+ nevents += activateSocketNotifiers();
+
+ if ( d->activate_timers ) {
+ nevents += activateTimers();
+ }
+ d->activate_timers = FALSE;
+
+ return ( (flags & WaitForMore) || ( pendingmask != 0 ) || nevents > 0 );
+}
+
+#include "qxteventloop.moc"
+
+#endif
+