-rw-r--r-- | library/qpeapplication.cpp | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/library/qpeapplication.cpp b/library/qpeapplication.cpp index 0e469ae..28fb13a 100644 --- a/library/qpeapplication.cpp +++ b/library/qpeapplication.cpp @@ -1,280 +1,282 @@ /********************************************************************** ** Copyright (C) 2000-2002 Trolltech AS. All rights reserved. ** ** This file is part of the Qtopia Environment. ** ** 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. ** ** 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/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** */ #define QTOPIA_INTERNAL_LANGLIST #include <stdlib.h> #include <unistd.h> #include <linux/limits.h> // needed for some toolchains (PATH_MAX) #include <qfile.h> #include <qqueue.h> #ifdef Q_WS_QWS #ifndef QT_NO_COP #if QT_VERSION <= 231 #define private public #define sendLocally processEvent #include "qcopenvelope_qws.h" #undef private #else #include "qcopenvelope_qws.h" #endif #endif #include <qwindowsystem_qws.h> #endif #include <qtextstream.h> #include <qpalette.h> #include <qbuffer.h> #include <qptrdict.h> #include <qregexp.h> #include <qdir.h> #include <qlabel.h> #include <qdialog.h> #include <qdragobject.h> #include <qtextcodec.h> #include <qevent.h> #include <qtooltip.h> #include <qsignal.h> #include <qmainwindow.h> #include <qwidgetlist.h> +#include <qpixmapcache.h> #if defined(Q_WS_QWS) && !defined(QT_NO_COP) #define QTOPIA_INTERNAL_INITAPP #include "qpeapplication.h" #include "qpestyle.h" #include "styleinterface.h" #if QT_VERSION >= 300 #include <qstylefactory.h> #else #include <qplatinumstyle.h> #include <qwindowsstyle.h> #include <qmotifstyle.h> #include <qmotifplusstyle.h> #include "lightstyle.h" #include <qpe/qlibrary.h> #endif #include "global.h" #include "resource.h" #if QT_VERSION <= 230 && defined(QT_NO_CODECS) #include "qutfcodec.h" #endif #include "config.h" #include "network.h" #ifdef QWS #include "fontmanager.h" #endif #include "alarmserver.h" #include "applnk.h" #include "qpemenubar.h" #include "textcodecinterface.h" #include "imagecodecinterface.h" #include <unistd.h> #include <sys/file.h> #include <sys/ioctl.h> #include <sys/soundcard.h> #include "qt_override_p.h" class QPEApplicationData { public: QPEApplicationData ( ) : presstimer( 0 ), presswidget( 0 ), rightpressed( false ), kbgrabbed( false ), notbusysent( false ), preloaded( false ), forceshow( false ), nomaximize( false ), - keep_running( true ), qpe_main_widget( 0 ), qcopQok( false ) + keep_running( true ), qcopQok( false ), qpe_main_widget( 0 ) {} int presstimer; QWidget* presswidget; QPoint presspos; bool rightpressed : 1; bool kbgrabbed : 1; bool notbusysent : 1; bool preloaded : 1; bool forceshow : 1; bool nomaximize : 1; - bool qcopQok : 1; bool keep_running : 1; + bool qcopQok : 1; QStringList langs; QString appName; struct QCopRec { QCopRec( const QCString &ch, const QCString &msg, const QByteArray &d ) : channel( ch ), message( msg ), data( d ) { } QCString channel; QCString message; QByteArray data; }; QWidget* qpe_main_widget; QGuardedPtr<QWidget> lastraised; QQueue<QCopRec> qcopq; QString styleName; QString decorationName; void enqueueQCop( const QCString &ch, const QCString &msg, const QByteArray &data ) { qcopq.enqueue( new QCopRec( ch, msg, data ) ); } void sendQCopQ() { if (!qcopQok ) return; QCopRec * r; while((r=qcopq.dequeue())) { // remove from queue before sending... // event loop can come around again before getting // back from sendLocally #ifndef QT_NO_COP QCopChannel::sendLocally( r->channel, r->message, r->data ); #endif delete r; } } static void show_mx(QWidget* mw, bool nomaximize, const QString & = QString::null ) { // ugly hack, remove that later after finding a sane solution // Addendum: Only Sharp currently has models with high resolution but (physically) small displays, // so this is only useful if QT_QWS_SIMPAD is NOT defined. E.g. SIMpad has 800x600 but has // a (physically) large enough display to use the small icons #ifndef QT_QWS_SIMPAD if ( QPEApplication::desktop() ->width() >= 600 && ( mw->inherits("QMainWindow") || mw->isA("QMainWindow") ) ) { ( ( QMainWindow* ) mw )->setUsesBigPixmaps( true ); } #endif if ( mw->layout() && mw->inherits("QDialog") ) { QPEApplication::showDialog((QDialog*)mw, nomaximize); } else { #ifdef Q_WS_QWS if ( !nomaximize ) mw->showMaximized(); else #endif mw->show(); } } static bool setWidgetCaptionFromAppName( QWidget* /*mw*/, const QString& /*appName*/, const QString& /*appsPath*/ ) { /* // This works but disable it for now until it is safe to apply // What is does is scan the .desktop files of all the apps for // the applnk that has the corresponding argv[0] as this program // then it uses the name stored in the .desktop file as the caption // for the main widget. This saves duplicating translations for // the app name in the program and in the .desktop files. AppLnkSet apps( appsPath ); QList<AppLnk> appsList = apps.children(); for ( QListIterator<AppLnk> it(appsList); it.current(); ++it ) { if ( (*it)->exec() == appName ) { mw->setCaption( (*it)->name() ); return TRUE; } } */ return FALSE; } void show(QWidget* mw, bool nomax) { setWidgetCaptionFromAppName( mw, appName, QPEApplication::qpeDir() + "apps" ); nomaximize = nomax; qpe_main_widget = mw; + qcopQok = TRUE; #ifndef QT_NO_COP sendQCopQ(); #endif if ( preloaded ) { if (forceshow) show_mx(mw, nomax); } else if ( keep_running ) { show_mx(mw, nomax); } } void loadTextCodecs() { QString path = QPEApplication::qpeDir() + "/plugins/textcodecs"; QDir dir( path, "lib*.so" ); QStringList list; if ( dir. exists ( )) list = dir.entryList(); QStringList::Iterator it; for ( it = list.begin(); it != list.end(); ++it ) { TextCodecInterface *iface = 0; QLibrary *lib = new QLibrary( path + "/" + *it ); if ( lib->queryInterface( IID_QtopiaTextCodec, (QUnknownInterface**)&iface ) == QS_OK && iface ) { QValueList<int> mibs = iface->mibEnums(); for (QValueList<int>::ConstIterator i = mibs.begin(); i != mibs.end(); ++i) { (void)iface->createForMib(*i); // ### it exists now; need to remember if we can delete it } } else { lib->unload(); delete lib; } } } void loadImageCodecs() { QString path = QPEApplication::qpeDir() + "/plugins/imagecodecs"; QDir dir( path, "lib*.so" ); QStringList list; if ( dir. exists ( )) list = dir.entryList(); QStringList::Iterator it; for ( it = list.begin(); it != list.end(); ++it ) { ImageCodecInterface *iface = 0; QLibrary *lib = new QLibrary( path + "/" + *it ); if ( lib->queryInterface( IID_QtopiaImageCodec, (QUnknownInterface**)&iface ) == QS_OK && iface ) { QStringList formats = iface->keys(); for (QStringList::ConstIterator i = formats.begin(); i != formats.end(); ++i) { (void)iface->installIOHandler(*i); // ### it exists now; need to remember if we can delete it } } else { lib->unload(); delete lib; } } } }; @@ -515,128 +517,130 @@ void QPEApplication::processQCopFile() QString qcopfn("/tmp/qcop-msg-"); qcopfn += d->appName; // append command name QFile f(qcopfn); if ( f.open(IO_ReadWrite) ) { #ifndef Q_OS_WIN32 flock(f.handle(), LOCK_EX); #endif QDataStream ds(&f); QCString channel, message; QByteArray data; while(!ds.atEnd()) { ds >> channel >> message >> data; d->enqueueQCop(channel,message,data); } ::ftruncate(f.handle(), 0); #ifndef Q_OS_WIN32 f.flush(); flock(f.handle(), LOCK_UN); #endif } #endif } /*! \fn void QPEApplication::appMessage( const QCString& msg, const QByteArray& data ) This signal is emitted when a message is received on this application's QPE/Application/<i>appname</i> \link qcop.html QCop\endlink channel. The slot to which you connect this signal uses \a msg and \a data in the following way: \code void MyWidget::receive( const QCString& msg, const QByteArray& data ) { QDataStream stream( data, IO_ReadOnly ); if ( msg == "someMessage(int,int,int)" ) { int a,b,c; stream >> a >> b >> c; ... } else if ( msg == "otherMessage(QString)" ) { ... } } \endcode \sa qcop.html Note that messages received here may be processed by qpe application and emitted as signals, such as flush() and reload(). */ /*! Constructs a QPEApplication just as you would construct a QApplication, passing \a argc, \a argv, and \a t. For applications, \a t should be the default, GuiClient. Only the Qtopia server passes GuiServer. */ QPEApplication::QPEApplication( int & argc, char **argv, Type t ) : QApplication( hack(argc), argv, t ), pidChannel( 0 ) { + QPixmapCache::setCacheLimit(256); // sensible default for smaller devices. + d = new QPEApplicationData; d->loadTextCodecs(); d->loadImageCodecs(); int dw = desktop() ->width(); if ( dw < 200 ) { setFont( QFont( "vera", 8 ) ); AppLnk::setSmallIconSize( 10 ); AppLnk::setBigIconSize( 28 ); } #ifndef QT_QWS_SIMPAD else if ( dw > 600 ) { setFont( QFont( "vera", 16 ) ); AppLnk::setSmallIconSize( 24 ); AppLnk::setBigIconSize( 48 ); } #endif else if ( dw > 200 ) { setFont( QFont( "vera", 10 ) ); AppLnk::setSmallIconSize( 14 ); AppLnk::setBigIconSize( 32 ); } QMimeSourceFactory::setDefaultFactory( new ResourceMimeFactory ); connect( this, SIGNAL( lastWindowClosed() ), this, SLOT( hideOrQuit() ) ); sysChannel = new QCopChannel( "QPE/System", this ); connect( sysChannel, SIGNAL( received( const QCString &, const QByteArray & ) ), this, SLOT( systemMessage( const QCString &, const QByteArray & ) ) ); /* COde now in initapp */ #if 0 #if defined(Q_WS_QWS) && !defined(QT_NO_COP) QString qcopfn( "/tmp/qcop-msg-" ); qcopfn += QString( argv[ 0 ] ); // append command name QFile f( qcopfn ); if ( f.open( IO_ReadOnly ) ) { flock( f.handle(), LOCK_EX ); } QCString channel = QCString( argv[ 0 ] ); channel.replace( QRegExp( ".*/" ), "" ); d->appName = channel; channel = "QPE/Application/" + channel; pidChannel = new QCopChannel( channel, this ); connect( pidChannel, SIGNAL( received( const QCString &, const QByteArray & ) ), this, SLOT( pidMessage( const QCString &, const QByteArray & ) ) ); if ( f.isOpen() ) { d->keep_running = FALSE; QDataStream ds( &f ); QCString channel, message; QByteArray data; while ( !ds.atEnd() ) { ds >> channel >> message >> data; d->enqueueQCop( channel, message, data ); } @@ -1715,256 +1719,262 @@ void QPEApplication::shutdown() \internal */ void QPEApplication::restart() { // Implement in server's QPEApplication subclass } static QPtrDict<void>* stylusDict = 0; static void createDict() { if ( !stylusDict ) stylusDict = new QPtrDict<void>; } /*! Returns the current StylusMode for widget \a w. \sa setStylusOperation() StylusMode */ QPEApplication::StylusMode QPEApplication::stylusOperation( QWidget* w ) { if ( stylusDict ) return ( StylusMode ) ( int ) stylusDict->find( w ); return LeftOnly; } /*! \enum QPEApplication::StylusMode \value LeftOnly the stylus only generates LeftButton events (the default). \value RightOnHold the stylus generates RightButton events if the user uses the press-and-hold gesture. \sa setStylusOperation() stylusOperation() */ /*! Causes widget \a w to receive mouse events according to the stylus \a mode. \sa stylusOperation() StylusMode */ void QPEApplication::setStylusOperation( QWidget * w, StylusMode mode ) { createDict(); if ( mode == LeftOnly ) { stylusDict->remove ( w ); w->removeEventFilter( qApp ); } else { stylusDict->insert( w, ( void* ) mode ); connect( w, SIGNAL( destroyed() ), qApp, SLOT( removeSenderFromStylusDict() ) ); w->installEventFilter( qApp ); } } /*! \reimp */ bool QPEApplication::eventFilter( QObject *o, QEvent *e ) { + if ( !o->isWidgetType() ) + return FALSE; + if ( stylusDict && e->type() >= QEvent::MouseButtonPress && e->type() <= QEvent::MouseMove ) { QMouseEvent * me = ( QMouseEvent* ) e; StylusMode mode = (StylusMode)(int)stylusDict->find(o); switch (mode) { case RightOnHold: switch ( me->type() ) { case QEvent::MouseButtonPress: if ( me->button() == LeftButton ) { - d->presstimer = startTimer(500); // #### pref. + if (!d->presstimer ) + d->presstimer = startTimer(500); // #### pref. d->presswidget = (QWidget*)o; d->presspos = me->pos(); d->rightpressed = FALSE; } break; case QEvent::MouseMove: if (d->presstimer && (me->pos() - d->presspos).manhattanLength() > 8) { killTimer(d->presstimer); d->presstimer = 0; } break; case QEvent::MouseButtonRelease: if ( me->button() == LeftButton ) { if ( d->presstimer ) { killTimer(d->presstimer); d->presstimer = 0; } if ( d->rightpressed && d->presswidget ) { // Right released postEvent( d->presswidget, new QMouseEvent( QEvent::MouseButtonRelease, me->pos(), RightButton, LeftButton + RightButton ) ); // Left released, off-widget postEvent( d->presswidget, new QMouseEvent( QEvent::MouseMove, QPoint( -1, -1), LeftButton, LeftButton ) ); postEvent( d->presswidget, new QMouseEvent( QEvent::MouseButtonRelease, QPoint( -1, -1), LeftButton, LeftButton ) ); d->rightpressed = FALSE; return TRUE; // don't send the real Left release } } break; default: break; } break; default: ; } } else if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease ) { QKeyEvent *ke = (QKeyEvent *)e; if ( ke->key() == Key_Enter ) { if ( o->isA( "QRadioButton" ) || o->isA( "QCheckBox" ) ) { postEvent( o, new QKeyEvent( e->type(), Key_Space, ' ', ke->state(), " ", ke->isAutoRepeat(), ke->count() ) ); return TRUE; } } } return FALSE; } /*! \reimp */ void QPEApplication::timerEvent( QTimerEvent *e ) { if ( e->timerId() == d->presstimer && d->presswidget ) { // Right pressed postEvent( d->presswidget, new QMouseEvent( QEvent::MouseButtonPress, d->presspos, RightButton, LeftButton ) ); killTimer( d->presstimer ); d->presstimer = 0; d->rightpressed = TRUE; } } void QPEApplication::removeSenderFromStylusDict() { stylusDict->remove ( ( void* ) sender() ); if ( d->presswidget == sender() ) d->presswidget = 0; } /*! \internal */ bool QPEApplication::keyboardGrabbed() const { return d->kbgrabbed; } /*! Reverses the effect of grabKeyboard(). This is called automatically on program exit. */ void QPEApplication::ungrabKeyboard() { ((QPEApplication *) qApp )-> d-> kbgrabbed = false; } /*! Grabs the physical keyboard keys, e.g. the application's launching keys. Instead of launching applications when these keys are pressed the signals emitted are sent to this application instead. Some games programs take over the launch keys in this way to make interaction easier. \sa ungrabKeyboard() */ void QPEApplication::grabKeyboard() { ((QPEApplication *) qApp )-> d-> kbgrabbed = true; } /*! \reimp */ int QPEApplication::exec() { d->qcopQok = true; #ifndef QT_NO_COP d->sendQCopQ(); + if ( !d->keep_running ) + processEvents(); // we may have received QCop messages in the meantime. #endif if ( d->keep_running ) //|| d->qpe_main_widget && d->qpe_main_widget->isVisible() ) return QApplication::exec(); #ifndef QT_NO_COP { QCopEnvelope e( "QPE/System", "closing(QString)" ); e << d->appName; } #endif processEvents(); return 0; } /*! \internal External request for application to quit. Quits if possible without loosing state. */ void QPEApplication::tryQuit() { if ( activeModalWidget() || strcmp( argv() [ 0 ], "embeddedkonsole" ) == 0 ) return ; // Inside modal loop or konsole. Too hard to save state. #ifndef QT_NO_COP { QCopEnvelope e( "QPE/System", "closing(QString)" ); e << d->appName; } #endif processEvents(); quit(); } /*! \internal */ void QPEApplication::installTranslation( const QString& baseName ) { QTranslator* trans = new QTranslator(this); QString tfn = qpeDir() + "/i18n/"+baseName; if ( trans->load( tfn ) ) installTranslator( trans ); else delete trans; } /*! \internal User initiated quit. Makes the window 'Go Away'. If preloaded this means hiding the window. If not it means quitting the application. As this is user initiated we don't need to check state. */ void QPEApplication::hideOrQuit() { processEvents(); // If we are a preloaded application we don't actually quit, so emit // a System message indicating we're quasi-closing. if ( d->preloaded && d->qpe_main_widget ) #ifndef QT_NO_COP |