summaryrefslogtreecommitdiff
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--library/alarmserver.cpp23
-rw-r--r--library/global.cpp6
2 files changed, 17 insertions, 12 deletions
diff --git a/library/alarmserver.cpp b/library/alarmserver.cpp
index 2ea4025..a75fc7e 100644
--- a/library/alarmserver.cpp
+++ b/library/alarmserver.cpp
@@ -1,449 +1,452 @@
/**********************************************************************
** 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.
**
**********************************************************************/
#include <qdir.h>
#include <qfile.h>
#include <qmessagebox.h>
#include <qtextstream.h>
#include <qpe/qpeapplication.h>
#include "global.h"
#include "resource.h"
#include <qpe/qcopenvelope_qws.h>
#include "alarmserver.h"
#include <qpe/timeconversion.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#undef USE_ATD // not used anymore -- we run opie-alarm on suspend/resume
struct timerEventItem
{
time_t UTCtime;
QCString channel, message;
int data;
bool operator==( const timerEventItem &right ) const
{
return ( UTCtime == right.UTCtime
&& channel == right.channel
&& message == right.message
&& data == right.data );
}
};
class TimerReceiverObject : public QObject
{
public:
TimerReceiverObject()
{ }
~TimerReceiverObject()
{ }
void resetTimer();
void setTimerEventItem();
void deleteTimer();
protected:
void timerEvent( QTimerEvent *te );
#ifdef USE_ATD
private:
QString atfilename;
#endif
};
TimerReceiverObject *timerEventReceiver = NULL;
QList<timerEventItem> timerEventList;
timerEventItem *nearestTimerEvent = NULL;
// set the timer to go off on the next event in the list
void setNearestTimerEvent()
{
nearestTimerEvent = NULL;
QListIterator<timerEventItem> it( timerEventList );
if ( *it )
nearestTimerEvent = *it;
for ( ; *it; ++it )
if ( (*it)->UTCtime < nearestTimerEvent->UTCtime )
nearestTimerEvent = *it;
if (nearestTimerEvent)
timerEventReceiver->resetTimer();
else
timerEventReceiver->deleteTimer();
}
//store current state to file
//Simple implementation. Should run on a timer.
static void saveState()
{
QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" );
if ( timerEventList.isEmpty() ) {
unlink( savefilename );
return ;
}
QFile savefile(savefilename + ".new");
if ( savefile.open(IO_WriteOnly) ) {
QDataStream ds( &savefile );
//save
QListIterator<timerEventItem> it( timerEventList );
for ( ; *it; ++it ) {
ds << it.current()->UTCtime;
ds << it.current()->channel;
ds << it.current()->message;
ds << it.current()->data;
}
savefile.close();
unlink( savefilename );
QDir d;
d.rename(savefilename + ".new", savefilename);
}
}
/*!
Sets up the alarm server. Restoring to previous state (session management).
*/
void AlarmServer::initialize()
{
//read autosave file and put events in timerEventList
QString savefilename = Global::applicationFileName( "AlarmServer", "saveFile" );
QFile savefile(savefilename);
if ( savefile.open(IO_ReadOnly) ) {
QDataStream ds( &savefile );
while ( !ds.atEnd() ) {
timerEventItem *newTimerEventItem = new timerEventItem;
ds >> newTimerEventItem->UTCtime;
ds >> newTimerEventItem->channel;
ds >> newTimerEventItem->message;
ds >> newTimerEventItem->data;
timerEventList.append( newTimerEventItem );
}
savefile.close();
if (!timerEventReceiver)
timerEventReceiver = new TimerReceiverObject;
setNearestTimerEvent();
}
}
#ifdef USE_ATD
static const char* atdir = "/var/spool/at/";
static bool triggerAtd( bool writeHWClock = FALSE )
{
QFile trigger(QString(atdir) + "trigger");
if ( trigger.open(IO_WriteOnly | IO_Raw) ) {
if ( trigger.writeBlock("\n", 2) != 2 ) {
QMessageBox::critical( 0, QObject::tr( "Out of Space" ),
QObject::tr( "Unable to schedule alarm.\nFree some memory and try again." ) );
trigger.close();
QFile::remove
( trigger.name() );
return FALSE;
}
return TRUE;
}
return FALSE;
}
#else
static bool writeResumeAt ( time_t wakeup )
{
FILE *fp = ::fopen ( "/var/run/resumeat", "w" );
if ( fp ) {
::fprintf ( fp, "%d\n", (int) wakeup );
::fclose ( fp );
}
else
qWarning ( "Failed to write wakeup time to /var/run/resumeat" );
return ( fp );
}
#endif
void TimerReceiverObject::deleteTimer()
{
#ifdef USE_ATD
if ( !atfilename.isEmpty() ) {
unlink( atfilename );
atfilename = QString::null;
triggerAtd( FALSE );
}
#else
writeResumeAt ( 0 );
#endif
}
void TimerReceiverObject::resetTimer()
{
const int maxsecs = 2147000;
QDateTime nearest = TimeConversion::fromUTC(nearestTimerEvent->UTCtime);
QDateTime now = QDateTime::currentDateTime();
if ( nearest < now )
nearest = now;
int secs = TimeConversion::secsTo( now, nearest );
if ( secs > maxsecs ) {
// too far for millisecond timing
secs = maxsecs;
}
// System timer (needed so that we wake from deep sleep),
// from the Epoch in seconds.
//
int at_secs = TimeConversion::toUTC(nearest);
// qDebug("reset timer to %d seconds from Epoch",at_secs);
#ifdef USE_ATD
QString fn = atdir + QString::number(at_secs) + "."
+ QString::number(getpid());
if ( fn != atfilename ) {
QFile atfile(fn + ".new");
if ( atfile.open(IO_WriteOnly | IO_Raw) ) {
int total_written;
// just wake up and delete the at file
QString cmd = "#!/bin/sh\nrm " + fn;
total_written = atfile.writeBlock(cmd.latin1(), cmd.length());
if ( total_written != int(cmd.length()) ) {
QMessageBox::critical( 0, tr("Out of Space"),
tr("Unable to schedule alarm.\n"
"Please free up space and try again") );
atfile.close();
QFile::remove
( atfile.name() );
return ;
}
atfile.close();
unlink( atfilename );
QDir d;
d.rename(fn + ".new", fn);
chmod(fn.latin1(), 0755);
atfilename = fn;
triggerAtd( FALSE );
}
else {
qWarning("Cannot open atd file %s", fn.latin1());
}
}
#else
writeResumeAt ( at_secs );
#endif
// Qt timers (does the actual alarm)
// from now in milliseconds
//
qDebug("AlarmServer waiting %d seconds", secs);
startTimer( 1000 * secs + 500 );
}
void TimerReceiverObject::timerEvent( QTimerEvent * )
{
bool needSave = FALSE;
killTimers();
if (nearestTimerEvent) {
if ( nearestTimerEvent->UTCtime
<= TimeConversion::toUTC(QDateTime::currentDateTime()) ) {
#ifndef QT_NO_COP
QCopEnvelope e( nearestTimerEvent->channel,
nearestTimerEvent->message );
e << TimeConversion::fromUTC( nearestTimerEvent->UTCtime )
<< nearestTimerEvent->data;
#endif
timerEventList.remove( nearestTimerEvent );
needSave = TRUE;
}
setNearestTimerEvent();
}
else {
resetTimer();
}
if ( needSave )
saveState();
}
/*!
\class AlarmServer alarmserver.h
\brief The AlarmServer class allows alarms to be scheduled and unscheduled.
-
+
Applications can schedule alarms with addAlarm() and can
unschedule alarms with deleteAlarm(). When the time for an alarm
to go off is reached the specified \link qcop.html QCop\endlink
message is sent on the specified channel (optionally with
additional data).
-
+
Scheduling an alarm using this class is important (rather just using
a QTimer) since the machine may be asleep and needs to get woken up using
the Linux kernel which implements this at the kernel level to minimize
battery usage while asleep.
-
+
\ingroup qtopiaemb
\sa QCopEnvelope
*/
/*!
Schedules an alarm to go off at (or soon after) time \a when. When
the alarm goes off, the \link qcop.html QCop\endlink \a message will
be sent to \a channel, with \a data as a parameter.
-
+
If this function is called with exactly the same data as a previous
call the subsequent call is ignored, so there is only ever one alarm
with a given set of parameters.
-
+
\sa deleteAlarm()
*/
void AlarmServer::addAlarm ( QDateTime when, const QCString& channel,
const QCString& message, int data)
{
if ( qApp->type() == QApplication::GuiServer ) {
bool needSave = FALSE;
// Here we are the server so either it has been directly called from
// within the server or it has been sent to us from a client via QCop
if (!timerEventReceiver)
timerEventReceiver = new TimerReceiverObject;
timerEventItem *newTimerEventItem = new timerEventItem;
newTimerEventItem->UTCtime = TimeConversion::toUTC( when );
newTimerEventItem->channel = channel;
newTimerEventItem->message = message;
newTimerEventItem->data = data;
// explore the case of already having the event in here...
QListIterator<timerEventItem> it( timerEventList );
for ( ; *it; ++it )
if ( *(*it) == *newTimerEventItem )
return ;
// if we made it here, it is okay to add the item...
timerEventList.append( newTimerEventItem );
needSave = TRUE;
// quicker than using setNearestTimerEvent()
if ( nearestTimerEvent ) {
if (newTimerEventItem->UTCtime < nearestTimerEvent->UTCtime) {
nearestTimerEvent = newTimerEventItem;
timerEventReceiver->killTimers();
timerEventReceiver->resetTimer();
}
}
else {
nearestTimerEvent = newTimerEventItem;
timerEventReceiver->resetTimer();
}
if ( needSave )
saveState();
}
else {
#ifndef QT_NO_COP
QCopEnvelope e( "QPE/System", "addAlarm(QDateTime,QCString,QCString,int)" );
e << when << channel << message << data;
#endif
}
}
/*!
Deletes previously scheduled alarms which match \a when, \a channel,
\a message, and \a data.
-
+
Passing null values for \a when, \a channel, or for the \link
qcop.html QCop\endlink \a message, acts as a wildcard meaning "any".
Similarly, passing -1 for \a data indicates "any".
-
+
If there is no matching alarm, nothing happens.
-
+
\sa addAlarm()
-
+
*/
void AlarmServer::deleteAlarm (QDateTime when, const QCString& channel, const QCString& message, int data)
{
if ( qApp->type() == QApplication::GuiServer) {
bool needSave = FALSE;
if ( timerEventReceiver != NULL ) {
timerEventReceiver->killTimers();
// iterate over the list of events
QListIterator<timerEventItem> it( timerEventList );
time_t deleteTime = TimeConversion::toUTC( when );
for ( ; *it; ++it ) {
// if its a match, delete it
if ( ( (*it)->UTCtime == deleteTime || when.isNull() )
&& ( channel.isNull() || (*it)->channel == channel )
&& ( message.isNull() || (*it)->message == message )
&& ( data == -1 || (*it)->data == data ) ) {
// if it's first, then we need to update the timer
if ( (*it) == nearestTimerEvent ) {
timerEventList.remove(*it);
setNearestTimerEvent();
}
else {
timerEventList.remove(*it);
}
needSave = TRUE;
}
}
if ( nearestTimerEvent )
timerEventReceiver->resetTimer();
}
if ( needSave )
saveState();
}
else {
#ifndef QT_NO_COP
QCopEnvelope e( "QPE/System", "deleteAlarm(QDateTime,QCString,QCString,int)" );
e << when << channel << message << data;
#endif
}
}
/*!
- Writes the system clock to the hardware clock.
+ The implementation depends on the mode of AlarmServer. If the AlarmServer
+ uses atd the current system time will be written to the hardware clock.
+ If the AlarmServer relies on opie-alarm the time will be written once the
+ device gets suspended. opie-alarm is used by the Zaurus, iPAQs and SIMpad
*/
void Global::writeHWClock()
{
#ifdef USE_ATD
if ( !triggerAtd( TRUE ) ) {
// atd not running? set it ourselves
system("/sbin/hwclock --systohc"); // ##### UTC?
}
#else
// hwclock is written on suspend
#endif
}
diff --git a/library/global.cpp b/library/global.cpp
index 5c89430..90954fe 100644
--- a/library/global.cpp
+++ b/library/global.cpp
@@ -1,729 +1,731 @@
/**********************************************************************
** 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 <qpe/qpedebug.h>
#include <qpe/global.h>
#include <qpe/qdawg.h>
#include <qpe/qpeapplication.h>
#include <qpe/resource.h>
#include <qpe/storage.h>
#include <qpe/applnk.h>
#include <qpe/qcopenvelope_qws.h>
#include <qfile.h>
#include <qlabel.h>
#include <qtimer.h>
#include <qmap.h>
#include <qdict.h>
#include <qdir.h>
#include <qmessagebox.h>
#include <qregexp.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <qwindowsystem_qws.h> // for qwsServer
#include <qdatetime.h>
#include <qfile.h>
namespace {
// checks if the storage should be searched
bool checkStorage(const QString &path ){ // this is a small Config replacement cause config is too limited -zecke
QFile file(path );
if(!file.open(IO_ReadOnly ) )
return true;
QByteArray array = file.readAll();
QStringList list = QStringList::split('\n', QString( array ) );
for(QStringList::Iterator it = list.begin(); it != list.end(); ++it ){
if( (*it).startsWith("autocheck = 0" ) ){
return false;
}else if( (*it).startsWith("autocheck = 1" ) ){
return true;
}
}
return true;
}
}
//#include "quickexec_p.h"
class Emitter : public QObject {
Q_OBJECT
public:
Emitter( QWidget* receiver, const QString& document )
{
connect(this, SIGNAL(setDocument(const QString&)),
receiver, SLOT(setDocument(const QString&)));
emit setDocument(document);
disconnect(this, SIGNAL(setDocument(const QString&)),
receiver, SLOT(setDocument(const QString&)));
}
signals:
void setDocument(const QString&);
};
class StartingAppList : public QObject {
Q_OBJECT
public:
static void add( const QString& name );
static bool isStarting( const QString name );
private slots:
void handleNewChannel( const QString &);
private:
StartingAppList( QObject *parent=0, const char* name=0 ) ;
QDict<QTime> dict;
static StartingAppList *appl;
};
StartingAppList* StartingAppList::appl = 0;
StartingAppList::StartingAppList( QObject *parent, const char* name )
:QObject( parent, name )
{
#if QT_VERSION >= 232 && defined(QWS)
connect( qwsServer, SIGNAL( newChannel(const QString&)),
this, SLOT( handleNewChannel(const QString&)) );
#endif
dict.setAutoDelete( TRUE );
}
void StartingAppList::add( const QString& name )
{
#if QT_VERSION >= 232 && !defined(QT_NO_COP)
if ( !appl )
appl = new StartingAppList;
QTime *t = new QTime;
t->start();
appl->dict.insert( "QPE/Application/" + name, t );
#endif
}
bool StartingAppList::isStarting( const QString name )
{
#if QT_VERSION >= 232 && !defined(QT_NO_COP)
if ( appl ) {
QTime *t = appl->dict.find( "QPE/Application/" + name );
if ( !t )
return FALSE;
if ( t->elapsed() > 10000 ) {
// timeout in case of crash or something
appl->dict.remove( "QPE/Application/" + name );
return FALSE;
}
return TRUE;
}
#endif
return FALSE;
}
void StartingAppList::handleNewChannel( const QString & name )
{
#if QT_VERSION >= 232 && !defined(QT_NO_COP)
dict.remove( name );
#endif
}
static bool docDirCreated = FALSE;
static QDawg* fixed_dawg = 0;
static QDict<QDawg> *named_dawg = 0;
static QString qpeDir()
{
QString dir = getenv("OPIEDIR");
if ( dir.isEmpty() ) dir = "..";
return dir;
}
static QString dictDir()
{
return qpeDir() + "/etc/dict";
}
/*!
\class Global global.h
\brief The Global class provides application-wide global functions.
The Global functions are grouped as follows:
\tableofcontents
\section1 User Interface
The statusMessage() function provides short-duration messages to the
user. The showInputMethod() function shows the current input method,
and hideInputMethod() hides the input method.
\section1 Document related
The findDocuments() function creates a set of \link doclnk.html
DocLnk\endlink objects in a particular folder.
\section1 Filesystem related
Global provides an applicationFileName() function that returns the
full path of an application-specific file.
The execute() function runs an application.
\section1 Word list related
A list of words relevant to the current locale is maintained by the
system. The list is held in a \link qdawg.html DAWG\endlink
(implemented by the QDawg class). This list is used, for example, by
the pickboard input method.
The global QDawg is returned by fixedDawg(); this cannot be updated.
An updatable copy of the global QDawg is returned by addedDawg().
Applications may have their own word lists stored in \l{QDawg}s
which are returned by dawg(). Use addWords() to add words to the
updateable copy of the global QDawg or to named application
\l{QDawg}s.
\section1 Quoting
The shellQuote() function quotes a string suitable for passing to a
shell. The stringQuote() function backslash escapes '\' and '"'
characters.
\section1 Hardware
- The writeHWClock() function sets the hardware clock to the system
- clock's date and time.
+ The implementation of the writeHWClock() function depends on the AlarmServer
+ implementation. If the AlarmServer is using atd the clock will be synced to
+ hardware. If opie-alarm is used the hardware clock will be synced before
+ suspending the device. opie-alarm is used by iPAQ and Zaurii implementation
\ingroup qtopiaemb
*/
/*!
\internal
*/
Global::Global()
{
}
/*!
Returns the unchangeable QDawg that contains general
words for the current locale.
\sa addedDawg()
*/
const QDawg& Global::fixedDawg()
{
if ( !fixed_dawg ) {
if ( !docDirCreated )
createDocDir();
fixed_dawg = new QDawg;
QString dawgfilename = dictDir() + "/dawg";
QString words_lang;
QStringList langs = Global::languageList();
for (QStringList::ConstIterator it = langs.begin(); it!=langs.end(); ++it) {
QString lang = *it;
words_lang = dictDir() + "/words." + lang;
QString dawgfilename_lang = dawgfilename + "." + lang;
if ( QFile::exists(dawgfilename_lang) ||
QFile::exists(words_lang) ) {
dawgfilename = dawgfilename_lang;
break;
}
}
QFile dawgfile(dawgfilename);
if ( !dawgfile.exists() ) {
QString fn = dictDir() + "/words";
if ( QFile::exists(words_lang) )
fn = words_lang;
QFile in(fn);
if ( in.open(IO_ReadOnly) ) {
fixed_dawg->createFromWords(&in);
dawgfile.open(IO_WriteOnly);
fixed_dawg->write(&dawgfile);
dawgfile.close();
}
} else {
fixed_dawg->readFile(dawgfilename);
}
}
return *fixed_dawg;
}
/*!
Returns the changeable QDawg that contains general
words for the current locale.
\sa fixedDawg()
*/
const QDawg& Global::addedDawg()
{
return dawg("local");
}
/*!
Returns the QDawg with the given \a name.
This is an application-specific word list.
\a name should not contain "/".
*/
const QDawg& Global::dawg(const QString& name)
{
createDocDir();
if ( !named_dawg )
named_dawg = new QDict<QDawg>;
QDawg* r = named_dawg->find(name);
if ( !r ) {
r = new QDawg;
named_dawg->insert(name,r);
QString dawgfilename = applicationFileName("Dictionary", name ) + ".dawg";
QFile dawgfile(dawgfilename);
if ( dawgfile.open(IO_ReadOnly) )
r->readFile(dawgfilename);
}
return *r;
}
/*!
\overload
Adds \a wordlist to the addedDawg().
Note that the addition of words persists between program executions
(they are saved in the dictionary files), so you should confirm the
words with the user before adding them.
*/
void Global::addWords(const QStringList& wordlist)
{
addWords("local",wordlist);
}
/*!
\overload
Adds \a wordlist to the addedDawg().
Note that the addition of words persists between program executions
(they are saved in the dictionary files), so you should confirm the
words with the user before adding them.
*/
void Global::addWords(const QString& dictname, const QStringList& wordlist)
{
QDawg& d = (QDawg&)dawg(dictname);
QStringList all = d.allWords() + wordlist;
d.createFromWords(all);
QString dawgfilename = applicationFileName("Dictionary", dictname) + ".dawg";
QFile dawgfile(dawgfilename);
if ( dawgfile.open(IO_WriteOnly) ) {
d.write(&dawgfile);
dawgfile.close();
}
// #### Re-read the dawg here if we use mmap().
// #### Signal other processes to re-read.
}
/*!
Returns the full path for the application called \a appname, with the
given \a filename. Returns QString::null if there was a problem creating
the directory tree for \a appname.
If \a filename contains "/", it is the caller's responsibility to
ensure that those directories exist.
*/
QString Global::applicationFileName(const QString& appname, const QString& filename)
{
QDir d;
QString r = getenv("HOME");
r += "/Applications/";
if ( !QFile::exists( r ) )
if ( d.mkdir(r) == false )
return QString::null;
r += appname;
if ( !QFile::exists( r ) )
if ( d.mkdir(r) == false )
return QString::null;
r += "/"; r += filename;
return r;
}
/*!
\internal
*/
void Global::createDocDir()
{
if ( !docDirCreated ) {
docDirCreated = TRUE;
mkdir( QPEApplication::documentDir().latin1(), 0755 );
}
}
/*!
Displays a status \a message to the user. This usually appears
in the taskbar for a short amount of time, then disappears.
*/
void Global::statusMessage(const QString& message)
{
#if !defined(QT_NO_COP)
QCopEnvelope e( "QPE/TaskBar", "message(QString)" );
e << message;
#endif
}
/*!
\internal
*/
void Global::applyStyle()
{
#if !defined(QT_NO_COP)
QCopChannel::send( "QPE/System", "applyStyle()" );
#else
((QPEApplication *)qApp)->applyStyle(); // apply without needing QCop for floppy version
#endif
}
/*!
\internal
*/
QWidget *Global::shutdown( bool )
{
#if !defined(QT_NO_COP)
QCopChannel::send( "QPE/System", "shutdown()" );
#endif
return 0;
}
/*!
\internal
*/
QWidget *Global::restart( bool )
{
#if !defined(QT_NO_COP)
QCopChannel::send( "QPE/System", "restart()" );
#endif
return 0;
}
/*!
Explicitly show the current input method.
Input methods are indicated in the taskbar by a small icon. If the
input method is activated (shown) then it takes up some proportion
of the bottom of the screen, to allow the user to interact (input
characters) with it.
\sa hideInputMethod()
*/
void Global::showInputMethod()
{
#if !defined(QT_NO_COP)
QCopChannel::send( "QPE/TaskBar", "showInputMethod()" );
#endif
}
/*!
Explicitly hide the current input method.
The current input method is still indicated in the taskbar, but no
longer takes up screen space, and can no longer be interacted with.
\sa showInputMethod()
*/
void Global::hideInputMethod()
{
#if !defined(QT_NO_COP)
QCopChannel::send( "QPE/TaskBar", "hideInputMethod()" );
#endif
}
/*!
\internal
*/
bool Global::isBuiltinCommand( const QString &name )
{
if(!builtin)
return FALSE; // yes, it can happen
for (int i = 0; builtin[i].file; i++) {
if ( builtin[i].file == name ) {
return TRUE;
}
}
return FALSE;
}
Global::Command* Global::builtin=0;
QGuardedPtr<QWidget> *Global::running=0;
/*!
\class Global::Command
\brief The Global::Command class is internal.
\internal
*/
/*!
\internal
*/
void Global::setBuiltinCommands( Command* list )
{
if ( running )
delete [] running;
builtin = list;
int count = 0;
if (!builtin)
return;
while ( builtin[count].file )
count++;
running = new QGuardedPtr<QWidget> [ count ];
}
/*!
\internal
*/
void Global::setDocument( QWidget* receiver, const QString& document )
{
Emitter emitter(receiver,document);
}
/*!
\internal
*/
bool Global::terminateBuiltin( const QString& n )
{
if (!builtin)
return FALSE;
for (int i = 0; builtin[i].file; i++) {
if ( builtin[i].file == n ) {
delete running[i];
return TRUE;
}
}
return FALSE;
}
/*!
\internal
*/
void Global::terminate( const AppLnk* app )
{
//if ( terminateBuiltin(app->exec()) ) return; // maybe? haven't tried this
#ifndef QT_NO_COP
QCString channel = "QPE/Application/" + app->exec().utf8();
if ( QCopChannel::isRegistered(channel) ) {
QCopEnvelope e(channel, "quit()");
}
#endif
}
/*!
Low-level function to run command \a c.
\warning Do not use this function. Use execute instead.
\sa execute()
*/
void Global::invoke(const QString &c)
{
// Convert the command line in to a list of arguments
QStringList list = QStringList::split(QRegExp(" *"),c);
#if !defined(QT_NO_COP)
QString ap=list[0];
// see if the application is already running
// XXX should lock file /tmp/qcop-msg-ap
if ( QCopChannel::isRegistered( ("QPE/Application/" + ap).latin1() ) ) {
// If the channel is already register, the app is already running, so show it.
{ QCopEnvelope env( ("QPE/Application/" + ap).latin1(), "raise()" ); }
//QCopEnvelope e("QPE/System", "notBusy(QString)" );
//e << ap;
return;
}
// XXX should unlock file /tmp/qcop-msg-ap
//see if it is being started
if ( StartingAppList::isStarting( ap ) ) {
// FIXME take it out for now, since it leads to a much to short showing of wait if
// some entry is clicked.
// Real cause is that ::execute is called twice for document tab. But it would need some larger changes
// to fix that, and with future syncs with qtopia 1.6 it will change anyway big time since somebody there
// had the idea that an apploader belongs to the launcher ...
//QCopEnvelope e("QPE/System", "notBusy(QString)" );
//e << ap;
return;
}
#endif
#ifdef QT_NO_QWS_MULTIPROCESS
QMessageBox::warning( 0, "Error", "Could not find the application " + c, "Ok", 0, 0, 0, 1 );
#else
QStrList slist;
unsigned int j;
for ( j = 0; j < list.count(); j++ )
slist.append( list[j].utf8() );
const char **args = new (const char *)[slist.count() + 1];
for ( j = 0; j < slist.count(); j++ )
args[j] = slist.at(j);
args[j] = NULL;
#if !defined(QT_NO_COP)
// an attempt to show a wait...
// more logic should be used, but this will be fine for the moment...
QCopEnvelope ( "QPE/System", "busy()" );
#endif
#ifdef HAVE_QUICKEXEC
QString libexe = qpeDir()+"/binlib/lib"+args[0] + ".so";
qDebug("libfile = %s", libexe.latin1() );
if ( QFile::exists( libexe ) ) {
qDebug("calling quickexec %s", libexe.latin1() );
quickexecv( libexe.utf8().data(), (const char **)args );
} else
#endif
{
bool success = false;
int pfd [2];
if ( ::pipe ( pfd ) < 0 )
pfd [0] = pfd [1] = -1;
pid_t pid = ::fork ( );
if ( pid == 0 ) { // child
for ( int fd = 3; fd < 100; fd++ ) {
if ( fd != pfd [1] )
::close ( fd );
}
::setpgid ( ::getpid ( ), ::getppid ( ));
// Closing of fd[1] indicates that the execvp succeeded!
if ( pfd [1] >= 0 )
::fcntl ( pfd [1], F_SETFD, FD_CLOEXEC );
// Try bindir first, so that foo/bar works too
::execv ( qpeDir ( ) + "/bin/" + args [0], (char * const *) args );
::execvp ( args [0], (char * const *) args );
char resultByte = 1;
if ( pfd [1] >= 0 )
::write ( pfd [1], &resultByte, 1 );
::_exit ( -1 );
}
else if ( pid > 0 ) {
success = true;
if ( pfd [1] >= 0 )
::close ( pfd [1] );
if ( pfd [0] >= 0 ) {
while ( true ) {
char resultByte;
int n = ::read ( pfd [0], &resultByte, 1 );
if ( n == 1 ) {
success = false;
break;
}
if (( n == -1 ) && (( errno == ECHILD ) || ( errno == EINTR )))
continue;
break; // success
}
::close ( pfd [0] );
}
}
if ( success )
StartingAppList::add( list[0] );
else
QMessageBox::warning( 0, "Error", "Could not start the application " + c, "Ok", 0, 0, 0, 1 );
}
#endif //QT_NO_QWS_MULTIPROCESS
}
/*!
Executes the application identfied by \a c, passing \a
document if it isn't null.
Note that a better approach might be to send a QCop message to the
application's QPE/Application/\e{appname} channel.
*/
void Global::execute( const QString &c, const QString& document )
{
// ask the server to do the work
#if !defined(QT_NO_COP)
if ( document.isNull() ) {
QCopEnvelope e( "QPE/System", "execute(QString)" );
e << c;
} else {
QCopEnvelope e( "QPE/System", "execute(QString,QString)" );
e << c << document;
}
#endif
return;
}
/*!
Returns the string \a s with the characters '\', '"', and '$' quoted
by a preceeding '\'.
\sa stringQuote()
*/
QString Global::shellQuote(const QString& s)
{
QString r="\"";
for (int i=0; i<(int)s.length(); i++) {
char c = s[i].latin1();
switch (c) {
case '\\': case '"': case '$':
r+="\\";
}
r += s[i];
}
r += "\"";
return r;
}
/*!
Returns the string \a s with the characters '\' and '"' quoted by a
preceeding '\'.
\sa shellQuote()
*/
QString Global::stringQuote(const QString& s)
{
QString r="\"";
for (int i=0; i<(int)s.length(); i++) {
char c = s[i].latin1();
switch (c) {
case '\\': case '"':
r+="\\";
}
r += s[i];
}