You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebase/nsplugins/viewer/qxteventloop.cpp

473 lines
12 KiB

/****************************************************************************
** 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