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.
473 lines
12 KiB
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
|
|
|