summaryrefslogtreecommitdiff
path: root/library/global.cpp
Unidiff
Diffstat (limited to 'library/global.cpp') (more/less context) (show whitespace changes)
-rw-r--r--library/global.cpp644
1 files changed, 644 insertions, 0 deletions
diff --git a/library/global.cpp b/library/global.cpp
new file mode 100644
index 0000000..e1bbf3e
--- a/dev/null
+++ b/library/global.cpp
@@ -0,0 +1,644 @@
1/**********************************************************************
2** Copyright (C) 2000 Trolltech AS. All rights reserved.
3**
4** This file is part of Qtopia Environment.
5**
6** This file may be distributed and/or modified under the terms of the
7** GNU General Public License version 2 as published by the Free Software
8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file.
10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15**
16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you.
18**
19**********************************************************************/
20#include <qpe/qpedebug.h>
21#include <qpe/global.h>
22#include <qpe/qdawg.h>
23#include <qpe/qpeapplication.h>
24#include <qpe/resource.h>
25#include <qpe/storage.h>
26#include <qpe/applnk.h>
27#if defined(Q_WS_QWS) && !defined(QT_NO_COP)
28#include "qpe/qcopenvelope_qws.h"
29#endif
30
31#include <qfile.h>
32#include <qlabel.h>
33#include <qtimer.h>
34#include <qmap.h>
35#include <qdict.h>
36#include <qdir.h>
37#include <qmessagebox.h>
38#include <qregexp.h>
39
40#include <stdlib.h>
41#include <sys/stat.h>
42#include <sys/wait.h>
43#include <sys/types.h>
44#include <fcntl.h>
45#include <unistd.h>
46
47#include <qwindowsystem_qws.h> // for qwsServer
48#include <qdatetime.h>
49
50//#include "quickexec_p.h"
51
52class Emitter : public QObject {
53 Q_OBJECT
54public:
55 Emitter( QWidget* receiver, const QString& document )
56 {
57 connect(this, SIGNAL(setDocument(const QString&)),
58 receiver, SLOT(setDocument(const QString&)));
59 emit setDocument(document);
60 disconnect(this, SIGNAL(setDocument(const QString&)),
61 receiver, SLOT(setDocument(const QString&)));
62 }
63
64signals:
65 void setDocument(const QString&);
66};
67
68
69class StartingAppList : public QObject {
70 Q_OBJECT
71public:
72 static void add( const QString& name );
73 static bool isStarting( const QString name );
74private slots:
75 void handleNewChannel( const QString &);
76private:
77 StartingAppList( QObject *parent=0, const char* name=0 ) ;
78
79 QDict<QTime> dict;
80 static StartingAppList *appl;
81};
82
83StartingAppList* StartingAppList::appl = 0;
84
85StartingAppList::StartingAppList( QObject *parent, const char* name )
86 :QObject( parent, name )
87{
88#if QT_VERSION >= 232 && !defined(QT_NO_COP)
89 connect( qwsServer, SIGNAL( newChannel(const QString&)),
90 this, SLOT( handleNewChannel(const QString&)) );
91 dict.setAutoDelete( TRUE );
92#endif
93}
94
95void StartingAppList::add( const QString& name )
96{
97#if QT_VERSION >= 232 && !defined(QT_NO_COP)
98 if ( !appl )
99 appl = new StartingAppList;
100 QTime *t = new QTime;
101 t->start();
102 appl->dict.insert( "QPE/Application/" + name, t );
103#endif
104}
105
106bool StartingAppList::isStarting( const QString name )
107{
108#if QT_VERSION >= 232 && !defined(QT_NO_COP)
109 if ( appl ) {
110 QTime *t = appl->dict.find( "QPE/Application/" + name );
111 if ( !t )
112 return FALSE;
113 if ( t->elapsed() > 10000 ) {
114 // timeout in case of crash or something
115 appl->dict.remove( "QPE/Application/" + name );
116 return FALSE;
117 }
118 return TRUE;
119 }
120#endif
121 return FALSE;
122}
123
124void StartingAppList::handleNewChannel( const QString & name )
125{
126#if QT_VERSION >= 232 && !defined(QT_NO_COP)
127 dict.remove( name );
128#endif
129}
130
131static bool docDirCreated = FALSE;
132static QDawg* fixed_dawg = 0;
133static QDict<QDawg> *named_dawg = 0;
134
135static QString qpeDir()
136{
137 QString dir = getenv("QPEDIR");
138 if ( dir.isEmpty() ) dir = "..";
139 return dir;
140}
141
142static QString dictDir()
143{
144 return qpeDir() + "/etc/dict";
145}
146
147/*!
148 \class Global global.h
149 \brief The Global class collects application-wide global functions.
150*/
151
152/*!
153 \internal
154*/
155Global::Global()
156{
157}
158
159/*!
160 Returns the unchangeable QDawg that contains general
161 words for the current locale.
162
163 \sa addedDawg()
164*/
165const QDawg& Global::fixedDawg()
166{
167 if ( !fixed_dawg ) {
168 if ( !docDirCreated )
169 createDocDir();
170
171 fixed_dawg = new QDawg;
172 QString dawgfilename = dictDir() + "/dawg";
173 QString lang = getenv( "LANG" );
174 QString dawgfilename_lang = dawgfilename + "." + lang;
175 QString words_lang = dictDir() + "/words." + lang;
176 if ( QFile::exists(dawgfilename_lang) ||
177 QFile::exists(words_lang) )
178 dawgfilename = dawgfilename_lang;
179 QFile dawgfile(dawgfilename);
180
181 if ( !dawgfile.exists() ) {
182 QString fn = dictDir() + "/words";
183 if ( QFile::exists(words_lang) )
184 fn = words_lang;
185 QFile in(fn);
186 if ( in.open(IO_ReadOnly) ) {
187 fixed_dawg->createFromWords(&in);
188 dawgfile.open(IO_WriteOnly);
189 fixed_dawg->write(&dawgfile);
190 dawgfile.close();
191 }
192 } else {
193 fixed_dawg->readFile(dawgfilename);
194 }
195 }
196
197 return *fixed_dawg;
198}
199
200/*!
201 Returns the changeable QDawg that contains general
202 words for the current locale.
203
204 \sa fixedDawg()
205*/
206const QDawg& Global::addedDawg()
207{
208 return dawg("local");
209}
210
211/*!
212 Returns the QDawg with the given \a name.
213 This is an application-specific word list.
214
215 \a name should not contain "/".
216*/
217const QDawg& Global::dawg(const QString& name)
218{
219 createDocDir();
220 if ( !named_dawg )
221 named_dawg = new QDict<QDawg>;
222 QDawg* r = named_dawg->find(name);
223 if ( !r ) {
224 r = new QDawg;
225 named_dawg->insert(name,r);
226 QString dawgfilename = dictDir() + "/" + name + ".dawg";
227 QFile dawgfile(dawgfilename);
228 if ( dawgfile.open(IO_ReadOnly) )
229 r->readFile(dawgfilename);
230 }
231 return *r;
232}
233
234/*!
235 Adds \a wordlist to the addedDawg().
236*/
237void Global::addWords(const QStringList& wordlist)
238{
239 addWords("local",wordlist);
240}
241
242/*!
243 Adds \a wordlist to the dawg() named \a dictname.
244*/
245void Global::addWords(const QString& dictname, const QStringList& wordlist)
246{
247 QDawg& d = (QDawg&)dawg(dictname);
248 QStringList all = d.allWords() + wordlist;
249 d.createFromWords(all);
250
251 QString dawgfilename = dictDir() + "/" + dictname + ".dawg";
252 QFile dawgfile(dawgfilename);
253 if ( dawgfile.open(IO_WriteOnly) ) {
254 d.write(&dawgfile);
255 dawgfile.close();
256 }
257
258 // #### Re-read the dawg here if we use mmap().
259
260 // #### Signal other processes to re-read.
261}
262
263
264/*!
265 Returns a full path for the application named \a appname, with the
266 given \a filename or QString::null if there was a problem creating
267 the directory tree for \a appname.
268 If \a filename contains "/", it is the caller's responsibility to
269 ensure those directories exist.
270*/
271QString Global::applicationFileName(const QString& appname, const QString& filename)
272{
273 QDir d;
274 QString r = getenv("HOME");
275 r += "/Applications/";
276 if ( !QFile::exists( r ) )
277 if ( d.mkdir(r) == false )
278 return QString::null;
279 r += appname;
280 if ( !QFile::exists( r ) )
281 if ( d.mkdir(r) == false )
282 return QString::null;
283 r += "/"; r += filename;
284 return r;
285}
286
287/*!
288 \internal
289*/
290void Global::createDocDir()
291{
292 if ( !docDirCreated ) {
293 docDirCreated = TRUE;
294 mkdir( QPEApplication::documentDir().latin1(), 0755 );
295 }
296}
297
298
299/*!
300 Displays a status \a message to the user. This generally appears
301 in the taskbar for some amount of time, then disappears.
302*/
303void Global::statusMessage(const QString& message)
304{
305#if defined(Q_WS_QWS) && !defined(QT_NO_COP)
306 QCopEnvelope e( "QPE/TaskBar", "message(QString)" );
307 e << message;
308#endif
309}
310
311/*!
312 \internal
313*/
314void Global::applyStyle()
315{
316#if defined(Q_WS_QWS) && !defined(QT_NO_COP)
317 QCopChannel::send( "QPE/System", "applyStyle()" );
318#else
319 ((QPEApplication *)qApp)->applyStyle(); // apply without needing QCop for floppy version
320#endif
321}
322
323/*!
324 \internal
325*/
326QWidget *Global::shutdown( bool )
327{
328#if defined(Q_WS_QWS) && !defined(QT_NO_COP)
329 QCopChannel::send( "QPE/System", "shutdown()" );
330#endif
331 return 0;
332}
333
334/*!
335 \internal
336*/
337QWidget *Global::restart( bool )
338{
339#if defined(Q_WS_QWS) && !defined(QT_NO_COP)
340 QCopChannel::send( "QPE/System", "restart()" );
341#endif
342 return 0;
343}
344
345/*!
346 Explicitly show the current input method.
347*/
348void Global::showInputMethod()
349{
350#if defined(Q_WS_QWS) && !defined(QT_NO_COP)
351 QCopChannel::send( "QPE/TaskBar", "showInputMethod()" );
352#endif
353}
354
355/*!
356 Explicitly hide the current input method.
357*/
358void Global::hideInputMethod()
359{
360#if defined(Q_WS_QWS) && !defined(QT_NO_COP)
361 QCopChannel::send( "QPE/TaskBar", "hideInputMethod()" );
362#endif
363}
364
365
366/*!
367 \internal
368*/
369bool Global::isBuiltinCommand( const QString &name )
370{
371 if(!builtin)
372 return FALSE; // yes, it can happen
373 for (int i = 0; builtin[i].file; i++) {
374 if ( builtin[i].file == name ) {
375 return TRUE;
376 }
377 }
378 return FALSE;
379}
380
381Global::Command* Global::builtin=0;
382QGuardedPtr<QWidget> *Global::running=0;
383
384/*!
385 \class Global::Command
386 \brief The Global::Command class is internal.
387 \internal
388*/
389
390/*!
391 \internal
392*/
393void Global::setBuiltinCommands( Command* list )
394{
395 if ( running )
396 delete [] running;
397
398 builtin = list;
399 int count = 0;
400 if (!builtin)
401 return;
402 while ( builtin[count].file )
403 count++;
404
405 running = new QGuardedPtr<QWidget> [ count ];
406}
407
408/*!
409 \internal
410*/
411void Global::setDocument( QWidget* receiver, const QString& document )
412{
413 Emitter emitter(receiver,document);
414}
415
416/*!
417 \internal
418*/
419bool Global::terminateBuiltin( const QString& n )
420{
421 if (!builtin)
422 return FALSE;
423 for (int i = 0; builtin[i].file; i++) {
424 if ( builtin[i].file == n ) {
425 delete running[i];
426 return TRUE;
427 }
428 }
429 return FALSE;
430}
431
432/*!
433 \internal
434*/
435void Global::terminate( const AppLnk* app )
436{
437 //if ( terminateBuiltin(app->exec()) ) return; // maybe? haven't tried this
438
439 QCString channel = "QPE/Application/" + app->exec().utf8();
440 if ( QCopChannel::isRegistered(channel) ) {
441 QCopEnvelope e(channel, "quit()");
442 }
443}
444
445/*!
446 Low-level function to run command \a c. Not recommended.
447*/
448void Global::invoke(const QString &c)
449{
450 // Convert the command line in to a list of arguments
451 QStringList list = QStringList::split(QRegExp(" *"),c);
452
453#if defined(Q_WS_QWS) && !defined(QT_NO_COP)
454 QString ap=list[0];
455 // see if the application is already running
456 // XXX should lock file /tmp/qcop-msg-ap
457 if ( QCopChannel::isRegistered( ("QPE/Application/" + ap).latin1() ) ) {
458 QCopEnvelope e("QPE/System", "notBusy(QString)" );
459 e << ap;
460 return;
461 }
462 // XXX should unlock file /tmp/qcop-msg-ap
463 //see if it is being started
464 if ( StartingAppList::isStarting( ap ) ) {
465 QCopEnvelope e("QPE/System", "notBusy(QString)" );
466 e << ap;
467 return;
468 }
469
470#endif
471
472#ifdef QT_NO_QWS_MULTIPROCESS
473 QMessageBox::warning( 0, "Error", "Could not find the application " + c, "Ok", 0, 0, 0, 1 );
474#else
475
476 QStrList slist;
477 unsigned int j;
478 for ( j = 0; j < list.count(); j++ )
479 slist.append( list[j].utf8() );
480
481 const char **args = new (const char *)[slist.count() + 1];
482 for ( j = 0; j < slist.count(); j++ )
483 args[j] = slist.at(j);
484 args[j] = NULL;
485
486#if defined(Q_WS_QWS) && !defined(QT_NO_COP)
487 // an attempt to show a wait...
488 // more logic should be used, but this will be fine for the moment...
489 QCopEnvelope ( "QPE/System", "busy()" );
490#endif
491
492#ifdef HAVE_QUICKEXEC
493 QString libexe = qpeDir()+"/binlib/lib"+args[0] + ".so";
494 qDebug("libfile = %s", libexe.latin1() );
495 if ( QFile::exists( libexe ) ) {
496 qDebug("calling quickexec %s", libexe.latin1() );
497 quickexecv( libexe.utf8().data(), (const char **)args );
498 } else
499#endif
500 {
501 if ( !::vfork() ) {
502 for ( int fd = 3; fd < 100; fd++ )
503 ::close( fd );
504 ::setpgid( ::getpid(), ::getppid() );
505 // Try bindir first, so that foo/bar works too
506 ::execv( qpeDir()+"/bin/"+args[0], (char * const *)args );
507 ::execvp( args[0], (char * const *)args );
508 exit( -1 );
509 }
510 }
511 StartingAppList::add( list[0] );
512#endif //QT_NO_QWS_MULTIPROCESS
513}
514
515/*!
516 Executes application identfied by \a c, passing \a document.
517
518 Note that you might be better off sending a QCop message to
519 the application's QPE/Application/<i>appname</i> channel.
520*/
521void Global::execute( const QString &c, const QString& document )
522{
523 if ( qApp->type() != QApplication::GuiServer ) {
524 // ask the server to do the work
525#if defined(Q_WS_QWS) && !defined(QT_NO_COP)
526 if ( document.isNull() ) {
527 QCopEnvelope e( "QPE/System", "execute(QString)" );
528 e << c;
529 } else {
530 QCopEnvelope e( "QPE/System", "execute(QString,QString)" );
531 e << c << document;
532 }
533#endif
534 return;
535 }
536
537 // Attempt to execute the app using a builtin class for the app first
538 // else try and find it in the bin directory
539 if (builtin) {
540 for (int i = 0; builtin[i].file; i++) {
541 if ( builtin[i].file == c ) {
542 if ( running[i] ) {
543 if ( !document.isNull() && builtin[i].documentary )
544 setDocument(running[i], document);
545 running[i]->raise();
546 running[i]->show();
547 running[i]->setActiveWindow();
548 } else {
549 running[i] = builtin[i].func( builtin[i].maximized );
550 }
551 QCopEnvelope e("QPE/System", "notBusy(QString)" );
552 e << c; // that was quick ;-)
553 return;
554 }
555 }
556 }
557
558 //Global::invoke(c, document);
559
560 // Convert the command line in to a list of arguments
561 QStringList list = QStringList::split(QRegExp(" *"),c);
562
563#if defined(Q_WS_QWS) && !defined(QT_NO_COP)
564 QString ap=list[0];
565
566 qDebug("executing %s", ap.latin1() );
567 if ( ap == "suspend" ) {
568 QWSServer::sendKeyEvent( 0xffff, Qt::Key_F34, FALSE, TRUE, FALSE );
569 return;
570 }
571
572 /* if need be, sending a qcop message will result in an invoke, see
573 preceeding function */
574 { QCopEnvelope env( ("QPE/Application/" + ap).latin1(), "raise()" ); }
575 if ( !document.isEmpty() ) {
576 QCopEnvelope env( ("QPE/Application/" + ap).latin1(), "setDocument(QString)" );
577 env << document;
578 }
579#endif
580}
581
582/*!
583 Returns the string \a s with the characters backslash, ", and $
584 quoted by a preceeding backslash.
585*/
586QString Global::shellQuote(const QString& s)
587{
588 QString r="\"";
589 for (int i=0; i<(int)s.length(); i++) {
590 char c = s[i].latin1();
591 switch (c) {
592 case '\\': case '"': case '$':
593 r+="\\";
594 }
595 r += s[i];
596 }
597 r += "\"";
598 return r;
599}
600
601/*!
602 Returns the string \a s with the characters backslash and "
603 quoted by a preceeding backslash.
604*/
605QString Global::stringQuote(const QString& s)
606{
607 QString r="\"";
608 for (int i=0; i<(int)s.length(); i++) {
609 char c = s[i].latin1();
610 switch (c) {
611 case '\\': case '"':
612 r+="\\";
613 }
614 r += s[i];
615 }
616 r += "\"";
617 return r;
618}
619
620/*!
621 Finds all documents on the system's document directories which
622 match the filter \a mimefilter, and appends the resulting DocLnk
623 objects to \a folder.
624*/
625void Global::findDocuments(DocLnkSet* folder, const QString &mimefilter)
626{
627 QString homedocs = QString(getenv("HOME")) + "/Documents";
628 DocLnkSet d(homedocs,mimefilter);
629 folder->appendFrom(d);
630 StorageInfo storage;
631 const QList<FileSystem> &fs = storage.fileSystems();
632 QListIterator<FileSystem> it ( fs );
633 for ( ; it.current(); ++it ) {
634 if ( (*it)->isRemovable() ) {
635 QString path = (*it)->path();
636 DocLnkSet ide( path, mimefilter );
637 folder->appendFrom(ide);
638 }
639 }
640}
641
642
643
644#include "global.moc"