summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--core/launcher/serverapp.cpp626
-rw-r--r--core/launcher/serverapp.h73
2 files changed, 472 insertions, 227 deletions
diff --git a/core/launcher/serverapp.cpp b/core/launcher/serverapp.cpp
index 6edaa21..522ef07 100644
--- a/core/launcher/serverapp.cpp
+++ b/core/launcher/serverapp.cpp
@@ -7,113 +7,94 @@
7** GNU General Public License version 2 as published by the Free Software 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 8** Foundation and appearing in the file LICENSE.GPL included in the
9** packaging of this file. 9** packaging of this file.
10** 10**
11** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 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. 12** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
13** 13**
14** See http://www.trolltech.com/gpl/ for GPL licensing information. 14** See http://www.trolltech.com/gpl/ for GPL licensing information.
15** 15**
16** Contact info@trolltech.com if any conditions of this licensing are 16** Contact info@trolltech.com if any conditions of this licensing are
17** not clear to you. 17** not clear to you.
18** 18**
19**********************************************************************/ 19**********************************************************************/
20 20
21#include "serverapp.h" 21#include "serverapp.h"
22 22
23#include <opie/odevice.h>
24
23#include <qtopia/password.h> 25#include <qtopia/password.h>
24#include <qtopia/config.h> 26#include <qtopia/config.h>
25#include <qtopia/power.h> 27#include <qtopia/power.h>
26#include <qtopia/devicebuttonmanager.h>
27#include <qtopia/pluginloader.h>
28 28
29#ifdef Q_WS_QWS 29#ifdef Q_WS_QWS
30#include <qtopia/qcopenvelope_qws.h> 30#include <qtopia/qcopenvelope_qws.h>
31#endif 31#endif
32#include <qtopia/global.h> 32#include <qtopia/global.h>
33#include <qtopia/custom.h> 33#include <qtopia/custom.h>
34 34
35#ifdef Q_WS_QWS 35#ifdef Q_WS_QWS
36#include <qgfx_qws.h> 36#include <qgfx_qws.h>
37#endif 37#endif
38#ifdef Q_OS_WIN32 38#ifdef Q_OS_WIN32
39#include <io.h> 39#include <io.h>
40#include <process.h> 40#include <process.h>
41#else 41#else
42#include <unistd.h> 42#include <unistd.h>
43#endif 43#endif
44#include <qmessagebox.h> 44#include <qmessagebox.h>
45#include <qtimer.h> 45#include <qtimer.h>
46#include <qpainter.h> 46#include <qpainter.h>
47#include <qfile.h> 47#include <qfile.h>
48#include <qpixmapcache.h> 48#include <qpixmapcache.h>
49 49
50#include <stdlib.h> 50#include <stdlib.h>
51#include "screensaver.h"
51 52
52static ServerApplication *serverApp = 0; 53static ServerApplication *serverApp = 0;
53static int loggedin=0; 54static int loggedin=0;
54 55
56using namespace Opie;
55 57
58QCopKeyRegister::QCopKeyRegister()
59 : m_keyCode( 0 ) {
60}
56 61
57/* Apply light/power settings for current power source */ 62QCopKeyRegister::QCopKeyRegister( int k, const QCString& c, const QCString& m )
58static void applyLightSettings(PowerStatus *p) 63 :m_keyCode( k ), m_channel( c ), m_message( m ) {
59{ 64}
60 int initbright, intervalDim, intervalLightOff, intervalSuspend;
61 bool dim, lightoff, suspend;
62 65
63 { 66int QCopKeyRegister::keyCode()const {
64 Config config("qpe"); 67 return m_keyCode;
65 bool defsus; 68}
66 if ( p->acStatus() == PowerStatus::Online ) {
67 config.setGroup("ExternalPower");
68 defsus = FALSE;
69 } else {
70 config.setGroup("BatteryPower");
71 defsus = TRUE;
72 }
73 69
74 intervalDim = config.readNumEntry( "Interval_Dim", 20 ); 70QCString QCopKeyRegister::channel()const {
75 intervalLightOff = config.readNumEntry("Interval_LightOff", 30); 71 return m_channel;
76 intervalSuspend = config.readNumEntry("Interval", 240); 72}
77 initbright = config.readNumEntry("Brightness", 255);
78 dim = config.readBoolEntry("Dim", TRUE);
79 lightoff = config.readBoolEntry("LightOff", FALSE );
80 suspend = config.readBoolEntry("Suspend", defsus );
81
82 /* For compability*/
83 config.setGroup("Screensaver");
84 config.writeEntry( "Dim", dim );
85 config.writeEntry( "LightOff", lightoff );
86 config.writeEntry( "Suspend", suspend );
87 config.writeEntry( "Interval_Dim", intervalDim );
88 config.writeEntry( "Interval_LightOff", intervalLightOff );
89 config.writeEntry( "Interval", intervalSuspend );
90 config.writeEntry( "Brightness", initbright );
91 }
92 73
93 int i_dim = (dim ? intervalDim : 0); 74QCString QCopKeyRegister::message()const {
94 int i_lightoff = (lightoff ? intervalLightOff : 0); 75 return m_message;
95 int i_suspend = (suspend ? intervalSuspend : 0); 76}
96 77
97#ifndef QT_NO_COP 78bool QCopKeyRegister::send() {
98 QCopEnvelope eB("QPE/System", "setBacklight(int)" ); 79 if (m_channel.isNull() )
99 eB << initbright; 80 return false;
100 81
101 QCopEnvelope e("QPE/System", "setScreenSaverIntervals(int,int,int)" ); 82 QCopEnvelope( m_channel, m_message );
102 e << i_dim << i_lightoff << i_suspend; 83
103#endif 84 return true;
104} 85}
105 86
106//--------------------------------------------------------------------------- 87//---------------------------------------------------------------------------
107 88
108/* 89/*
109 Priority is number of alerts that are needed to pop up 90 Priority is number of alerts that are needed to pop up
110 alert. 91 alert.
111 */ 92 */
112class DesktopPowerAlerter : public QMessageBox 93class DesktopPowerAlerter : public QMessageBox
113{ 94{
114 Q_OBJECT 95 Q_OBJECT
115public: 96public:
116 DesktopPowerAlerter( QWidget *parent, const char *name = 0 ) 97 DesktopPowerAlerter( QWidget *parent, const char *name = 0 )
117 : QMessageBox( tr("Battery Status"), tr("Low Battery"), 98 : QMessageBox( tr("Battery Status"), tr("Low Battery"),
118 QMessageBox::Critical, 99 QMessageBox::Critical,
119 QMessageBox::Ok | QMessageBox::Default, 100 QMessageBox::Ok | QMessageBox::Default,
@@ -142,419 +123,633 @@ void DesktopPowerAlerter::alert( const QString &text, int priority )
142 setText( text ); 123 setText( text );
143 show(); 124 show();
144} 125}
145 126
146 127
147void DesktopPowerAlerter::hideEvent( QHideEvent *e ) 128void DesktopPowerAlerter::hideEvent( QHideEvent *e )
148{ 129{
149 QMessageBox::hideEvent( e ); 130 QMessageBox::hideEvent( e );
150 alertCount = 0; 131 alertCount = 0;
151 currentPriority = INT_MAX; 132 currentPriority = INT_MAX;
152} 133}
153 134
154//--------------------------------------------------------------------------- 135//---------------------------------------------------------------------------
155 136
156KeyFilter::KeyFilter(QObject* parent) : QObject(parent), held_tid(0), heldButton(0) 137KeyFilter::KeyFilter(QObject* parent) : QObject(parent), held_tid(0), heldButton(0)
157{ 138{
139 /* We don't do this cause it would interfere with ODevice */
140#if 0
158 qwsServer->setKeyboardFilter(this); 141 qwsServer->setKeyboardFilter(this);
142#endif
159} 143}
160 144
161void KeyFilter::timerEvent(QTimerEvent* e) 145void KeyFilter::timerEvent(QTimerEvent* e)
162{ 146{
163 if ( e->timerId() == held_tid ) { 147 if ( e->timerId() == held_tid ) {
164 killTimer(held_tid); 148 killTimer(held_tid);
165 // button held 149 // button held
166 if ( heldButton ) { 150 if ( heldButton ) {
167 emit activate(heldButton, TRUE); 151 emit activate(heldButton, TRUE);
168 heldButton = 0; 152 heldButton = 0;
169 } 153 }
170 held_tid = 0; 154 held_tid = 0;
171 } 155 }
172} 156}
173 157
174bool KeyFilter::filter(int /*unicode*/, int keycode, int modifiers, bool press, 158void KeyFilter::registerKey( const QCopKeyRegister& key ) {
175 bool autoRepeat) 159 m_keys.insert( key.keyCode(), key );
160}
161
162void KeyFilter::unregisterKey( const QCopKeyRegister& key ) {
163 m_keys.remove( key.keyCode() );
164}
165
166bool KeyFilter::keyRegistered( int key ) {
167 /*
168 * Check if we've a key registered
169 */
170 if ( !m_keys[key].send())
171 return false;
172 else
173 return true;
174
175}
176
177bool KeyFilter::checkButtonAction(bool db, int keycode, int press, int autoRepeat)
176{ 178{
177 if ( !loggedin 179 if ( !loggedin
178 // Permitted keys 180 // Permitted keys
179 && keycode != Key_F34 // power 181 && keycode != Key_F34 // power
180 && keycode != Key_F30 // select 182 && keycode != Key_F30 // select
181 && keycode != Key_Enter 183 && keycode != Key_Enter
182 && keycode != Key_Return 184 && keycode != Key_Return
183 && keycode != Key_Space 185 && keycode != Key_Space
184 && keycode != Key_Left 186 && keycode != Key_Left
185 && keycode != Key_Right 187 && keycode != Key_Right
186 && keycode != Key_Up 188 && keycode != Key_Up
187 && keycode != Key_Down ) 189 && keycode != Key_Down )
188 return TRUE; 190 return TRUE;
189 if ( !modifiers ) { 191
190 if ( !((ServerApplication*)qApp)->keyboardGrabbed() ) { 192 /* check if it was registered */
191 // First check to see if DeviceButtonManager knows something about this button: 193 if (!db ) {
192 const DeviceButton* button = DeviceButtonManager::instance().buttonForKeycode(keycode); 194 if (keycode != 0 &&press && !autoRepeat && keyRegistered(keycode) )
193 if (button && !autoRepeat) { 195 return true;
194 if ( held_tid ) { 196 }else {
195 killTimer(held_tid); 197
196 held_tid = 0; 198
197 } 199 // First check to see if DeviceButtonManager knows something about this button:
198 if ( button->heldAction().isNull() ) { 200 const Opie::ODeviceButton* button = Opie::ODevice::inst()->buttonForKeycode(keycode);
199 if ( press ) 201 if (button && !autoRepeat) {
200 emit activate(button, FALSE); 202 if ( held_tid ) {
201 } else if ( press ) { 203 killTimer(held_tid);
202 heldButton = button; 204 held_tid = 0;
203 held_tid = startTimer(500); 205 }
204 } else if ( heldButton ) { 206 if ( button->heldAction().isNull() ) {
205 heldButton = 0; 207 if ( press )
206 emit activate(button, FALSE); 208 emit activate(button, FALSE);
207 } 209 } else if ( press ) {
208 QWSServer::screenSaverActivate(FALSE); 210 heldButton = button;
209 return TRUE; 211 held_tid = startTimer( ODevice::inst ()->buttonHoldTime () );
210 } 212 } else if ( heldButton ) {
211 } 213 heldButton = 0;
212 if ( keycode == Key_F34 ) { 214 emit activate(button, FALSE);
213 if ( press ) emit power(); 215 }
214 return TRUE; 216 QWSServer::screenSaverActivate(FALSE);
215 } 217 return TRUE;
216 if ( keycode == Key_F35 ) { 218 }
217 if ( press ) emit backlight(); 219 return false;
218 return TRUE; 220 }
219 } 221 if ( keycode == HardKey_Suspend ) {
220 if ( keycode == Key_F32 ) { 222 if ( press ) emit power();
223 return TRUE;
224 }
225 if ( keycode == HardKey_Backlight ) {
226 if ( press ) emit backlight();
227 return TRUE;
228 }
229 if ( keycode == Key_F32 ) {
221#ifndef QT_NO_COP 230#ifndef QT_NO_COP
222 if ( press ) QCopEnvelope e( "QPE/Desktop", "startSync()" ); 231 if ( press ) QCopEnvelope e( "QPE/Desktop", "startSync()" );
223#endif 232#endif
224 return TRUE; 233 return TRUE;
225 }
226 if ( keycode == Key_F31 ) {
227 if ( press ) emit symbol();
228 QWSServer::screenSaverActivate(FALSE);
229 return TRUE;
230 }
231 } 234 }
232 if ( keycode == Key_NumLock ) { 235 if ( keycode == Key_F31 ) {
233 if ( press ) emit numLockStateToggle(); 236 if ( press ) emit symbol();
234 } 237 QWSServer::screenSaverActivate(FALSE);
235 if ( keycode == Key_CapsLock ) { 238 return TRUE;
236 if ( press ) emit capsLockStateToggle();
237 } 239 }
240
241 if ( keycode == Key_NumLock )
242 if ( press ) emit numLockStateToggle();
243
244 if ( keycode == Key_CapsLock )
245 if ( press ) emit capsLockStateToggle();
246
238 if ( serverApp ) 247 if ( serverApp )
239 serverApp->keyClick(keycode,press,autoRepeat); 248 serverApp->keyClick(keycode,press,autoRepeat);
249
240 return FALSE; 250 return FALSE;
241} 251}
242 252
243enum MemState { MemUnknown, MemVeryLow, MemLow, MemNormal } memstate=MemUnknown; 253enum MemState { MemUnknown, MemVeryLow, MemLow, MemNormal } memstate=MemUnknown;
244 254
245#if defined(QPE_HAVE_MEMALERTER) 255#if defined(QPE_HAVE_MEMALERTER)
246QPE_MEMALERTER_IMPL 256QPE_MEMALERTER_IMPL
247#endif 257#endif
248 258
249#if defined(CUSTOM_SOUND_IMPL) 259
250CUSTOM_SOUND_IMPL
251#endif
252 260
253//--------------------------------------------------------------------------- 261//---------------------------------------------------------------------------
254 262
255bool ServerApplication::doRestart = FALSE; 263bool ServerApplication::doRestart = FALSE;
256bool ServerApplication::allowRestart = TRUE; 264bool ServerApplication::allowRestart = TRUE;
257 265
266void ServerApplication::switchLCD( bool on ) {
267 if ( !qApp )
268 return;
269
270 ServerApplication *dapp = ServerApplication::me() ;
271
272 if ( !dapp-> m_screensaver )
273 return;
274
275 if ( on ) {
276 dapp-> m_screensaver-> setDisplayState ( true );
277 dapp-> m_screensaver-> setBacklight ( -3 );
278 }else
279 dapp-> m_screensaver-> setDisplayState ( false );
280
281
282}
283
258ServerApplication::ServerApplication( int& argc, char **argv, Type t ) 284ServerApplication::ServerApplication( int& argc, char **argv, Type t )
259 : QPEApplication( argc, argv, t ) 285 : QPEApplication( argc, argv, t )
260{ 286{
261#ifdef CUSTOM_SOUND_INIT
262 CUSTOM_SOUND_INIT;
263#endif
264 287
265#if defined(QPE_HAVE_MEMALERTER)
266 initMemalerter();
267#endif
268 288
269 // We know we'll have lots of cached pixmaps due to App/DocLnks 289 // We know we'll have lots of cached pixmaps due to App/DocLnks
270 QPixmapCache::setCacheLimit(512); 290 QPixmapCache::setCacheLimit(512);
271 291
272 QTimer *timer = new QTimer( this ); 292 m_ps = new PowerStatus;
273 connect( timer, SIGNAL(timeout()), this, SLOT(psTimeout()) ); 293 m_ps_last = new PowerStatus;
274 timer->start( 10000 );
275 ps = new PowerStatus;
276 pa = new DesktopPowerAlerter( 0 ); 294 pa = new DesktopPowerAlerter( 0 );
277 295
278 applyLightSettings(ps); 296 m_apm_timer = new QTimer( this );
297 connect(m_apm_timer, SIGNAL( timeout() ),
298 this, SLOT( apmTimeout() ) );
299
300 reloadPowerWarnSettings();
301
302 QCopChannel *channel = new QCopChannel( "QPE/System", this );
303 connect(channel, SIGNAL(received( const QCString&, const QByteArray& ) ),
304 this, SLOT(systemMessage(const QCString&, const QByteArray& ) ) );
305
306 channel = new QCopChannel("QPE/Launcher", this );
307 connect(channel, SIGNAL(received( const QCString&, const QByteArray& ) ),
308 this, SLOT(launcherMessage( const QCString&, const QByteArray& ) ) );
309
310 m_screensaver = new OpieScreenSaver();
311 m_screensaver->setInterval( -1 );
312 QWSServer::setScreenSaver( m_screensaver );
279 313
314 connect( qApp, SIGNAL( volumeChanged( bool ) ),
315 this, SLOT( rereadVolumes() ) );
316
317
318 /* ### PluginLoader libqtopia SafeMode */
319#if 0
280 if ( PluginLoader::inSafeMode() ) 320 if ( PluginLoader::inSafeMode() )
281 QTimer::singleShot(500, this, SLOT(showSafeMode()) ); 321 QTimer::singleShot(500, this, SLOT(showSafeMode()) );
282 QTimer::singleShot(20*1000, this, SLOT(clearSafeMode()) ); 322 QTimer::singleShot(20*1000, this, SLOT(clearSafeMode()) );
323#endif
283 324
284 KeyFilter* kf = new KeyFilter(this); 325 kf = new KeyFilter(this);
285 326
286 connect( kf, SIGNAL(launch()), this, SIGNAL(launch()) ); 327 connect( kf, SIGNAL(launch()), this, SIGNAL(launch()) );
287 connect( kf, SIGNAL(power()), this, SIGNAL(power()) ); 328 connect( kf, SIGNAL(power()), this, SIGNAL(power()) );
288 connect( kf, SIGNAL(backlight()), this, SIGNAL(backlight()) ); 329 connect( kf, SIGNAL(backlight()), this, SIGNAL(backlight()) );
289 connect( kf, SIGNAL(symbol()), this, SIGNAL(symbol())); 330 connect( kf, SIGNAL(symbol()), this, SIGNAL(symbol()));
290 connect( kf, SIGNAL(numLockStateToggle()), this,SIGNAL(numLockStateToggle())); 331 connect( kf, SIGNAL(numLockStateToggle()), this,SIGNAL(numLockStateToggle()));
291 connect( kf, SIGNAL(capsLockStateToggle()), this,SIGNAL(capsLockStateToggle())); 332 connect( kf, SIGNAL(capsLockStateToggle()), this,SIGNAL(capsLockStateToggle()));
292 connect( kf, SIGNAL(activate(const DeviceButton*,bool)), this,SIGNAL(activate(const DeviceButton*,bool))); 333 connect( kf, SIGNAL(activate(const Opie::ODeviceButton*,bool)),
334 this,SIGNAL(activate(const Opie::ODeviceButton*,bool)));
293 335
294 connect( kf, SIGNAL(power()), this, SLOT(togglePower()) ); 336 connect( kf, SIGNAL(power()), this, SLOT(togglePower()) );
295 connect( kf, SIGNAL(backlight()), this, SLOT(toggleLight()) ); 337 connect( kf, SIGNAL(backlight()), this, SLOT(toggleLight()) );
296 338
297 connect( this, SIGNAL(volumeChanged(bool)), this, SLOT(rereadVolumes()) ); 339 connect( this, SIGNAL(power() ),
340 SLOT(togglePower() ) );
341
298 rereadVolumes(); 342 rereadVolumes();
299 343
300 serverApp = this; 344 serverApp = this;
345
346 apmTimeout();
347 grabKeyboard();
348
349 /* make sure the event filter is installed */
350 const Opie::ODeviceButton* but = Opie::ODevice::inst()->buttonForKeycode( -1 );
301} 351}
302 352
303 353
304ServerApplication::~ServerApplication() 354ServerApplication::~ServerApplication()
305{ 355{
306 delete ps; 356 ungrabKeyboard();
357
358
307 delete pa; 359 delete pa;
360 delete m_ps;
361 delete m_ps_last;
362}
363
364void ServerApplication::apmTimeout() {
365 serverApp-> checkMemory( ); // in case no events are generated
366 *m_ps_last = *m_ps;
367 *m_ps = PowerStatusManager::readStatus();
368
369 if ( m_ps->acStatus() != m_ps_last-> acStatus() )
370 m_screensaver-> powerStatusChanged( *m_ps );
371
372 if ( m_ps->acStatus() == PowerStatus::Online )
373 return;
374
375 int bat = m_ps-> batteryPercentRemaining();
376
377 if ( bat < m_ps_last-> batteryPercentRemaining() ) {
378 if ( bat <= m_powerCritical )
379 pa->alert( tr( "Battery level is critical!\nKeep power off until power restored!" ), 1 );
380 else if ( bat <= m_powerVeryLow )
381 pa->alert( tr( "Battery is running very low. "), 2 );
382 }
383 if ( m_ps-> backupBatteryStatus() == PowerStatus::VeryLow )
384 pa->alert( tr("The Back-up battery is very low.\nPlease charge the back-up battery." ), 2);
385
386}
387
388void ServerApplication::systemMessage( const QCString& msg,
389 const QByteArray& data ) {
390 QDataStream stream ( data, IO_ReadOnly );
391
392 if ( msg == "setScreenSaverInterval(int)" ) {
393 int time;
394 stream >> time;
395 m_screensaver-> setInterval( time );
396 }
397 else if ( msg == "setScreenSaverIntervals(int,int,int)" ) {
398 int t1, t2, t3;
399 stream >> t1 >> t2 >> t3;
400 m_screensaver-> setIntervals( t1, t2, t3 );
401 }
402 else if ( msg == "setBacklight(int)" ) {
403 int bright;
404 stream >> bright;
405 m_screensaver-> setBacklight( bright );
406 }
407 else if ( msg == "setScreenSaverMode(int)" ) {
408 int mode;
409 stream >> mode;
410 m_screensaver-> setMode ( mode );
411 }
412 else if ( msg == "reloadPowerWarnSettings()" ) {
413 reloadPowerWarnSettings();
414 }
415 else if ( msg == "setDisplayState(int)" ) {
416 int state;
417 stream >> state;
418 m_screensaver-> setDisplayState ( state != 0 );
419 }
420 else if ( msg == "suspend()" ) {
421 emit power();
422 }
423 else if ( msg == "sendBusinessCard()" ) {
424 QString card = ::getenv ( "HOME" );
425 card += "/Applications/addressbook/businesscard.vcf";
426
427 if ( QFile::exists( card ) ) {
428 QCopEnvelope e ( "QPE/Obex", "send(QString,QString,QString)" );
429 QString mimetype = "text/x-vCard";
430 e << tr( "business card" ) << card << mimetype;
431 }
432 }
433}
434
435void ServerApplication::reloadPowerWarnSettings ( )
436{
437 Config cfg ( "apm" );
438 cfg. setGroup ( "Warnings" );
439
440 int iv = cfg. readNumEntry ( "checkinterval", 10000 );
441
442 m_apm_timer-> stop ( );
443 if ( iv )
444 m_apm_timer-> start ( iv );
445
446 m_powerVeryLow = cfg. readNumEntry ( "powerverylow", 10 );
447 m_powerCritical = cfg. readNumEntry ( "powervcritical", 5 );
448}
449
450void ServerApplication::launcherMessage( const QCString & msg, const QByteArray & data )
451{
452 QDataStream stream ( data, IO_ReadOnly );
453
454 if ( msg == "deviceButton(int,int,int)" ) {
455 int keycode, press, autoRepeat;
456 stream >> keycode >> press >> autoRepeat;
457
458 kf->checkButtonAction ( true, keycode, press, autoRepeat );
459 }
460 else if ( msg == "keyRegister(int,QCString,QCString)" ) {
461 int k;
462 QCString c, m;
463 stream >> k >> c >> m;
464
465 kf -> registerKey( QCopKeyRegister(k, c, m) );
466 }
308} 467}
309 468
469
310bool ServerApplication::screenLocked() 470bool ServerApplication::screenLocked()
311{ 471{
312 return loggedin == 0; 472 return loggedin == 0;
313} 473}
314 474
315void ServerApplication::login(bool at_poweron) 475void ServerApplication::login(bool at_poweron)
316{ 476{
317 if ( !loggedin ) { 477 if ( !loggedin ) {
318 Global::terminateBuiltin("calibrate"); // No tr 478 Global::terminateBuiltin("calibrate"); // No tr
319 Password::authenticate(at_poweron); 479 Password::authenticate(at_poweron);
320 loggedin=1; 480 loggedin=1;
321#ifndef QT_NO_COP 481#ifndef QT_NO_COP
322 QCopEnvelope e( "QPE/Desktop", "unlocked()" ); 482 QCopEnvelope e( "QPE/Desktop", "unlocked()" );
323#endif 483#endif
324 } 484 }
325} 485}
326 486
327#if defined(QPE_HAVE_TOGGLELIGHT) 487#if defined(QPE_HAVE_TOGGLELIGHT)
328#include <qtopia/config.h> 488#include <qtopia/config.h>
329 489
330#include <sys/ioctl.h> 490#include <sys/ioctl.h>
331#include <sys/types.h> 491#include <sys/types.h>
332#include <fcntl.h> 492#include <fcntl.h>
333#include <unistd.h> 493#include <unistd.h>
334#include <errno.h> 494#include <errno.h>
335#include <linux/ioctl.h> 495#include <linux/ioctl.h>
336#include <time.h> 496#include <time.h>
337#endif 497#endif
338 498
499#if 0
339static bool blanked=FALSE; 500static bool blanked=FALSE;
340 501
341static void blankScreen() 502static void blankScreen()
342{ 503{
343#ifdef QWS 504#ifdef QWS
344 QWidget w(0, 0, Qt::WStyle_Customize | Qt::WStyle_NoBorder | Qt::WStyle_Tool | Qt::WStyle_StaysOnTop | Qt::WPaintUnclipped); 505 QWidget w(0, 0, Qt::WStyle_Customize | Qt::WStyle_NoBorder | Qt::WStyle_Tool | Qt::WStyle_StaysOnTop | Qt::WPaintUnclipped);
345 w.resize( qt_screen->width(), qt_screen->height() ); 506 w.resize( qt_screen->width(), qt_screen->height() );
346 w.move(0, 0); 507 w.move(0, 0);
347 508
348 QPainter p(&w); 509 QPainter p(&w);
349 p.fillRect(w.rect(), QBrush(QColor(255,255,255)) ); 510 p.fillRect(w.rect(), QBrush(QColor(255,255,255)) );
350 p.end(); 511 p.end();
351 w.repaint(); 512 w.repaint();
352 513
353 blanked = TRUE; 514 blanked = TRUE;
354#endif 515#endif
355} 516}
356 517
357static void darkScreen() 518static void darkScreen()
358{ 519{
520 /* ### Screen blanking ODevice */
521#if 0
359 qpe_setBacklight(0); // force off 522 qpe_setBacklight(0); // force off
523#endif
524}
525#endif
526
527namespace {
528 void execAutoStart(const QDateTime& suspendTime ) {
529 QString appName;
530 int delay;
531 QDateTime now = QDateTime::currentDateTime();
532
533 Config cfg( "autostart" );
534 cfg.setGroup( "AutoStart" );
535 appName = cfg.readEntry( "Apps", "" );
536 delay = cfg.readNumEntry( "Delay", 0 );
537
538 // If the time between suspend and resume was longer then the
539 // value saved as delay, start the app
540 if ( suspendTime.secsTo( now ) >= ( delay * 60 ) && !appName.isEmpty() ) {
541 QCopEnvelope e( "QPE/System", "execute(QString)" );
542 e << QString( appName );
543 }
544 }
360} 545}
361 546
362 547
363void ServerApplication::togglePower() 548void ServerApplication::togglePower()
364{ 549{
365 static int haveAPM = -1; 550 static bool excllock = false;
366 if ( haveAPM < 0 ) { 551
367 if ( QFile::exists( "/proc/apm" ) ) { 552 if ( excllock )
368 haveAPM = 1; 553 return ;
369 } else { 554
370 haveAPM = 0; 555 excllock = true;
371 qWarning( "Cannot suspend - no APM support in kernel" ); 556
372 }
373 }
374
375 if ( haveAPM ) {
376 bool wasloggedin = loggedin; 557 bool wasloggedin = loggedin;
377 loggedin=0; 558 loggedin = 0;
378 if ( wasloggedin ) { 559 m_suspendTime = QDateTime::currentDateTime();
379 Config cfg( QPEApplication::qpeDir()+"/etc/Security.conf", Config::File); 560
380 cfg.setGroup("Passcode"); 561#ifdef QWS
381 QString passcode = cfg.readEntry("passcode"); 562
382 if ( !passcode.isEmpty() && cfg.readNumEntry("passcode_poweron",0) ) 563 if ( Password::needToAuthenticate ( true ) && qt_screen ) {
383 blankScreen(); 564 // Should use a big black window instead.
565 // But this would not show up fast enough
566 QGfx *g = qt_screen-> screenGfx ( );
567 g-> fillRect ( 0, 0, qt_screen-> width ( ), qt_screen-> height ( ));
568 delete g;
384 } 569 }
385 570#endif
386 system("apm --suspend"); 571
387 572 ODevice::inst ( )-> suspend ( );
388#ifndef QT_NO_COP 573
389 QWSServer::screenSaverActivate( FALSE ); 574 ServerApplication::switchLCD ( true ); // force LCD on without slow qcop call
575 QWSServer::screenSaverActivate ( false );
576
390 { 577 {
391 QCopEnvelope("QPE/Card", "mtabChanged()" ); // might have changed while asleep 578 QCopEnvelope( "QPE/Card", "mtabChanged()" ); // might have changed while asleep
392 QCopEnvelope e("QPE/System", "setBacklight(int)");
393 e << -3; // Force on
394 } 579 }
395#endif 580
396 if ( wasloggedin ) 581 if ( wasloggedin )
397 login(TRUE); 582 login ( true );
398 } 583
399 584 execAutoStart(m_suspendTime);
400 //qcopBridge->closeOpenConnections(); 585 //qcopBridge->closeOpenConnections();
401 //qDebug("called togglePower()!!!!!!"); 586
587 excllock = false;
402} 588}
403 589
404void ServerApplication::toggleLight() 590void ServerApplication::toggleLight()
405{ 591{
406#ifndef QT_NO_COP 592#ifndef QT_NO_COP
407 QCopEnvelope e("QPE/System", "setBacklight(int)"); 593 QCopEnvelope e("QPE/System", "setBacklight(int)");
408 e << -2; // toggle 594 e << -2; // toggle
409#endif 595#endif
410} 596}
411 597
412 598
599/*
600 * We still listen to key events but handle them in
601 * a special class
602 */
603
604bool ServerApplication::eventFilter( QObject *o, QEvent *e) {
605 if ( e->type() != QEvent::KeyPress &&
606 e->type() != QEvent::KeyRelease )
607 return QPEApplication::eventFilter( o, e );
608
609 QKeyEvent *ke = static_cast<QKeyEvent*>( e );
610 if ( kf->checkButtonAction( true, ke->key(),
611 e->type() == QEvent::KeyPress,
612 ke-> isAutoRepeat() ))
613 return true;
614
615 return QPEApplication::eventFilter( o, e );
616
617}
618
413#ifdef Q_WS_QWS 619#ifdef Q_WS_QWS
414bool ServerApplication::qwsEventFilter( QWSEvent *e ) 620bool ServerApplication::qwsEventFilter( QWSEvent *e )
415{ 621{
416 checkMemory(); 622 checkMemory();
417 623
418 if ( e->type == QWSEvent::Mouse ) { 624 if ( e->type == QWSEvent::Mouse ) {
419 QWSMouseEvent *me = (QWSMouseEvent *)e; 625 QWSMouseEvent *me = (QWSMouseEvent *)e;
420 static bool up = TRUE; 626 static bool up = TRUE;
421 if ( me->simpleData.state&LeftButton ) { 627 if ( me->simpleData.state&LeftButton ) {
422 if ( up ) { 628 if ( up ) {
423 up = FALSE; 629 up = FALSE;
424 screenClick(TRUE); 630 screenClick(TRUE);
425 } 631 }
426 } else if ( !up ) { 632 } else if ( !up ) {
427 up = TRUE; 633 up = TRUE;
428 screenClick(FALSE); 634 screenClick(FALSE);
429 } 635 }
636 }else if ( e->type == QWSEvent::Key ) {
637 QWSKeyEvent * ke = static_cast<QWSKeyEvent*>( e );
638 if ( kf->checkButtonAction( false,
639 ke-> simpleData.keycode,
640 ke-> simpleData.is_press,
641 ke-> simpleData.is_auto_repeat ) )
642 return true;
430 } 643 }
431 644
432 return QPEApplication::qwsEventFilter( e ); 645 return QPEApplication::qwsEventFilter( e );
433} 646}
434#endif 647#endif
435 648
436void ServerApplication::psTimeout()
437{
438 checkMemory(); // in case no events are being generated
439
440 PowerStatus::ACStatus oldStatus = ps->acStatus();
441 649
442 *ps = PowerStatusManager::readStatus(); 650/* ### FIXME libqtopia Plugin Safe Mode */
443
444 if ( oldStatus != ps->acStatus() ) {
445 // power source changed, read settings applying to current powersource
446 applyLightSettings(ps);
447 }
448
449
450 if ( (ps->batteryStatus() == PowerStatus::VeryLow ) ) {
451 pa->alert( tr( "Battery is running very low." ), 6 );
452 }
453
454 if ( ps->batteryStatus() == PowerStatus::Critical ) {
455 pa->alert( tr( "Battery level is critical!\n"
456 "Please recharge the main battery!" ), 1 );
457 }
458
459 if ( ps->backupBatteryStatus() == PowerStatus::VeryLow ) {
460 pa->alert( tr( "The Back-up battery is very low.\nPlease charge the back-up battery." ), 3 );
461 }
462}
463 651
464void ServerApplication::showSafeMode() 652void ServerApplication::showSafeMode()
465{ 653{
654#if 0
466 if ( QMessageBox::warning(0, tr("Safe Mode"), tr("<P>A system startup error occurred, " 655 if ( QMessageBox::warning(0, tr("Safe Mode"), tr("<P>A system startup error occurred, "
467 "and the system is now in Safe Mode. " 656 "and the system is now in Safe Mode. "
468 "Plugins are not loaded in Safe Mode. " 657 "Plugins are not loaded in Safe Mode. "
469 "You can use the Plugin Manager to " 658 "You can use the Plugin Manager to "
470 "disable plugins that cause system error."), tr("OK"), tr("Plugin Manager..."), 0) == 1 ) { 659 "disable plugins that cause system error."), tr("OK"), tr("Plugin Manager..."), 0) == 1 ) {
471 Global::execute( "pluginmanager" ); 660 Global::execute( "pluginmanager" );
472 } 661 }
662#endif
473} 663}
474 664
475void ServerApplication::clearSafeMode() 665void ServerApplication::clearSafeMode()
476{ 666{
667#if 0
477 // If we've been running OK for a while then we won't bother going into 668 // If we've been running OK for a while then we won't bother going into
478 // safe mode immediately on the next crash. 669 // safe mode immediately on the next crash.
479 Config cfg( "PluginLoader" ); 670 Config cfg( "PluginLoader" );
480 cfg.setGroup( "Global" ); 671 cfg.setGroup( "Global" );
481 QString mode = cfg.readEntry( "Mode", "Normal" ); 672 QString mode = cfg.readEntry( "Mode", "Normal" );
482 if ( mode == "MaybeSafe" ) { 673 if ( mode == "MaybeSafe" ) {
483 cfg.writeEntry( "Mode", "Normal" ); 674 cfg.writeEntry( "Mode", "Normal" );
484 } 675 }
676#endif
485} 677}
486 678
679
487void ServerApplication::shutdown() 680void ServerApplication::shutdown()
488{ 681{
489 if ( type() != GuiServer ) 682 if ( type() != GuiServer )
490 return; 683 return;
491 ShutdownImpl *sd = new ShutdownImpl( 0, 0, WDestructiveClose ); 684 ShutdownImpl *sd = new ShutdownImpl( 0, 0, WDestructiveClose );
492 connect( sd, SIGNAL(shutdown(ShutdownImpl::Type)), 685 connect( sd, SIGNAL(shutdown(ShutdownImpl::Type)),
493 this, SLOT(shutdown(ShutdownImpl::Type)) ); 686 this, SLOT(shutdown(ShutdownImpl::Type)) );
494 sd->showMaximized(); 687 sd->showMaximized();
495} 688}
496 689
497void ServerApplication::shutdown( ShutdownImpl::Type t ) 690void ServerApplication::shutdown( ShutdownImpl::Type t )
498{ 691{
499 switch ( t ) { 692 char *opt = 0;
500 case ShutdownImpl::ShutdownSystem:
501#ifndef Q_OS_WIN32
502 execlp("shutdown", "shutdown", "-h", "now", (void*)0); // No tr
503#else
504 qDebug("ServerApplication::ShutdownSystem");
505 prepareForTermination(FALSE);
506 quit();
507#endif
508 break;
509
510 case ShutdownImpl::RebootSystem:
511#ifndef Q_OS_WIN32
512 execlp("shutdown", "shutdown", "-r", "now", (void*)0); // No tr
513#else
514 qDebug("ServerApplication::RebootSystem");
515 restart();
516#endif
517 break;
518 693
519 case ShutdownImpl::RestartDesktop: 694 switch ( t ) {
520 restart(); 695 case ShutdownImpl::ShutdownSystem:
521 break; 696 opt = "-h";
522 697 // fall through
523 case ShutdownImpl::TerminateDesktop: 698 case ShutdownImpl::RebootSystem:
524 prepareForTermination(FALSE); 699 if ( opt == 0 )
525 quit(); 700 opt = "-r";
526 break; 701
702 if ( execl( "/sbin/shutdown", "shutdown", opt, "now", ( void* ) 0) < 0 )
703 perror("shutdown");
704 // ::syslog ( LOG_ERR, "Erroring execing shutdown\n" );
705
706 break;
707 case ShutdownImpl::RestartDesktop:
708 restart();
709 break;
710 case ShutdownImpl::TerminateDesktop:
711 prepareForTermination( FALSE );
712
713 // This is a workaround for a Qt bug
714 // clipboard applet has to stop its poll timer, or Qt/E
715 // will hang on quit() right before it emits aboutToQuit()
716 emit aboutToQuit ( );
717
718 quit();
719 break;
527 } 720 }
528} 721}
529 722
530void ServerApplication::restart() 723void ServerApplication::restart()
531{ 724{
532 if ( allowRestart ) { 725 if ( allowRestart ) {
533 prepareForTermination(TRUE); 726 prepareForTermination(TRUE);
534 doRestart = TRUE; 727 doRestart = TRUE;
535 quit(); 728 quit();
536 } 729 }
537} 730}
538 731
539void ServerApplication::rereadVolumes() 732void ServerApplication::rereadVolumes()
540{ 733{
541 Config cfg("Sound"); 734 Config cfg( "qpe" );
542 cfg.setGroup("System"); 735 cfg. setGroup ( "Volume" );
543 touchclick = cfg.readBoolEntry("Touch"); 736
544 keyclick = cfg.readBoolEntry("Key"); 737 m_screentap_sound = cfg. readBoolEntry ( "TouchSound" );
738 m_keyclick_sound = cfg. readBoolEntry ( "KeySound" );
739 m_alarm_sound = cfg. readBoolEntry ( "AlarmSound" );
545} 740}
546 741
547 742
548void ServerApplication::checkMemory() 743void ServerApplication::checkMemory()
549{ 744{
550#if defined(QPE_HAVE_MEMALERTER) 745#if defined(QPE_HAVE_MEMALERTER)
551 static bool ignoreNormal=TRUE; 746 static bool ignoreNormal=TRUE;
552 static bool existingMessage=FALSE; 747 static bool existingMessage=FALSE;
553 748
554 if(existingMessage) 749 if(existingMessage)
555 return; // don't show a second message while still on first 750 return; // don't show a second message while still on first
556 751
557 existingMessage = TRUE; 752 existingMessage = TRUE;
558 switch ( memstate ) { 753 switch ( memstate ) {
559 case MemUnknown: 754 case MemUnknown:
560 break; 755 break;
@@ -578,40 +773,41 @@ void ServerApplication::checkMemory()
578 memstate = MemUnknown; 773 memstate = MemUnknown;
579 QMessageBox::critical( 0 , tr("Memory Status"), 774 QMessageBox::critical( 0 , tr("Memory Status"),
580 tr("Critical Memory Shortage\n" 775 tr("Critical Memory Shortage\n"
581 "Please end this application\n" 776 "Please end this application\n"
582 "immediately.") ); 777 "immediately.") );
583 recoverMemory(); 778 recoverMemory();
584 } 779 }
585 existingMessage = FALSE; 780 existingMessage = FALSE;
586#endif 781#endif
587} 782}
588 783
589bool ServerApplication::recoverMemory() 784bool ServerApplication::recoverMemory()
590{ 785{
591 return FALSE; 786 return FALSE;
592} 787}
593 788
594void ServerApplication::keyClick(int keycode, bool press, bool repeat) 789void ServerApplication::keyClick(int , bool press, bool )
595{ 790{
596#ifdef CUSTOM_SOUND_KEYCLICK 791 if ( press && m_keyclick_sound )
597 if ( keyclick ) 792 ODevice::inst() -> keySound();
598 CUSTOM_SOUND_KEYCLICK(keycode,press,repeat); 793
599#else
600 Q_UNUSED( keycode );
601 Q_UNUSED( press );
602 Q_UNUSED( repeat );
603#endif
604} 794}
605 795
606void ServerApplication::screenClick(bool press) 796void ServerApplication::screenClick(bool press)
607{ 797{
608#ifdef CUSTOM_SOUND_TOUCH 798 if ( press && m_screentap_sound )
609 if ( touchclick ) 799 ODevice::inst() -> touchSound();
610 CUSTOM_SOUND_TOUCH(press); 800}
611#else 801
612 Q_UNUSED( press ); 802void ServerApplication::soundAlarm() {
613#endif 803 if ( me ()->m_alarm_sound )
804 ODevice::inst()->alarmSound();
805}
806
807ServerApplication *ServerApplication::me ( )
808{
809 return static_cast<ServerApplication*>( qApp );
614} 810}
615 811
616 812
617#include "serverapp.moc" 813#include "serverapp.moc"
diff --git a/core/launcher/serverapp.h b/core/launcher/serverapp.h
index 60d9c41..0a3259a 100644
--- a/core/launcher/serverapp.h
+++ b/core/launcher/serverapp.h
@@ -19,98 +19,147 @@
19**********************************************************************/ 19**********************************************************************/
20 20
21#ifndef SERVERAPP_H 21#ifndef SERVERAPP_H
22#define SERVERAPP_H 22#define SERVERAPP_H
23 23
24#include <qtopia/qpeapplication.h> 24#include <qtopia/qpeapplication.h>
25 25
26#include <qwidget.h> 26#include <qwidget.h>
27#ifdef QWS 27#ifdef QWS
28#include <qwindowsystem_qws.h> 28#include <qwindowsystem_qws.h>
29#endif 29#endif
30 30
31#include "shutdownimpl.h" 31#include "shutdownimpl.h"
32 32
33class PowerStatus; 33class PowerStatus;
34class DesktopPowerAlerter; 34class DesktopPowerAlerter;
35class DeviceButton;
36 35
37class KeyFilter : public QObject, public QWSServer::KeyboardFilter { 36class OpieScreenSaver;
37namespace Opie {
38 class ODeviceButton;
39}
40
41struct QCopKeyRegister {
42 QCopKeyRegister();
43 QCopKeyRegister( int k, const QCString&, const QCString& );
44 int keyCode()const;
45 QCString channel()const;
46 QCString message()const;
47 inline bool send();
48
49private:
50 int m_keyCode;
51 QCString m_channel, m_message;
52};
53
54typedef QMap<int, QCopKeyRegister> KeyRegisterList;
55
56class KeyFilter : public QObject {
38 Q_OBJECT 57 Q_OBJECT
39public: 58public:
40 KeyFilter(QObject* parent); 59 KeyFilter(QObject* parent);
41 bool filter(int unicode, int keycode, int modifiers, bool press, 60 void registerKey( const QCopKeyRegister& );
42 bool autoRepeat); 61 void unregisterKey( const QCopKeyRegister& );
62 bool checkButtonAction( bool, int, int, int );
63
64
43 65
44protected: 66protected:
45 void timerEvent(QTimerEvent*); 67 void timerEvent(QTimerEvent*);
46 68
47signals: 69signals:
48 void launch(); 70 void launch();
49 void power(); 71 void power();
50 void backlight(); 72 void backlight();
51 void symbol(); 73 void symbol();
52 void numLockStateToggle(); 74 void numLockStateToggle();
53 void capsLockStateToggle(); 75 void capsLockStateToggle();
54 void activate(const DeviceButton*,bool); 76 void activate(const Opie::ODeviceButton*,bool);
77
55 78
56private: 79private:
80 inline bool keyRegistered( int key );
57 int held_tid; 81 int held_tid;
58 const DeviceButton* heldButton; 82 const Opie::ODeviceButton* heldButton;
83 KeyRegisterList m_keys;
59}; 84};
60 85
61class ServerApplication : public QPEApplication 86class ServerApplication : public QPEApplication
62{ 87{
63 Q_OBJECT 88 Q_OBJECT
64public: 89public:
65 ServerApplication( int& argc, char **argv, Type t ); 90 ServerApplication( int& argc, char **argv, Type t );
66 ~ServerApplication(); 91 ~ServerApplication();
67 92
68 static bool doRestart; 93 static bool doRestart;
69 static bool allowRestart; 94 static bool allowRestart;
70 static bool screenLocked(); 95 static bool screenLocked();
71 static void login(bool at_poweron); 96 static void login(bool at_poweron);
72 97
98 static void switchLCD ( bool on ); // only for togglePower in Desktop
99 static void soundAlarm(); // only because QCop soundAlarm() is defined in QPE/TaskBar
100
73 void restart(); 101 void restart();
74 102
75signals: 103signals:
104 void menu();
76 void home(); 105 void home();
77 void launch(); 106 void launch();
78 void power(); 107 void power();
79 void backlight(); 108 void backlight();
80 void symbol(); 109 void symbol();
81 void numLockStateToggle(); 110 void numLockStateToggle();
82 void capsLockStateToggle(); 111 void capsLockStateToggle();
83 void prepareForRestart(); 112 void prepareForRestart();
84 void activate(const DeviceButton*,bool); 113 void activate(const Opie::ODeviceButton*,bool);
114
115public slots:
116 virtual void systemMessage( const QCString& msg, const QByteArray& );
117 virtual void launcherMessage( const QCString& msg, const QByteArray& );
118 void rereadVolumes();
85 119
86protected: 120protected:
121 bool eventFilter( QObject*, QEvent* );
87#ifdef Q_WS_QWS 122#ifdef Q_WS_QWS
88 bool qwsEventFilter( QWSEvent * ); 123 bool qwsEventFilter( QWSEvent * );
89#endif 124#endif
90 void shutdown(); 125 void shutdown();
91 void checkMemory(); 126 void checkMemory();
92 bool recoverMemory(); 127 bool recoverMemory();
93 void keyClick(int keycode, bool press, bool repeat); 128 void keyClick(int keycode, bool press, bool repeat);
94 void screenClick(bool press); 129 void screenClick(bool press);
95 130
96protected slots: 131protected slots:
97 void shutdown(ShutdownImpl::Type); 132 void shutdown(ShutdownImpl::Type);
98 void psTimeout(); 133 void apmTimeout();
99 void showSafeMode(); 134 void showSafeMode();
100 void clearSafeMode(); 135 void clearSafeMode();
101 void togglePower(); 136 void togglePower();
102 void toggleLight(); 137 void toggleLight();
103 void rereadVolumes(); 138
139private:
140 static ServerApplication *me ();
141 void reloadPowerWarnSettings();
142 KeyFilter *kf;
143
104 144
105private: 145private:
106 DesktopPowerAlerter *pa; 146 DesktopPowerAlerter *pa;
107 PowerStatus *ps; 147 PowerStatus *m_ps, *m_ps_last;
108 bool keyclick; 148 OpieScreenSaver *m_screensaver;
109 bool touchclick; 149 QTimer *m_apm_timer;
150 QDateTime m_suspendTime;
151 int m_powerVeryLow;
152 int m_powerCritical;
153 int m_currentPowerLevel;
154
155 bool m_keyclick_sound : 1;
156 bool m_screentap_sound : 1;
157 bool m_alarm_sound : 1;
158
110 159
111 friend class KeyFilter; 160 friend class KeyFilter;
112}; 161};
113 162
114 163
115#endif // SERVERAPP_H 164#endif // SERVERAPP_H
116 165