add more spacing
[personal-kdebase.git] / apps / nsplugins / viewer / qxteventloop.cpp
blob942d26f4e136cb4b05a6a2b93a23082286ca53d2
1 /****************************************************************************
2 ** Implementation of QWidget class
3 **
4 ** Created : 931031
5 **
6 ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
7 **
8 ** This file is part of the Xt extension of the Qt GUI Toolkit.
9 **
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
32 ** not clear to you.
34 **********************************************************************/
36 #include "qxteventloop.h"
38 #include <config-apps.h>
40 #include <QApplication>
41 #include <kglobal.h>
43 #include <qwidgetintdict.h>
44 #include <QVector>
45 #include <QHash>
47 // resolve the conflict between X11's FocusIn and QEvent::FocusIn
48 const int XFocusOut = FocusOut;
49 const int XFocusIn = FocusIn;
50 #undef FocusOut
51 #undef FocusIn
53 const int XKeyPress = KeyPress;
54 const int XKeyRelease = KeyRelease;
55 #undef KeyPress
56 #undef KeyRelease
58 Boolean qmotif_event_dispatcher( XEvent *event );
60 class QXtEventLoopPrivate
62 public:
63 QXtEventLoopPrivate();
65 void hookMeUp();
66 void unhook();
68 XtAppContext appContext, ownContext;
69 QVector<XtEventDispatchProc> dispatchers;
70 QWidgetIntDict mapper;
72 QHash<int, QSocketNotifier> socknotDict;
73 bool activate_timers;
74 XtIntervalId timerid;
76 // arguments for Xt display initialization
77 const char* applicationClass;
78 XrmOptionDescRec* options;
79 int numOptions;
81 static QXtEventLoopPrivate *static_d = 0;
82 static XEvent* last_xevent = 0;
85 /*! \internal
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 ) )
97 return true;
98 return false;
102 /*!\internal
104 XEvent* QXtEventLoop::lastEvent()
106 return last_xevent;
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 );
124 int et;
125 for ( et = 2; et < LASTEvent; et++ )
126 dispatchers[ 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?
137 int et;
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.
146 if ( ownContext )
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 ) ) {
165 break;
167 w = XtParent( w );
170 if ( qMotif &&
171 ( event->type == XKeyPress || event->type == XKeyRelease ) ) {
172 // remap key events
173 event->xany.window = qMotif->winId();
177 last_xevent = event;
178 bool delivered = ( qApp->x11ProcessEvent( event ) != -1 );
179 last_xevent = 0;
180 if ( qMotif ) {
181 switch ( event->type ) {
182 case EnterNotify:
183 case LeaveNotify:
184 event->xcrossing.focus = false;
185 delivered = false;
186 break;
187 case XKeyPress:
188 case XKeyRelease:
189 delivered = true;
190 break;
191 case XFocusIn:
192 case XFocusOut:
193 delivered = false;
194 break;
195 default:
196 delivered = false;
197 break;
201 if ( delivered )
202 return true;
205 if ( QApplication::activePopupWidget() )
206 // we get all events through the popup grabs. discard the event
207 return true;
209 if ( qMotif && QApplication::activeModalWidget() ) {
210 if ( !qt_try_modal(qMotif, event) )
211 return true;
215 if ( static_d->dispatchers[ event->type ]( event ) )
216 // Xt handled the event.
217 return true;
219 return false;
225 \class QXtEventLoop
226 \brief The QXtEventLoop class is the core behind the Motif Extension.
228 \extension Motif
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
237 QApplication.
239 Example usage of QXtEventLoop and QApplication:
241 \code
242 static char *resources[] = {
246 int main(int argc, char **argv)
248 QXtEventLoop integrator( "AppClass" );
249 XtAppSetFallbackResources( integrator.applicationContext(),
250 resources );
251 QApplication app( argc, argv );
255 return app.exec();
257 \endcode
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)
276 if ( static_d )
277 qWarning( "QXtEventLoop: should only have one QXtEventLoop instance!" );
278 #endif
280 d = static_d = new QXtEventLoopPrivate;
281 XtToolkitInitialize();
282 if ( context )
283 d->appContext = context;
284 else
285 d->ownContext = d->appContext = XtCreateApplicationContext();
287 d->applicationClass = applicationClass;
288 d->options = options;
289 d->numOptions = numOptions;
294 Destroys QXtEventLoop.
296 QXtEventLoop::~QXtEventLoop()
298 // d->unhook();
299 delete d;
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(),
316 qApp->name(),
317 d->applicationClass,
318 d->options,
319 d->numOptions,
320 &argc,
321 qApp->argv() );
322 d->hookMeUp();
325 void QXtEventLoop::appClosingDown()
327 d->unhook();
331 /*!\internal
333 void QXtEventLoop::registerWidget( QWidget* w )
335 if ( !static_d )
336 return;
337 static_d->mapper.insert( w->winId(), w );
341 /*!\internal
343 void QXtEventLoop::unregisterWidget( QWidget* w )
345 if ( !static_d )
346 return;
347 static_d->mapper.remove( w->winId() );
351 /*! \internal
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
358 return;
359 eventloop->setSocketNotifierPending( socknot );
362 /*! \reimp
364 void QXtEventLoop::registerSocketNotifier( QSocketNotifier *notifier )
366 XtInputMask mask;
367 switch ( notifier->type() ) {
368 case QSocketNotifier::Read:
369 mask = XtInputReadMask;
370 break;
372 case QSocketNotifier::Write:
373 mask = XtInputWriteMask;
374 break;
376 case QSocketNotifier::Exception:
377 mask = XtInputExceptMask;
378 break;
380 default:
381 qWarning( "QXtEventLoopEventLoop: socket notifier has invalid type" );
382 return;
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 );
393 /*! \reimp
395 void QXtEventLoop::unregisterSocketNotifier( QSocketNotifier *notifier )
398 int key = d->socknotDict.key(notifier);
399 if ( ! key ) {
400 // this shouldn't happen
401 qWarning( "QXtEventLoopEventLoop: failed to unregister socket notifier" );
402 return;
405 XtRemoveInput( key );
406 d->socknotDict.remove( key );
408 QEventLoop::unregisterSocketNotifier( notifier );
411 /*! \internal
413 void qmotif_timeout_handler( XtPointer, XtIntervalId * )
415 static_d->activate_timers = true;
416 static_d->timerid = 0;
419 /*! \reimp
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 );
432 d->timerid = 0;
433 if ( ttw != -1 ) {
434 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 ) {
443 mask &= ~XtIMTimer;
444 // zero timers will starve the Xt X event dispatcher... so process
445 // something *instead* of a timer first...
446 if ( mask != 0 )
447 XtAppProcessEvent( d->appContext, mask );
448 // and process a timer afterwards
449 mask = pendingmask & XtIMTimer;
452 if ( ( flags & WaitForMore ) )
453 XtAppProcessEvent( d->appContext, XtIMAll );
454 else
455 XtAppProcessEvent( d->appContext, mask );
457 int nevents = 0;
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"