diff options
Diffstat (limited to 'nsplugins/viewer/qxteventloop.cpp')
-rw-r--r-- | nsplugins/viewer/qxteventloop.cpp | 472 |
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 sales@trolltech.com 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 info@trolltech.com 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 + |