-rw-r--r-- | library/qpeapplication.cpp | 271 |
1 files changed, 240 insertions, 31 deletions
diff --git a/library/qpeapplication.cpp b/library/qpeapplication.cpp index 755fb19..90cd5f1 100644 --- a/library/qpeapplication.cpp +++ b/library/qpeapplication.cpp @@ -75,182 +75,387 @@ #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> #ifndef QT_NO_SOUND #include <sys/soundcard.h> #endif #include "qt_override_p.h" +class HackWidget : public QWidget +{ +public: + bool needsOk() + { return (getWState() & WState_Reserved1 ); } + + QRect normalGeometry() + { return topData()->normalGeometry; }; +}; class QPEApplicationData { public: QPEApplicationData ( ) : presstimer( 0 ), presswidget( 0 ), rightpressed( false ), kbgrabbed( false ), notbusysent( false ), preloaded( false ), forceshow( false ), nomaximize( 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 keep_running : 1; - bool qcopQok : 1; + bool qcopQok : 1; - QStringList langs; + 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 ) + + static void show_mx(QWidget* mw, bool nomaximize, QString &strName/* = QString::null */) { + if ( mw->isVisible() ) { + mw->raise(); + } else { + QPoint p; + QSize s; + + if ( mw->layout() && mw->inherits("QDialog") ) { + bool max; + if ( read_widget_rect(strName, max, p, s) && validate_widget_size(mw, p, s) ) { + mw->resize(s); + mw->move(p); + + if ( max && !nomaximize ) + mw->showMaximized(); + else + mw->show(); + } else { + qpe_show_dialog((QDialog*)mw,nomaximize); + } + } else { + bool max; + if ( read_widget_rect(strName, max, p, s) && validate_widget_size(mw, p, s) ) { + mw->resize(s); + mw->move(p); + } else { //no stored rectangle, make an estimation + int x = (qApp->desktop()->width()-mw->frameGeometry().width())/2; + int y = (qApp->desktop()->height()-mw->frameGeometry().height())/2; + mw->move( QMAX(x,0), QMAX(y,0) ); +#ifdef Q_WS_QWS + if ( !nomaximize ) + mw->showMaximized(); +#endif + } + if ( max && !nomaximize ) + mw->showMaximized(); + else + mw->show(); + } + } + } +// // 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 +// #if defined(OPIE_HIGH_RES_SMALL_PHY) +// 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 ) { +// qDebug("QDialog special case XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); +// mw->showMaximized(); +// // QPEApplication::showWidget( mw, !nomaximize ); +// } else +// #endif +// mw->show(); +// } +// } + + +static void qpe_show_dialog( QDialog* d, bool nomax ) +{ + QSize sh = d->sizeHint(); + int w = QMAX(sh.width(),d->width()); + int h = QMAX(sh.height(),d->height()); - // 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 -#if defined(OPIE_HIGH_RES_SMALL_PHY) - if ( QPEApplication::desktop() ->width() >= 600 && ( mw->inherits("QMainWindow") || mw->isA("QMainWindow") ) ) { - ( ( QMainWindow* ) mw )->setUsesBigPixmaps( true ); - } + if ( d->parentWidget() && !d->parentWidget()->topLevelWidget()->isMaximized() ) + nomax = TRUE; + +#ifndef Q_WS_QWS + QSize s(qApp->desktop()->width(), qApp->desktop()->height() ); +#else + QSize s(qt_maxWindowRect.width(), qt_maxWindowRect.height() ); #endif - if ( mw->layout() && mw->inherits("QDialog") ) { - QPEApplication::showDialog((QDialog*)mw, nomaximize); - } - else { -#ifdef Q_WS_QWS - if ( !nomaximize ) - mw->showMaximized(); - else + int maxX = s.width() - (d->frameGeometry().width() - d->geometry().width()); + int maxY = s.height() - (d->frameGeometry().height() - d->geometry().height()); + + if ( (w >= maxX && h >= maxY) || ( (!nomax) && ( w > s.width()*3/4 || h > s.height()*3/4 ) ) ) { + d->showMaximized(); + } else { + // try centering the dialog around its parent + QPoint p(0,0); + if ( d->parentWidget() ) { + QPoint pp = d->parentWidget()->mapToGlobal( QPoint(0,0) ); + p = QPoint( pp.x() + d->parentWidget()->width()/2, + pp.y() + d->parentWidget()->height()/ 2 ); + } else { + p = QPoint( maxX/2, maxY/2 ); + } + + p = QPoint( p.x() - w/2, p.y() - h/2 ); +// qDebug("p(x,y) is %d %d", p.x(), p.y() ); + + if ( w >= maxX ) { + if ( p.y() < 0 ) + p.setY(0); + if ( p.y() + h > maxY ) + p.setY( maxY - h); + + d->resize(maxX, h); + d->move(0, p.y() ); + } else if ( h >= maxY ) { + if ( p.x() < 0 ) + p.setX(0); + if ( p.x() + w > maxX ) + p.setX( maxX - w); + + d->resize(w, maxY); + d->move(p.x(),0); + } else { + d->resize(w, h); + } + + d->show(); + } +} + + static bool read_widget_rect(const QString &app, bool &maximized, QPoint &p, QSize &s) + { + maximized = TRUE; + + // 350 is the trigger in qwsdefaultdecoration for providing a resize button + if ( qApp->desktop()->width() <= 350 ) + return FALSE; + + Config cfg( "qpe" ); + cfg.setGroup("ApplicationPositions"); + QString str = cfg.readEntry( app, QString::null ); + QStringList l = QStringList::split(",", str); + + if ( l.count() == 5) { + p.setX( l[0].toInt() ); + p.setY( l[1].toInt() ); + + s.setWidth( l[2].toInt() ); + s.setHeight( l[3].toInt() ); + + maximized = l[4].toInt(); + + return TRUE; + } + + return FALSE; + } + + + static bool validate_widget_size(const QWidget *w, QPoint &p, QSize &s) + { +#ifndef Q_WS_QWS + QRect qt_maxWindowRect = qApp->desktop()->geometry(); #endif + int maxX = qt_maxWindowRect.width(); + int maxY = qt_maxWindowRect.height(); + int wWidth = s.width() + ( w->frameGeometry().width() - w->geometry().width() ); + int wHeight = s.height() + ( w->frameGeometry().height() - w->geometry().height() ); - mw->show(); - } + // total window size is not allowed to be larger than desktop window size + if ( ( wWidth >= maxX ) && ( wHeight >= maxY ) ) + return FALSE; + + if ( wWidth > maxX ) { + s.setWidth( maxX - (w->frameGeometry().width() - w->geometry().width() ) ); + wWidth = maxX; + } + + if ( wHeight > maxY ) { + s.setHeight( maxY - (w->frameGeometry().height() - w->geometry().height() ) ); + wHeight = maxY; } + + // any smaller than this and the maximize/close/help buttons will be overlapping + if ( wWidth < 80 || wHeight < 60 ) + return FALSE; + + if ( p.x() < 0 ) + p.setX(0); + if ( p.y() < 0 ) + p.setY(0); + + if ( p.x() + wWidth > maxX ) + p.setX( maxX - wWidth ); + if ( p.y() + wHeight > maxY ) + p.setY( maxY - wHeight ); + + return TRUE; + } + + static void store_widget_rect(QWidget *w, QString &app) + { + // 350 is the trigger in qwsdefaultdecoration for providing a resize button + if ( qApp->desktop()->width() <= 350 ) + return; + + // we use these to map the offset of geometry and pos. ( we can only use normalGeometry to + // get the non-maximized version, so we have to do it the hard way ) + int offsetX = w->x() - w->geometry().left(); + int offsetY = w->y() - w->geometry().top(); + + QRect r; + if ( w->isMaximized() ) + r = ( (HackWidget *) w)->normalGeometry(); + else + r = w->geometry(); + + // Stores the window placement as pos(), size() (due to the offset mapping) + Config cfg( "qpe" ); + cfg.setGroup("ApplicationPositions"); + QString s; + s.sprintf("%d,%d,%d,%d,%d", r.left() + offsetX, r.top() + offsetY, r.width(), r.height(), w->isMaximized() ); + cfg.writeEntry( app, s ); + } + 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); + show_mx(mw, nomax, appName); } else if ( keep_running ) { - show_mx(mw, nomax); + show_mx(mw, nomax, appName); } } void loadTextCodecs() { QString path = QPEApplication::qpeDir() + "/plugins/textcodecs"; #ifdef Q_OS_MACX QDir dir( path, "lib*.dylib" ); #else QDir dir( path, "lib*.so" ); #endif 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 } @@ -842,56 +1047,56 @@ public: { reject(); } }; void QPEApplication::mapToDefaultAction( QWSKeyEvent * ke, int key ) { // specialised actions for certain widgets. May want to // add more stuff here. if ( activePopupWidget() && activePopupWidget() ->inherits( "QListBox" ) && activePopupWidget() ->parentWidget() && activePopupWidget() ->parentWidget() ->inherits( "QComboBox" ) ) key = Qt::Key_Return; if ( activePopupWidget() && activePopupWidget() ->inherits( "QPopupMenu" ) ) key = Qt::Key_Return; #ifdef QWS ke->simpleData.keycode = key; #endif } -class HackWidget : public QWidget -{ -public: - bool needsOk() - { - return ( getWState() & WState_Reserved1 ); - } -}; +// class HackWidget : public QWidget +// { +// public: +// bool needsOk() +// { +// return ( getWState() & WState_Reserved1 ); +// } +// }; /*! \internal */ #ifdef QWS bool QPEApplication::qwsEventFilter( QWSEvent * e ) { if ( !d->notbusysent && e->type == QWSEvent::Focus ) { if ( qApp->type() != QApplication::GuiServer ) { QCopEnvelope e( "QPE/System", "notBusy(QString)" ); e << d->appName; } d->notbusysent = TRUE; } if ( type() == GuiServer ) { switch ( e->type ) { case QWSEvent::Mouse: if ( e->asMouse() ->simpleData.state && !QWidget::find( e->window() ) ) emit clientMoused(); break; default: break; } @@ -1957,73 +2162,77 @@ int QPEApplication::exec() 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 + if ( d->keep_running ) + d->store_widget_rect(d->qpe_main_widget, d->appName); 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() { + if ( d->keep_running ) + d->store_widget_rect(d->qpe_main_widget, d->appName); 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 { QCopEnvelope e("QPE/System", "fastAppHiding(QString)" ); e << d->appName; d->qpe_main_widget->hide(); } #endif else quit(); } #if (__GNUC__ > 2 ) extern "C" void __cxa_pure_virtual(); void __cxa_pure_virtual() { fprintf( stderr, "Pure virtual called\n"); abort(); |