summaryrefslogtreecommitdiff
path: root/core/launcher/server.cpp
Unidiff
Diffstat (limited to 'core/launcher/server.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r--core/launcher/server.cpp657
1 files changed, 657 insertions, 0 deletions
diff --git a/core/launcher/server.cpp b/core/launcher/server.cpp
new file mode 100644
index 0000000..08baa8e
--- a/dev/null
+++ b/core/launcher/server.cpp
@@ -0,0 +1,657 @@
1/**********************************************************************
2** Copyright (C) 2000-2002 Trolltech AS. All rights reserved.
3**
4** This file is part of the 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
21#include "server.h"
22#include "serverapp.h"
23#include "launcher.h"
24#include "startmenu.h"
25#include "transferserver.h"
26#include "qcopbridge.h"
27#include "irserver.h"
28#include "packageslave.h"
29#include "calibrate.h"
30#include "qrsync.h"
31#include "syncdialog.h"
32#include "launcher.h"
33#include "shutdownimpl.h"
34#include "applauncher.h"
35#include "suspendmonitor.h"
36#include "documentlist.h"
37
38#include <qtopia/applnk.h>
39#include <qtopia/categories.h>
40#include <qtopia/mimetype.h>
41#include <qtopia/config.h>
42#include <qtopia/services.h>
43#include <qtopia/devicebuttonmanager.h>
44#include <qtopia/pluginloader.h>
45#include <qtopia/resource.h>
46#include <qtopia/version.h>
47#include <qtopia/storage.h>
48
49#ifdef Q_WS_QWS
50#include <qtopia/qcopenvelope_qws.h>
51#include <qwindowsystem_qws.h>
52#include <qgfx_qws.h>
53#endif
54#include <qtopia/global.h>
55#include <qtopia/custom.h>
56
57#ifdef Q_OS_WIN32
58#include <io.h>
59#include <process.h>
60#else
61#include <unistd.h>
62#endif
63#include <qmainwindow.h>
64#include <qmessagebox.h>
65#include <qtimer.h>
66#include <qtextstream.h>
67
68#include <stdlib.h>
69
70extern QRect qt_maxWindowRect;
71
72static QWidget *calibrate(bool)
73{
74#ifdef Q_WS_QWS
75 Calibrate *c = new Calibrate;
76 c->show();
77 return c;
78#else
79 return 0;
80#endif
81}
82
83#define FACTORY(T) \
84 static QWidget *new##T( bool maximized ) { \
85 QWidget *w = new T( 0, 0, QWidget::WDestructiveClose | QWidget::WGroupLeader ); \
86 if ( maximized ) { \
87 if ( qApp->desktop()->width() <= 350 ) { \
88 w->showMaximized(); \
89 } else { \
90 w->resize( QSize( 300, 300 ) ); \
91 } \
92 } \
93 w->show(); \
94 return w; \
95 }
96
97
98#ifdef SINGLE_APP
99#define APP(a,b,c,d) FACTORY(b)
100#include "apps.h"
101#undef APP
102#endif // SINGLE_APP
103
104static Global::Command builtins[] = {
105
106#ifdef SINGLE_APP
107#define APP(a,b,c,d) { a, new##b, c, d },
108#include "apps.h"
109#undef APP
110#endif
111
112#if defined(QPE_NEED_CALIBRATION)
113 { "calibrate", calibrate,1, 0 }, // No tr
114#endif
115#if !defined(QT_QWS_CASSIOPEIA)
116 { "shutdown", Global::shutdown, 1, 0 }, // No tr
117 // { "run", run, 1, 0 }, // No tr
118#endif
119
120 { 0, calibrate,0, 0 },
121};
122
123
124//---------------------------------------------------------------------------
125
126
127//===========================================================================
128
129Server::Server() :
130 QWidget( 0, 0, WStyle_Tool | WStyle_Customize ),
131 qcopBridge( 0 ),
132 transferServer( 0 ),
133 packageHandler( 0 ),
134 syncDialog( 0 )
135{
136 Global::setBuiltinCommands(builtins);
137
138 tid_xfer = 0;
139 tid_today = startTimer(3600*2*1000);
140 last_today_show = QDate::currentDate();
141
142 tsmMonitor = new TempScreenSaverMonitor();
143 connect( tsmMonitor, SIGNAL(forceSuspend()), qApp, SIGNAL(power()) );
144
145 serverGui = new Launcher;
146 serverGui->createGUI();
147
148 docList = new DocumentList( serverGui );
149 appLauncher = new AppLauncher(this);
150 connect(appLauncher, SIGNAL(launched(int, const QString &)), this, SLOT(applicationLaunched(int, const QString &)) );
151 connect(appLauncher, SIGNAL(terminated(int, const QString &)), this, SLOT(applicationTerminated(int, const QString &)) );
152 connect(appLauncher, SIGNAL(connected(const QString &)), this, SLOT(applicationConnected(const QString &)) );
153
154 storage = new StorageInfo( this );
155 connect( storage, SIGNAL(disksChanged()), this, SLOT(storageChanged()) );
156
157 // start services
158 startTransferServer();
159 (void) new IrServer( this );
160
161 packageHandler = new PackageHandler( this );
162 connect(qApp, SIGNAL(activate(const DeviceButton*,bool)),this,SLOT(activate(const DeviceButton*,bool)));
163
164 setGeometry( -10, -10, 9, 9 );
165
166 QCopChannel *channel = new QCopChannel("QPE/System", this);
167 connect(channel, SIGNAL(received(const QCString &, const QByteArray &)),
168 this, SLOT(systemMsg(const QCString &, const QByteArray &)) );
169
170 QCopChannel *tbChannel = new QCopChannel( "QPE/TaskBar", this );
171 connect( tbChannel, SIGNAL(received(const QCString&, const QByteArray&)),
172 this, SLOT(receiveTaskBar(const QCString&, const QByteArray&)) );
173
174 connect( qApp, SIGNAL(prepareForRestart()), this, SLOT(terminateServers()) );
175 connect( qApp, SIGNAL(timeChanged()), this, SLOT(pokeTimeMonitors()) );
176
177 preloadApps();
178}
179
180void Server::show()
181{
182 ServerApplication::login(TRUE);
183 QWidget::show();
184}
185
186Server::~Server()
187{
188 serverGui->destroyGUI();
189 delete docList;
190 delete qcopBridge;
191 delete transferServer;
192 delete serverGui;
193 delete tsmMonitor;
194}
195
196static bool hasVisibleWindow(const QString& clientname, bool partial)
197{
198#ifdef QWS
199 const QList<QWSWindow> &list = qwsServer->clientWindows();
200 QWSWindow* w;
201 for (QListIterator<QWSWindow> it(list); (w=it.current()); ++it) {
202 if ( w->client()->identity() == clientname ) {
203 if ( partial && !w->isFullyObscured() )
204 return TRUE;
205 if ( !partial && !w->isFullyObscured() && !w->isPartiallyObscured() ) {
206# if QT_VERSION < 0x030000
207 QRect mwr = qt_screen->mapToDevice(qt_maxWindowRect,
208 QSize(qt_screen->width(),qt_screen->height()) );
209# else
210 QRect mwr = qt_maxWindowRect;
211# endif
212 if ( mwr.contains(w->requested().boundingRect()) )
213 return TRUE;
214 }
215 }
216 }
217#endif
218 return FALSE;
219}
220
221void Server::activate(const DeviceButton* button, bool held)
222{
223 Global::terminateBuiltin("calibrate"); // No tr
224 ServiceRequest sr;
225 if ( held ) {
226 sr = button->heldAction();
227 } else {
228 sr = button->pressedAction();
229 }
230 // A button with no action defined, will return a null ServiceRequest. Don't attempt
231 // to send/do anything with this as it will crash
232 if ( !sr.isNull() ) {
233 QString app = sr.app();
234 bool vis = hasVisibleWindow(app, app != "qpe");
235 if ( sr.message() == "raise()" && vis ) {
236 sr.setMessage("nextView()");
237 } else {
238 // "back door"
239 sr << (int)vis;
240 }
241
242 sr.send();
243 }
244}
245
246
247#ifdef Q_WS_QWS
248
249
250typedef struct KeyOverride {
251 ushort scan_code;
252 QWSServer::KeyMap map;
253};
254
255
256static const KeyOverride jp109keys[] = {
257 { 0x03, { Qt::Key_2, '2' , 0x22 , 0xffff } },
258 { 0x07, { Qt::Key_6, '6' , '&' , 0xffff } },
259 { 0x08, { Qt::Key_7, '7' , '\'' , 0xffff } },
260 { 0x09, { Qt::Key_8, '8' , '(' , 0xffff } },
261 { 0x0a, { Qt::Key_9, '9' , ')' , 0xffff } },
262 { 0x0b, { Qt::Key_0, '0' , 0xffff , 0xffff } },
263 { 0x0c, { Qt::Key_Minus, '-' , '=' , 0xffff } },
264 { 0x0d, { Qt::Key_AsciiCircum,'^' , '~' , '^' - 64 } },
265 { 0x1a, { Qt::Key_At, '@' , '`' , 0xffff } },
266 { 0x1b, { Qt::Key_BraceLeft, '[' , '{' , '[' - 64 } },
267 { 0x27, { Qt::Key_Semicolon, ';' , '+' , 0xffff } },
268 { 0x28, { Qt::Key_Colon, ':' , '*' , 0xffff } },
269 { 0x29, { Qt::Key_Zenkaku_Hankaku, 0xffff , 0xffff , 0xffff } },
270 { 0x2b, { Qt::Key_BraceRight, ']' , '}' , ']'-64 } },
271 { 0x70, { Qt::Key_Hiragana_Katakana, 0xffff , 0xffff , 0xffff } },
272 { 0x73, { Qt::Key_Backslash, '\\' , '_' , 0xffff } },
273 { 0x79, { Qt::Key_Henkan, 0xffff , 0xffff , 0xffff } },
274 { 0x7b, { Qt::Key_Muhenkan, 0xffff , 0xffff , 0xffff } },
275 { 0x7d, { Qt::Key_yen, 0x00a5 , '|' , 0xffff } },
276 { 0x00, { 0, 0xffff , 0xffff , 0xffff } }
277};
278
279bool Server::setKeyboardLayout( const QString &kb )
280{
281 //quick demo version that can be extended
282
283 QIntDict<QWSServer::KeyMap> *om = 0;
284 if ( kb == "us101" ) { // No tr
285 om = 0;
286 } else if ( kb == "jp109" ) {
287 om = new QIntDict<QWSServer::KeyMap>(37);
288 const KeyOverride *k = jp109keys;
289 while ( k->scan_code ) {
290 om->insert( k->scan_code, &k->map );
291 k++;
292 }
293 }
294 QWSServer::setOverrideKeys( om );
295
296 return TRUE;
297}
298
299#endif
300
301void Server::systemMsg(const QCString &msg, const QByteArray &data)
302{
303 QDataStream stream( data, IO_ReadOnly );
304
305 if ( msg == "securityChanged()" ) {
306 if ( transferServer )
307 transferServer->authorizeConnections();
308 if ( qcopBridge )
309 qcopBridge->authorizeConnections();
310 } else if ( msg == "setTempScreenSaverMode(int,int)" ) {
311 int mode, pid;
312 stream >> mode >> pid;
313 tsmMonitor->setTempMode(mode, pid);
314 } else if ( msg == "linkChanged(QString)" ) {
315 QString link;
316 stream >> link;
317 qDebug( "desktop.cpp systemMsg -> linkchanged( %s )", link.latin1() );
318 docList->linkChanged(link);
319 } else if ( msg == "serviceChanged(QString)" ) {
320 MimeType::updateApplications();
321 } else if ( msg == "mkdir(QString)" ) {
322 QString dir;
323 stream >> dir;
324 if ( !dir.isEmpty() )
325 mkdir( dir );
326 } else if ( msg == "rdiffGenSig(QString,QString)" ) {
327 QString baseFile, sigFile;
328 stream >> baseFile >> sigFile;
329 QRsync::generateSignature( baseFile, sigFile );
330 } else if ( msg == "rdiffGenDiff(QString,QString,QString)" ) {
331 QString baseFile, sigFile, deltaFile;
332 stream >> baseFile >> sigFile >> deltaFile;
333 QRsync::generateDiff( baseFile, sigFile, deltaFile );
334 } else if ( msg == "rdiffApplyPatch(QString,QString)" ) {
335 QString baseFile, deltaFile;
336 stream >> baseFile >> deltaFile;
337 if ( !QFile::exists( baseFile ) ) {
338 QFile f( baseFile );
339 f.open( IO_WriteOnly );
340 f.close();
341 }
342 QRsync::applyDiff( baseFile, deltaFile );
343#ifndef QT_NO_COP
344 QCopEnvelope e( "QPE/Desktop", "patchApplied(QString)" );
345 e << baseFile;
346#endif
347 } else if ( msg == "rdiffCleanup()" ) {
348 mkdir( "/tmp/rdiff" );
349 QDir dir;
350 dir.setPath( "/tmp/rdiff" );
351 QStringList entries = dir.entryList();
352 for ( QStringList::Iterator it = entries.begin(); it != entries.end(); ++it )
353 dir.remove( *it );
354 } else if ( msg == "sendHandshakeInfo()" ) {
355 QString home = getenv( "HOME" );
356#ifndef QT_NO_COP
357 QCopEnvelope e( "QPE/Desktop", "handshakeInfo(QString,bool)" );
358 e << home;
359 int locked = (int) ServerApplication::screenLocked();
360 e << locked;
361#endif
362
363 } else if ( msg == "sendVersionInfo()" ) {
364 QCopEnvelope e( "QPE/Desktop", "versionInfo(QString,QString)" );
365 QString v = QPE_VERSION;
366 e << Global::version() << Global::architecture();
367 } else if ( msg == "sendCardInfo()" ) {
368#ifndef QT_NO_COP
369 QCopEnvelope e( "QPE/Desktop", "cardInfo(QString)" );
370#endif
371 storage->update();
372 const QList<FileSystem> &fs = storage->fileSystems();
373 QListIterator<FileSystem> it ( fs );
374 QString s;
375 QString homeDir = getenv("HOME");
376 QString homeFs, homeFsPath;
377 for ( ; it.current(); ++it ) {
378 int k4 = (*it)->blockSize()/256;
379 if ( (*it)->isRemovable() ) {
380 s += (*it)->name() + "=" + (*it)->path() + "/Documents " // No tr
381 + QString::number( (*it)->availBlocks() * k4/4 )
382 + "K " + (*it)->options() + ";";
383 } else if ( homeDir.contains( (*it)->path() ) &&
384 (*it)->path().length() > homeFsPath.length() ) {
385 homeFsPath = (*it)->path();
386 homeFs =
387 (*it)->name() + "=" + homeDir + "/Documents " // No tr
388 + QString::number( (*it)->availBlocks() * k4/4 )
389 + "K " + (*it)->options() + ";";
390 }
391 }
392 if ( !homeFs.isEmpty() )
393 s += homeFs;
394
395#ifndef QT_NO_COP
396 e << s;
397#endif
398 } else if ( msg == "sendSyncDate(QString)" ) {
399 QString app;
400 stream >> app;
401 Config cfg( "qpe" );
402 cfg.setGroup("SyncDate");
403#ifndef QT_NO_COP
404 QCopEnvelope e( "QPE/Desktop", "syncDate(QString,QString)" );
405 e << app << cfg.readEntry( app );
406#endif
407 //qDebug("QPE/System sendSyncDate for %s: response %s", app.latin1(),
408 //cfg.readEntry( app ).latin1() );
409 } else if ( msg == "setSyncDate(QString,QString)" ) {
410 QString app, date;
411 stream >> app >> date;
412 Config cfg( "qpe" );
413 cfg.setGroup("SyncDate");
414 cfg.writeEntry( app, date );
415 //qDebug("setSyncDate(QString,QString) %s %s", app.latin1(), date.latin1());
416 } else if ( msg == "startSync(QString)" ) {
417 QString what;
418 stream >> what;
419 delete syncDialog;
420 syncDialog = new SyncDialog( this, what );
421 syncDialog->show();
422 connect( syncDialog, SIGNAL(cancel()), SLOT(cancelSync()) );
423 } else if ( msg == "stopSync()") {
424 delete syncDialog;
425 syncDialog = 0;
426 } else if (msg == "restoreDone(QString)") {
427 docList->restoreDone();
428 } else if ( msg == "getAllDocLinks()" ) {
429 docList->sendAllDocLinks();
430 }
431#ifdef Q_WS_QWS
432 else if ( msg == "setMouseProto(QString)" ) {
433 QString mice;
434 stream >> mice;
435 setenv("QWS_MOUSE_PROTO",mice.latin1(),1);
436 qwsServer->openMouse();
437 } else if ( msg == "setKeyboard(QString)" ) {
438 QString kb;
439 stream >> kb;
440 setenv("QWS_KEYBOARD",kb.latin1(),1);
441 qwsServer->openKeyboard();
442
443 } else if ( msg == "setKeyboardAutoRepeat(int,int)" ) {
444 int delay, period;
445 stream >> delay >> period;
446 qwsSetKeyboardAutoRepeat( delay, period );
447 Config cfg( "qpe" );
448 cfg.setGroup("Keyboard");
449 cfg.writeEntry( "RepeatDelay", delay );
450 cfg.writeEntry( "RepeatPeriod", period );
451 } else if ( msg == "setKeyboardLayout(QString)" ) {
452 QString kb;
453 stream >> kb;
454 setKeyboardLayout( kb );
455 Config cfg( "qpe" );
456 cfg.setGroup("Keyboard");
457 cfg.writeEntry( "Layout", kb );
458 }
459#endif
460}
461
462void Server::receiveTaskBar(const QCString &msg, const QByteArray &data)
463{
464 QDataStream stream( data, IO_ReadOnly );
465
466 if ( msg == "reloadApps()" ) {
467 docList->reloadAppLnks();
468 } else if ( msg == "soundAlarm()" ) {
469 soundAlarm();
470 }
471#ifdef CUSTOM_LEDS
472 else if ( msg == "setLed(int,bool)" ) {
473 int led, status;
474 stream >> led >> status;
475 CUSTOM_LEDS( led, status );
476 }
477#endif
478}
479
480void Server::cancelSync()
481{
482#ifndef QT_NO_COP
483 QCopEnvelope e( "QPE/Desktop", "cancelSync()" );
484#endif
485 delete syncDialog;
486 syncDialog = 0;
487}
488
489bool Server::mkdir(const QString &localPath)
490{
491 QDir fullDir(localPath);
492 if (fullDir.exists())
493 return true;
494
495 // at this point the directory doesn't exist
496 // go through the directory tree and start creating the direcotories
497 // that don't exist; if we can't create the directories, return false
498
499 QString dirSeps = "/";
500 int dirIndex = localPath.find(dirSeps);
501 QString checkedPath;
502
503 // didn't find any seps; weird, use the cur dir instead
504 if (dirIndex == -1) {
505 //qDebug("No seperators found in path %s", localPath.latin1());
506 checkedPath = QDir::currentDirPath();
507 }
508
509 while (checkedPath != localPath) {
510 // no more seperators found, use the local path
511 if (dirIndex == -1)
512 checkedPath = localPath;
513 else {
514 // the next directory to check
515 checkedPath = localPath.left(dirIndex) + "/";
516 // advance the iterator; the next dir seperator
517 dirIndex = localPath.find(dirSeps, dirIndex+1);
518 }
519
520 QDir checkDir(checkedPath);
521 if (!checkDir.exists()) {
522 //qDebug("mkdir making dir %s", checkedPath.latin1());
523
524 if (!checkDir.mkdir(checkedPath)) {
525 qDebug("Unable to make directory %s", checkedPath.latin1());
526 return FALSE;
527 }
528 }
529
530 }
531 return TRUE;
532}
533
534void Server::styleChange( QStyle &s )
535{
536 QWidget::styleChange( s );
537}
538
539void Server::startTransferServer()
540{
541 if ( !qcopBridge ) {
542 // start qcop bridge server
543 qcopBridge = new QCopBridge( 4243 );
544 if ( qcopBridge->ok() ) {
545 // ... OK
546 connect( qcopBridge, SIGNAL(connectionClosed(const QHostAddress &)),
547 this, SLOT(syncConnectionClosed(const QHostAddress &)) );
548 } else {
549 delete qcopBridge;
550 qcopBridge = 0;
551 }
552 }
553 if ( !transferServer ) {
554 // start transfer server
555 transferServer = new TransferServer( 4242 );
556 if ( transferServer->ok() ) {
557 // ... OK
558 } else {
559 delete transferServer;
560 transferServer = 0;
561 }
562 }
563 if ( !transferServer || !qcopBridge )
564 tid_xfer = startTimer( 2000 );
565}
566
567void Server::timerEvent( QTimerEvent *e )
568{
569 if ( e->timerId() == tid_xfer ) {
570 killTimer( tid_xfer );
571 tid_xfer = 0;
572 startTransferServer();
573 } else if ( e->timerId() == tid_today ) {
574 QDate today = QDate::currentDate();
575 if ( today != last_today_show ) {
576 last_today_show = today;
577 Config cfg("today");
578 cfg.setGroup("Start");
579#ifndef QPE_DEFAULT_TODAY_MODE
580#define QPE_DEFAULT_TODAY_MODE "Never"
581#endif
582 if ( cfg.readEntry("Mode",QPE_DEFAULT_TODAY_MODE) == "Daily" ) {
583 QCopEnvelope env(Service::channel("today"),"raise()");
584 }
585 }
586 }
587}
588
589void Server::terminateServers()
590{
591 delete transferServer;
592 delete qcopBridge;
593 transferServer = 0;
594 qcopBridge = 0;
595}
596
597void Server::syncConnectionClosed( const QHostAddress & )
598{
599 qDebug( "Lost sync connection" );
600 delete syncDialog;
601 syncDialog = 0;
602}
603
604void Server::pokeTimeMonitors()
605{
606 // inform all TimeMonitors
607 QStrList tms = Service::channels("TimeMonitor");
608 for (const char* ch = tms.first(); ch; ch=tms.next()) {
609 QString t = getenv("TZ");
610 QCopEnvelope e(ch, "timeChange(QString)");
611 e << t;
612 }
613}
614
615void Server::applicationLaunched(int, const QString &app)
616{
617 serverGui->applicationStateChanged( app, ServerInterface::Launching );
618}
619
620void Server::applicationTerminated(int pid, const QString &app)
621{
622 serverGui->applicationStateChanged( app, ServerInterface::Terminated );
623 tsmMonitor->applicationTerminated( pid );
624}
625
626void Server::applicationConnected(const QString &app)
627{
628 serverGui->applicationStateChanged( app, ServerInterface::Running );
629}
630
631void Server::storageChanged()
632{
633 system( "qtopia-update-symlinks" );
634 serverGui->storageChanged( storage->fileSystems() );
635 docList->storageChanged();
636}
637
638
639void Server::soundAlarm()
640{
641#ifdef CUSTOM_SOUND_ALARM
642 CUSTOM_SOUND_ALARM;
643#endif
644}
645
646void Server::preloadApps()
647{
648 Config cfg("Launcher");
649 cfg.setGroup("Preload");
650 QStringList apps = cfg.readListEntry("Apps",',');
651 for (QStringList::ConstIterator it=apps.begin(); it!=apps.end(); ++it) {
652#ifndef QT_NO_COP
653 QCopEnvelope e("QPE/Application/"+(*it).local8Bit(), "enablePreload()");
654#endif
655 }
656}
657