1 /****************************************************************************
2 ** Implementation of QWidget class
6 ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
8 ** This file is part of the Xt extension of the Qt GUI Toolkit.
10 ** This file may be distributed under the terms of the Q Public License
11 ** as defined by Trolltech AS of Norway and appearing in the file
12 ** LICENSE.QPL included in the packaging of this file.
14 ** This file may be distributed and/or modified under the terms of the
15 ** GNU General Public License version 2 as published by the Free Software
16 ** Foundation and appearing in the file LICENSE.GPL included in the
17 ** packaging of this file.
19 ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
20 ** licenses may use this file in accordance with the Qt Commercial License
21 ** Agreement provided with the Software.
23 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
24 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
26 ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
27 ** information about Qt Commercial License Agreements.
28 ** See http://www.trolltech.com/qpl/ for QPL licensing information.
29 ** See http://www.trolltech.com/gpl/ for GPL licensing information.
31 ** Contact info@trolltech.com if any conditions of this licensing are
34 **********************************************************************/
36 #include "qxteventloop.h"
38 #include <config-apps.h>
40 #include <QApplication>
43 #include <qwidgetintdict.h>
47 // resolve the conflict between X11's FocusIn and QEvent::FocusIn
48 const int XFocusOut
= FocusOut
;
49 const int XFocusIn
= FocusIn
;
53 const int XKeyPress
= KeyPress
;
54 const int XKeyRelease
= KeyRelease
;
58 Boolean
qmotif_event_dispatcher( XEvent
*event
);
60 class QXtEventLoopPrivate
63 QXtEventLoopPrivate();
68 XtAppContext appContext
, ownContext
;
69 QVector
<XtEventDispatchProc
> dispatchers
;
70 QWidgetIntDict mapper
;
72 QHash
<int, QSocketNotifier
> socknotDict
;
76 // arguments for Xt display initialization
77 const char* applicationClass
;
78 XrmOptionDescRec
* options
;
81 static QXtEventLoopPrivate
*static_d
= 0;
82 static XEvent
* last_xevent
= 0;
86 Redeliver the given XEvent to Xt.
88 Rationale: An XEvent handled by Qt does not go through the Xt event
89 handlers, and the internal state of Xt/Motif widgets will not be
90 updated. This function should only be used if an event delivered by
91 Qt to a QWidget needs to be sent to an Xt/Motif widget.
93 bool QXtEventLoop::redeliverEvent( XEvent
*event
)
95 // redeliver the event to Xt, NOT through Qt
96 if ( static_d
->dispatchers
[ event
->type
]( event
) )
104 XEvent
* QXtEventLoop::lastEvent()
110 QXtEventLoopPrivate::QXtEventLoopPrivate()
111 : appContext(NULL
), ownContext(NULL
),
112 activate_timers(false), timerid(0)
116 void QXtEventLoopPrivate::hookMeUp()
118 // worker to plug Qt into Xt (event dispatchers)
119 // and Xt into Qt (QXtEventLoopEventLoop)
121 // ### TODO extensions?
122 dispatchers
.resize( LASTEvent
);
123 dispatchers
.fill( 0 );
125 for ( et
= 2; et
< LASTEvent
; et
++ )
127 XtSetEventDispatcher( QPaintDevice::x11AppDisplay(),
128 et
, ::qmotif_event_dispatcher
);
131 void QXtEventLoopPrivate::unhook()
133 // unhook Qt from Xt (event dispatchers)
134 // unhook Xt from Qt? (QXtEventLoopEventLoop)
136 // ### TODO extensions?
138 for ( et
= 2; et
< LASTEvent
; et
++ )
139 (void) XtSetEventDispatcher( QPaintDevice::x11AppDisplay(),
140 et
, dispatchers
[ et
] );
141 dispatchers
.resize( 0 );
144 We cannot destroy the app context here because it closes the X
145 display, something QApplication does as well a bit later.
147 XtDestroyApplicationContext( ownContext );
149 appContext
= ownContext
= 0;
152 extern bool qt_try_modal( QWidget
*, XEvent
* ); // defined in qapplication_x11.cpp
153 Boolean
qmotif_event_dispatcher( XEvent
*event
)
155 QApplication::sendPostedEvents();
157 QWidgetIntDict
*mapper
= &static_d
->mapper
;
158 QWidget
* qMotif
= mapper
->find( event
->xany
.window
);
159 if ( !qMotif
&& QWidget::find( event
->xany
.window
) == 0 ) {
160 // event is not for Qt, try Xt
161 Display
* dpy
= QPaintDevice::x11AppDisplay();
162 Widget w
= XtWindowToWidget( dpy
, event
->xany
.window
);
163 while ( w
&& ! ( qMotif
= mapper
->find( XtWindow( w
) ) ) ) {
164 if ( XtIsShell( w
) ) {
171 ( event
->type
== XKeyPress
|| event
->type
== XKeyRelease
) ) {
173 event
->xany
.window
= qMotif
->winId();
178 bool delivered
= ( qApp
->x11ProcessEvent( event
) != -1 );
181 switch ( event
->type
) {
184 event
->xcrossing
.focus
= false;
205 if ( QApplication::activePopupWidget() )
206 // we get all events through the popup grabs. discard the event
209 if ( qMotif
&& QApplication::activeModalWidget() ) {
210 if ( !qt_try_modal(qMotif
, event
) )
215 if ( static_d
->dispatchers
[ event
->type
]( event
) )
216 // Xt handled the event.
226 \brief The QXtEventLoop class is the core behind the Motif Extension.
230 QXtEventLoop only provides a few public functions, but is the brains
231 behind the integration. QXtEventLoop is responsible for initializing
232 the Xt toolkit and the Xt application context. It does not open a
233 connection to the X server, this is done by using QApplication.
235 The only member function in QXtEventLoop that depends on an X server
236 connection is QXtEventLoop::initialize(). QXtEventLoop must be created before
239 Example usage of QXtEventLoop and QApplication:
242 static char *resources[] = {
246 int main(int argc, char **argv)
248 QXtEventLoop integrator( "AppClass" );
249 XtAppSetFallbackResources( integrator.applicationContext(),
251 QApplication app( argc, argv );
261 Creates QXtEventLoop, which allows Qt and Xt/Motif integration.
263 If \a context is NULL, QXtEventLoop creates a default application context
264 itself. The context is accessible through applicationContext().
266 All arguments passed to this function (\a applicationClass, \a
267 options and \a numOptions) are used to call XtDisplayInitialize()
268 after QApplication has been constructed.
273 QXtEventLoop::QXtEventLoop( const char *applicationClass
, XtAppContext context
, XrmOptionDescRec
*options
, int numOptions
)
275 #if defined(QT_CHECK_STATE)
277 qWarning( "QXtEventLoop: should only have one QXtEventLoop instance!" );
280 d
= static_d
= new QXtEventLoopPrivate
;
281 XtToolkitInitialize();
283 d
->appContext
= context
;
285 d
->ownContext
= d
->appContext
= XtCreateApplicationContext();
287 d
->applicationClass
= applicationClass
;
288 d
->options
= options
;
289 d
->numOptions
= numOptions
;
294 Destroys QXtEventLoop.
296 QXtEventLoop::~QXtEventLoop()
303 Returns the application context.
305 XtAppContext
QXtEventLoop::applicationContext() const
307 return d
->appContext
;
311 void QXtEventLoop::appStartingUp()
313 int argc
= qApp
->argc();
314 XtDisplayInitialize( d
->appContext
,
315 QPaintDevice::x11AppDisplay(),
325 void QXtEventLoop::appClosingDown()
333 void QXtEventLoop::registerWidget( QWidget
* w
)
337 static_d
->mapper
.insert( w
->winId(), w
);
343 void QXtEventLoop::unregisterWidget( QWidget
* w
)
347 static_d
->mapper
.remove( w
->winId() );
353 void qmotif_socknot_handler( XtPointer pointer
, int *, XtInputId
*id
)
355 QXtEventLoop
*eventloop
= (QXtEventLoop
*) pointer
;
356 QSocketNotifier
*socknot
= static_d
->socknotDict
.value( *id
);
357 if ( ! socknot
) // this shouldn't happen
359 eventloop
->setSocketNotifierPending( socknot
);
364 void QXtEventLoop::registerSocketNotifier( QSocketNotifier
*notifier
)
367 switch ( notifier
->type() ) {
368 case QSocketNotifier::Read
:
369 mask
= XtInputReadMask
;
372 case QSocketNotifier::Write
:
373 mask
= XtInputWriteMask
;
376 case QSocketNotifier::Exception
:
377 mask
= XtInputExceptMask
;
381 qWarning( "QXtEventLoopEventLoop: socket notifier has invalid type" );
385 XtInputId id
= XtAppAddInput( d
->appContext
,
386 notifier
->socket(), (XtPointer
) mask
,
387 qmotif_socknot_handler
, this );
388 d
->socknotDict
.insert( id
, notifier
);
390 QEventLoop::registerSocketNotifier( notifier
);
395 void QXtEventLoop::unregisterSocketNotifier( QSocketNotifier
*notifier
)
398 int key
= d
->socknotDict
.key(notifier
);
400 // this shouldn't happen
401 qWarning( "QXtEventLoopEventLoop: failed to unregister socket notifier" );
405 XtRemoveInput( key
);
406 d
->socknotDict
.remove( key
);
408 QEventLoop::unregisterSocketNotifier( notifier
);
413 void qmotif_timeout_handler( XtPointer
, XtIntervalId
* )
415 static_d
->activate_timers
= true;
416 static_d
->timerid
= 0;
421 bool QXtEventLoop::processEvents( ProcessEventsFlags flags
)
423 // Qt uses posted events to do lots of delayed operations, like repaints... these
424 // need to be delivered before we go to sleep
425 QApplication::sendPostedEvents();
427 // make sure we fire off Qt's timers
428 int ttw
= timeToWait();
429 if ( d
->timerid
!= 0 ) {
430 XtRemoveTimeOut( d
->timerid
);
435 XtAppAddTimeOut( d
->appContext
, ttw
,
436 qmotif_timeout_handler
, 0 );
439 // get the pending event mask from Xt and process the next event
440 XtInputMask pendingmask
= XtAppPending( d
->appContext
);
441 XtInputMask mask
= pendingmask
;
442 if ( pendingmask
& XtIMTimer
) {
444 // zero timers will starve the Xt X event dispatcher... so process
445 // something *instead* of a timer first...
447 XtAppProcessEvent( d
->appContext
, mask
);
448 // and process a timer afterwards
449 mask
= pendingmask
& XtIMTimer
;
452 if ( ( flags
& WaitForMore
) )
453 XtAppProcessEvent( d
->appContext
, XtIMAll
);
455 XtAppProcessEvent( d
->appContext
, mask
);
458 if ( ! ( flags
& ExcludeSocketNotifiers
) )
459 nevents
+= activateSocketNotifiers();
461 if ( d
->activate_timers
) {
462 nevents
+= activateTimers();
464 d
->activate_timers
= false;
466 return ( (flags
& WaitForMore
) || ( pendingmask
!= 0 ) || nevents
> 0 );
469 #include "qxteventloop.moc"