summaryrefslogtreecommitdiff
path: root/library/qpeapplication.cpp
Side-by-side diff
Diffstat (limited to 'library/qpeapplication.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--library/qpeapplication.cpp5
1 files changed, 4 insertions, 1 deletions
diff --git a/library/qpeapplication.cpp b/library/qpeapplication.cpp
index 2bd7cbe..953f9d0 100644
--- a/library/qpeapplication.cpp
+++ b/library/qpeapplication.cpp
@@ -1,705 +1,708 @@
/**********************************************************************
** 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>
#ifndef Q_OS_MACX
#include <linux/limits.h> // needed for some toolchains (PATH_MAX)
#endif
#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 >= 0x030000
#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"
#include "fontdatabase.h"
#endif
#include "alarmserver.h"
#include "applnk.h"
#include "qpemenubar.h"
#include "textcodecinterface.h"
#include "imagecodecinterface.h"
#include <qtopia/qpeglobal.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#ifndef QT_NO_SOUND
#include <sys/soundcard.h>
#endif
#include <backend/rohfeedback.h>
static bool useBigPixmaps = 0;
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 ),
fontFamily( "Vera" ), fontSize( 10 ), smallIconSize( 14 ),
bigIconSize( 32 ), qpe_main_widget( 0 )
{
Config cfg( "qpe" );
cfg.setGroup( "Appearance" );
useBigPixmaps = cfg.readBoolEntry( "useBigPixmaps", false );
fontFamily = cfg.readEntry( "FontFamily", "Vera" );
fontSize = cfg.readNumEntry( "FontSize", 10 );
smallIconSize = cfg.readNumEntry( "SmallIconSize", 14 );
bigIconSize = cfg.readNumEntry( "BigIconSize", 32 );
#ifdef OPIE_WITHROHFEEDBACK
RoH = 0;
#endif
}
int presstimer;
QWidget* presswidget;
QPoint presspos;
#ifdef OPIE_WITHROHFEEDBACK
Opie::Internal::RoHFeedback *RoH;
#endif
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;
QCString fontFamily;
int fontSize;
int smallIconSize;
int bigIconSize;
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> 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, QString &strName) {
if ( mw->inherits("QMainWindow") || mw->isA("QMainWindow") )
{
( ( QMainWindow* ) mw )->setUsesBigPixmaps( useBigPixmaps );
}
QPoint p;
QSize s;
bool max;
if ( mw->isVisible() ) {
if ( read_widget_rect(strName, max, p, s) && validate_widget_size(mw, p, s) ) {
mw->resize(s);
mw->move(p);
}
mw->raise();
} else {
if ( mw->layout() && mw->inherits("QDialog") ) {
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 {
QPEApplication::showDialog((QDialog*)mw,nomaximize);
}
} else {
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();
}
}
}
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() );
// 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)
{
+ if( !w )
+ return;
+
// 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, appName);
}
else if ( keep_running ) {
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
}
}
else {
lib->unload();
delete lib;
}
}
}
void loadImageCodecs()
{
QString path = QPEApplication::qpeDir() + "plugins/imagecodecs";
#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 ) {
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;
}
}
}
};
class ResourceMimeFactory : public QMimeSourceFactory
{
public:
ResourceMimeFactory() : resImage( 0 )
{
setFilePath( Global::helpPath() );
setExtensionType( "html", "text/html;charset=UTF-8" );
}
~ResourceMimeFactory() {
delete resImage;
}
const QMimeSource* data( const QString& abs_name ) const
{
const QMimeSource * r = QMimeSourceFactory::data( abs_name );
if ( !r ) {
int sl = abs_name.length();
do {
sl = abs_name.findRev( '/', sl - 1 );
QString name = sl >= 0 ? abs_name.mid( sl + 1 ) : abs_name;
int dot = name.findRev( '.' );
if ( dot >= 0 )
name = name.left( dot );
QImage img = Resource::loadImage( name );
if ( !img.isNull() ) {
delete resImage;
resImage = new QImageDrag( img );
r = resImage;
}
}
while ( !r && sl > 0 );
}
return r;
}
private:
mutable QImageDrag *resImage;
};
static int& hack(int& i)
{
#if QT_VERSION <= 230 && defined(QT_NO_CODECS)
// These should be created, but aren't in Qt 2.3.0
(void)new QUtf8Codec;
(void)new QUtf16Codec;
#endif
return i;
}
static int muted = 0;
static int micMuted = 0;
static void setVolume( int t = 0, int percent = -1 )
{
switch ( t ) {
case 0: {
Config cfg( "qpe" );
cfg.setGroup( "Volume" );
if ( percent < 0 )
percent = cfg.readNumEntry( "VolumePercent", 50 );
#ifndef QT_NO_SOUND
int fd = 0;
#ifdef QT_QWS_DEVFS
if ( ( fd = open( "/dev/sound/mixer", O_RDWR ) ) >= 0 ) {
#else
if ( ( fd = open( "/dev/mixer", O_RDWR ) ) >= 0 ) {
#endif
int vol = muted ? 0 : percent;
// set both channels to same volume
vol |= vol << 8;
ioctl( fd, MIXER_WRITE( SOUND_MIXER_VOLUME ), &vol );
::close( fd );
}
#endif
}
break;
}
}
static void setMic( int t = 0, int percent = -1 )
{
switch ( t ) {
case 0: {
Config cfg( "qpe" );
cfg.setGroup( "Volume" );
if ( percent < 0 )
percent = cfg.readNumEntry( "Mic", 50 );
#ifndef QT_NO_SOUND
int fd = 0;
int mic = micMuted ? 0 : percent;
#ifdef QT_QWS_DEVFS
if ( ( fd = open( "/dev/sound/mixer", O_RDWR ) ) >= 0 ) {
#else
if ( ( fd = open( "/dev/mixer", O_RDWR ) ) >= 0 ) {
#endif
ioctl( fd, MIXER_WRITE( SOUND_MIXER_MIC ), &mic );
::close( fd );
}
#endif
}
break;
}
}
static void setBass( int t = 0, int percent = -1 )
{
switch ( t ) {
case 0: {
Config cfg( "qpe" );
cfg.setGroup( "Volume" );
if ( percent < 0 )
percent = cfg.readNumEntry( "BassPercent", 50 );
#ifndef QT_NO_SOUND
int fd = 0;
int bass = percent;
#ifdef QT_QWS_DEVFS
if ( ( fd = open( "/dev/sound/mixer", O_RDWR ) ) >= 0 ) {
#else
if ( ( fd = open( "/dev/mixer", O_RDWR ) ) >= 0 ) {
#endif
ioctl( fd, MIXER_WRITE( SOUND_MIXER_BASS ), &bass );
::close( fd );
}
#endif
}
break;
}
}
static void setTreble( int t = 0, int percent = -1 )
{
switch ( t ) {
case 0: {
Config cfg( "qpe" );
cfg.setGroup( "Volume" );
if ( percent < 0 )
percent = cfg.readNumEntry( "TreblePercent", 50 );
#ifndef QT_NO_SOUND
int fd = 0;
int treble = percent;
#ifdef QT_QWS_DEVFS
if ( ( fd = open( "/dev/sound/mixer", O_RDWR ) ) >= 0 ) {
#else
if ( ( fd = open( "/dev/mixer", O_RDWR ) ) >= 0 ) {
#endif
ioctl( fd, MIXER_WRITE( SOUND_MIXER_TREBLE ), &treble );
::close( fd );
}
#endif
}
break;
}
}
/**
\class QPEApplication
\brief The QPEApplication class implements various system services
that are available to all Qtopia applications.
Simply by using QPEApplication instead of QApplication, a standard Qt
application becomes a Qtopia application. It automatically follows
style changes, quits and raises, and in the
case of \link docwidget.html document-oriented\endlink applications,
changes the currently displayed document in response to the environment.
To create a \link docwidget.html document-oriented\endlink
application use showMainDocumentWidget(); to create a
non-document-oriented application use showMainWidget(). The
keepRunning() function indicates whether the application will
continue running after it's processed the last \link qcop.html
QCop\endlink message. This can be changed using setKeepRunning().
A variety of signals are emitted when certain events occur, for
example, timeChanged(), clockChanged(), weekChanged(),
dateFormatChanged() and volumeChanged(). If the application receives
a \link qcop.html QCop\endlink message on the application's
QPE/Application/\e{appname} channel, the appMessage() signal is
emitted. There are also flush() and reload() signals, which
are emitted when synching begins and ends respectively - upon these
signals, the application should save and reload any data
files that are involved in synching. Most of these signals will initially
be received and unfiltered through the appMessage() signal.
This class also provides a set of useful static functions. The
qpeDir() and documentDir() functions return the respective paths.
The grabKeyboard() and ungrabKeyboard() functions are used to
control whether the application takes control of the device's
physical buttons (e.g. application launch keys). The stylus' mode of
operation is set with setStylusOperation() and retrieved with
stylusOperation(). There are also setInputMethodHint() and
inputMethodHint() functions.
\ingroup qtopiaemb
*/
/*!
\fn void QPEApplication::clientMoused()
\internal
*/
/*!
\fn void QPEApplication::timeChanged();
This signal is emitted when the time changes outside the normal
passage of time, i.e. if the time is set backwards or forwards.
*/
/*!
\fn void QPEApplication::clockChanged( bool ampm );
This signal is emitted when the user changes the clock's style. If
\a ampm is TRUE, the user wants a 12-hour AM/PM clock, otherwise,
they want a 24-hour clock.
*/
/*!
\fn void QPEApplication::volumeChanged( bool muted )
This signal is emitted whenever the mute state is changed. If \a
muted is TRUE, then sound output has been muted.
*/
/*!
\fn void QPEApplication::weekChanged( bool startOnMonday )
This signal is emitted if the week start day is changed. If \a
startOnMonday is TRUE then the first day of the week is Monday; if
\a startOnMonday is FALSE then the first day of the week is
Sunday.
*/
/*!
\fn void QPEApplication::dateFormatChanged(DateFormat)
This signal is emitted whenever the date format is changed.
*/
/*!
\fn void QPEApplication::flush()
###
*/
/*!
\fn void QPEApplication::reload()
*/
void QPEApplication::processQCopFile()
{
QString qcopfn("/tmp/qcop-msg-");