qmotif.cpp
来自「Linux下的基于X11的图形开发环境。」· C++ 代码 · 共 513 行
CPP
513 行
/****************************************************************************** $Id: qt/qmotif.cpp 3.1.1 edited Dec 4 10:34 $**** Implementation of Qt extension classes for Xt/Motif support.**** Copyright (C) 1992-2002 Trolltech AS. All rights reserved.**** This file is part of the Qt extension for Xt/Motif support.**** Licensees holding valid Qt Enterprise Edition licenses for X11 may use** this file in accordance with the Qt Commercial License Agreement provided** with the Software.**** This file is not available for use under any other license without** express written permission from the copyright holder.**** 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.**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.************************************************************************/#include "qmotif.h"#include <qapplication.h>#include <qwidgetintdict.h>// resolve the conflict between X11's FocusIn and QEvent::FocusInconst int XFocusOut = FocusOut;const int XFocusIn = FocusIn;#undef FocusOut#undef FocusInconst int XKeyPress = KeyPress;const int XKeyRelease = KeyRelease;#undef KeyPress#undef KeyReleaseBoolean qmotif_event_dispatcher( XEvent *event );class QMotifPrivate{public: QMotifPrivate(); void hookMeUp(); void unhook(); XtAppContext appContext, ownContext; QMemArray<XtEventDispatchProc> dispatchers; QWidgetIntDict mapper; QIntDict<QSocketNotifier> socknotDict; uint pending_socknots; bool activate_timers; int timerid; // arguments for Xt display initialization const char* applicationClass; XrmOptionDescRec* options; int numOptions;};static QMotifPrivate *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 QMotif::redeliverEvent( XEvent *event ){ // redeliver the event to Xt, NOT through Qt if ( static_d->dispatchers[ event->type ]( event ) ) return TRUE; return FALSE;};/*!\internal */XEvent* QMotif::lastEvent(){ return last_xevent;}QMotifPrivate::QMotifPrivate() : appContext(NULL), ownContext(NULL), pending_socknots(0), activate_timers(FALSE), timerid(-1){}void QMotifPrivate::hookMeUp(){ // worker to plug Qt into Xt (event dispatchers) // and Xt into Qt (QMotifEventLoop) // ### 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 QMotifPrivate::unhook(){ // unhook Qt from Xt (event dispatchers) // unhook Xt from Qt? (QMotifEventLoop) // ### 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.cppBoolean qmotif_event_dispatcher( XEvent *event ){ static bool grabbed = FALSE; 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 if ( !grabbed && ( event->type == XFocusIn && event->xfocus.mode == NotifyGrab ) ) { grabbed = TRUE; } else if ( grabbed && ( event->type == XFocusOut && event->xfocus.mode == NotifyUngrab ) ) { grabbed = FALSE; } 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(); } } /* If the mouse has been grabbed for a window that we don't know about, we shouldn't deliver any pointer events, since this will intercept the event that ends the mouse grab that Xt/Motif started. */ bool do_deliver = TRUE; if ( grabbed && ( event->type == ButtonPress || event->type == ButtonRelease || event->type == MotionNotify || event->type == EnterNotify || event->type == LeaveNotify ) ) do_deliver = FALSE; last_xevent = event; bool delivered = do_deliver && ( 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 QMotif \brief The QMotif class provides the basis of the Motif Extension. \extension Motif QMotif only provides a few public functions, but it is at the heart of the integration. QMotif is responsible for initializing the Xt toolkit and the Xt application context. It does not open a connection to the X server, that is done by QApplication. The only member function in QMotif that depends on an X server connection is QMotif::initialize(). QMotif must be created before QApplication. Example usage of QMotif and QApplication: \code static char *resources[] = { ... }; int main(int argc, char **argv) { QMotif integrator( "AppClass" ); XtAppSetFallbackResources( integrator.applicationContext(), resources ); QApplication app( argc, argv ); ... return app.exec(); } \endcode*//*! Creates QMotif, which allows Qt and Xt/Motif integration. If \a context is 0, QMotif 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.*/QMotif::QMotif( const char *applicationClass, XtAppContext context, XrmOptionDescRec *options , int numOptions){#if defined(QT_CHECK_STATE) if ( static_d ) qWarning( "QMotif: should only have one QMotif instance!" );#endif d = static_d = new QMotifPrivate; XtToolkitInitialize(); if ( context ) d->appContext = context; else d->ownContext = d->appContext = XtCreateApplicationContext(); d->applicationClass = applicationClass; d->options = options; d->numOptions = numOptions;}/*! Destroys QMotif.*/QMotif::~QMotif(){ // d->unhook(); delete d;}/*! Returns the application context.*/XtAppContext QMotif::applicationContext() const{ return d->appContext;}void QMotif::appStartingUp(){ /* QApplication could be using a Display from an outside source, so we should only initialize the display if the current application context does not contain the QApplication display */ bool display_found = FALSE; Display **displays; Cardinal x, count; XtGetDisplays( d->appContext, &displays, &count ); for ( x = 0; x < count && ! display_found; ++x ) { if ( displays[x] == QPaintDevice::x11AppDisplay() ) display_found = TRUE; } if ( displays ) XtFree( (char *) displays ); if ( ! display_found ) { int argc = qApp->argc(); XtDisplayInitialize( d->appContext, QPaintDevice::x11AppDisplay(), qApp->name(), d->applicationClass, d->options, d->numOptions, &argc, qApp->argv() ); } d->hookMeUp();}void QMotif::appClosingDown(){ d->unhook();}/*!\internal */void QMotif::registerWidget( QWidget* w ){ if ( !static_d ) return; static_d->mapper.insert( w->winId(), w );}/*!\internal */void QMotif::unregisterWidget( QWidget* w ){ if ( !static_d ) return; static_d->mapper.remove( w->winId() );}/*! \internal */void qmotif_socknot_handler( XtPointer pointer, int *, XtInputId *id ){ QMotif *eventloop = (QMotif *) pointer; QSocketNotifier *socknot = static_d->socknotDict.find( *id ); if ( ! socknot ) // this shouldn't happen return; eventloop->setSocketNotifierPending( socknot ); if ( ++static_d->pending_socknots > static_d->socknotDict.count() ) { /* We have too many pending socket notifiers. Since Xt prefers socket notifiers over X events, we should go ahead and activate all our pending socket notifiers so that the event loop doesn't freeze up because of this. */ eventloop->activateSocketNotifiers(); static_d->pending_socknots = 0; }}/*! \reimp */void QMotif::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( "QMotifEventLoop: 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 QMotif::unregisterSocketNotifier( QSocketNotifier *notifier ){ QIntDictIterator<QSocketNotifier> it( d->socknotDict ); while ( it.current() && notifier != it.current() ) ++it; if ( ! it.current() ) { // this shouldn't happen qWarning( "QMotifEventLoop: 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 = -1;}/*! \reimp */bool QMotif::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(); bool canWait = ( flags & WaitForMore ); // make sure we fire off Qt's timers int ttw = timeToWait(); if ( d->timerid != -1 ) { XtRemoveTimeOut( d->timerid ); } d->timerid = -1; 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 ( canWait ) XtAppProcessEvent( d->appContext, XtIMAll ); else XtAppProcessEvent( d->appContext, mask ); int nevents = 0; if ( ! ( flags & ExcludeSocketNotifiers ) ) { nevents += activateSocketNotifiers(); d->pending_socknots = 0; } if ( d->activate_timers ) { nevents += activateTimers(); } d->activate_timers = FALSE; return ( canWait || ( pendingmask != 0 ) || nevents > 0 );}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?