~ubuntu-branches/ubuntu/gutsy/kdebase-workspace/gutsy-backports

« back to all changes in this revision

Viewing changes to ksysguard/gui/ksysguard.cc

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2007-09-05 20:45:14 UTC
  • Revision ID: james.westby@ubuntu.com-20070905204514-632hhspl0nvrc84i
Tags: upstream-3.93.0
ImportĀ upstreamĀ versionĀ 3.93.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    KSysGuard, the KDE System Guard
 
3
 
 
4
    Copyright (c) 2006 John Tapsell <john.tapsell@kdemail.org>
 
5
    Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org>
 
6
 
 
7
    This program is free software; you can redistribute it and/or
 
8
    modify it under the terms of version 2 of the GNU General Public
 
9
    License as published by the Free Software Foundation.
 
10
 
 
11
    This program is distributed in the hope that it will be useful,
 
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
    GNU General Public License for more details.
 
15
 
 
16
    You should have received a copy of the GNU General Public License
 
17
    along with this program; if not, write to the Free Software
 
18
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
19
 
 
20
    KSysGuard has been written with some source code and ideas from
 
21
    ktop (<1.0). Early versions of ktop have been written by Bernd
 
22
    Johannes Wuebben <wuebben@math.cornell.edu> and Nicolas Leclercq
 
23
    <nicknet@planete.net>.
 
24
 
 
25
*/
 
26
 
 
27
#include <assert.h>
 
28
#include <ctype.h>
 
29
#include <fcntl.h>
 
30
#include <stdio.h>
 
31
#include <stdlib.h>
 
32
#include <unistd.h>
 
33
 
 
34
#include <kaboutdata.h>
 
35
#include <kaction.h>
 
36
#include <kactioncollection.h>
 
37
#include <kapplication.h>
 
38
#include <kcmdlineargs.h>
 
39
#include <kdebug.h>
 
40
#include <kedittoolbar.h>
 
41
#include <kglobal.h>
 
42
#include <kglobalsettings.h>
 
43
#include <kicon.h>
 
44
#include <klocale.h>
 
45
#include <kmessagebox.h>
 
46
#include <ksgrd/SensorAgent.h>
 
47
#include <ksgrd/SensorManager.h>
 
48
#include <kstandarddirs.h>
 
49
#include <kstatusbar.h>
 
50
#include <kstandardaction.h>
 
51
#include <ktoggleaction.h>
 
52
#include <ktoolbar.h>
 
53
#include <kurl.h>
 
54
#include <kwindowsystem.h>
 
55
#include <QSplitter>
 
56
 
 
57
#include "../version.h"
 
58
#include "SensorBrowser.h"
 
59
#include "Workspace.h"
 
60
#include "WorkSheet.h"
 
61
#include "StyleEngine.h"
 
62
#include "HostConnector.h"
 
63
 
 
64
#include "ksysguard.h"
 
65
 
 
66
 
 
67
 
 
68
//Comment out to stop ksysguard from forking.  Good for debugging
 
69
//#define FORK_KSYSGUARD
 
70
 
 
71
static const char Description[] = I18N_NOOP( "KDE System Monitor" );
 
72
TopLevel* topLevel;
 
73
 
 
74
/**
 
75
  This is the constructor for the main widget. It sets up the menu and the
 
76
  TaskMan widget.
 
77
 */
 
78
TopLevel::TopLevel()
 
79
  : KXmlGuiWindow( 0 )
 
80
{
 
81
  QDBusConnection::sessionBus().registerObject("/", this, QDBusConnection::ExportScriptableSlots);
 
82
  setPlainCaption( i18n( "System Monitor" ) );
 
83
  mTimerId = -1;
 
84
 
 
85
  mSplitter = new QSplitter( this );
 
86
  mSplitter->setOrientation( Qt::Horizontal );
 
87
  mSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
 
88
  setCentralWidget( mSplitter );
 
89
 
 
90
  mSensorBrowser = 0;
 
91
 
 
92
  mWorkSpace = new Workspace( mSplitter );
 
93
  connect( mWorkSpace, SIGNAL( setCaption( const QString&) ),
 
94
           SLOT( setCaption( const QString&) ) );
 
95
  connect( mWorkSpace, SIGNAL( currentChanged( int ) ),
 
96
           SLOT( currentTabChanged( int ) ) );
 
97
 
 
98
  /* Create the status bar. It displays some information about the
 
99
   * number of processes and the memory consumption of the local
 
100
   * host. */
 
101
  const int STATUSBAR_STRETCH=1;
 
102
  statusBar()->insertItem( i18n( "Loading Processes Count.." ), 0, STATUSBAR_STRETCH );
 
103
  statusBar()->insertItem( i18n( "Loading CPU Stat.." ), 1, STATUSBAR_STRETCH );
 
104
  statusBar()->insertItem( i18n( "Loading Memory Totals.." ), 2, STATUSBAR_STRETCH );
 
105
  statusBar()->insertItem( i18n( "Loading Swap Totals.." ), 3, STATUSBAR_STRETCH);
 
106
  statusBar()->hide();
 
107
 
 
108
  // create actions for menu entries
 
109
  QAction *action = actionCollection()->addAction("new_worksheet");
 
110
  action->setIcon(KIcon("tab-new"));
 
111
  action->setText(i18n( "&New Worksheet..." ));
 
112
  connect(action, SIGNAL(triggered(bool)), mWorkSpace, SLOT( newWorkSheet() ));
 
113
  action = actionCollection()->addAction("import_worksheet");
 
114
  action->setIcon(KIcon("document-open") );
 
115
  action->setText(i18n( "Import Worksheet..." ));
 
116
  connect(action, SIGNAL(triggered(bool)), mWorkSpace, SLOT( importWorkSheet() ));
 
117
  mTabRemoveAction = actionCollection()->addAction( "remove_worksheet" );
 
118
  mTabRemoveAction->setIcon( KIcon("tab-remove") );
 
119
  mTabRemoveAction->setText( i18n( "&Remove Worksheet" ) );
 
120
  connect(mTabRemoveAction, SIGNAL(triggered(bool)), mWorkSpace, SLOT( removeWorkSheet() ));
 
121
  mTabExportAction = actionCollection()->addAction( "export_worksheet" );
 
122
  mTabExportAction->setIcon( KIcon("document-save-as") );
 
123
  mTabExportAction->setText( i18n( "&Export Worksheet..." ) );
 
124
  connect(mTabExportAction, SIGNAL(triggered(bool)), mWorkSpace, SLOT( exportWorkSheet() ));
 
125
 
 
126
  KStandardAction::quit( this, SLOT( close() ), actionCollection() );
 
127
 
 
128
  mMonitorRemoteAction = actionCollection()->addAction( "connect_host" );
 
129
  mMonitorRemoteAction->setIcon( KIcon("connection-established") );
 
130
  mMonitorRemoteAction->setText( i18n( "Monitor remote machine..." ) );
 
131
  connect(mMonitorRemoteAction, SIGNAL(triggered(bool)), SLOT( connectHost() ));
 
132
 
 
133
  action = actionCollection()->addAction( "configure_sheet" );
 
134
  action->setIcon( KIcon("configure") );
 
135
  action->setText( i18n( "&Worksheet Properties" ) );
 
136
  connect(action, SIGNAL(triggered(bool)), mWorkSpace, SLOT( configure() ));
 
137
 
 
138
  setupGUI(ToolBar | Keys | StatusBar | Create);
 
139
}
 
140
 
 
141
void TopLevel::currentTabChanged(int index)
 
142
{
 
143
  kDebug() << "Current tab changed to " << index;
 
144
  QWidget *wdg = mWorkSpace->widget(index);
 
145
  WorkSheet *sheet = (WorkSheet *)(wdg);
 
146
  Q_ASSERT(sheet);
 
147
  bool locked = !sheet || sheet->isLocked();
 
148
  mTabRemoveAction->setVisible(!locked);
 
149
  mTabExportAction->setVisible(!locked);
 
150
  mMonitorRemoteAction->setVisible(!locked);
 
151
 
 
152
  if(!locked && !mSensorBrowser) {
 
153
    startSensorBrowserWidget();
 
154
  }
 
155
  if(mSensorBrowser) {
 
156
    if(mSensorBrowser->isVisible() && locked) //going from visible to not visible to save the state
 
157
      mSplitterSize = mSplitter->sizes();
 
158
    mSensorBrowser->setVisible(!locked);
 
159
 
 
160
  }
 
161
}
 
162
void TopLevel::startSensorBrowserWidget()
 
163
{
 
164
  if(mSensorBrowser) return;
 
165
  kDebug() << "Creating sensor browser";
 
166
  mSensorBrowser = new SensorBrowserWidget( 0, KSGRD::SensorMgr );
 
167
  mSplitter->insertWidget(0,mSensorBrowser);
 
168
  mSplitter->setSizes( mSplitterSize );
 
169
}
 
170
 
 
171
/*
 
172
 * DBUS Interface functions
 
173
 */
 
174
 
 
175
void TopLevel::showOnCurrentDesktop()
 
176
{
 
177
  KWindowSystem::setOnDesktop( winId(), KWindowSystem::currentDesktop() );
 
178
  kapp->updateUserTimestamp();
 
179
  KWindowSystem::forceActiveWindow( winId() );
 
180
}
 
181
 
 
182
void TopLevel::importWorkSheet( const QString &fileName )
 
183
{
 
184
  mWorkSpace->importWorkSheet( KUrl( fileName ) );
 
185
}
 
186
 
 
187
void TopLevel::removeWorkSheet( const QString &fileName )
 
188
{
 
189
  mWorkSpace->removeWorkSheet( fileName );
 
190
}
 
191
 
 
192
QStringList TopLevel::listSensors( const QString &hostName )
 
193
{
 
194
  startSensorBrowserWidget();
 
195
  return mSensorBrowser->listSensors( hostName );
 
196
}
 
197
 
 
198
QStringList TopLevel::listHosts()
 
199
{
 
200
  startSensorBrowserWidget();
 
201
  return mSensorBrowser->listHosts();
 
202
}
 
203
 
 
204
void TopLevel::initStatusBar()
 
205
{
 
206
  KSGRD::SensorMgr->engage( "localhost", "", "ksysguardd" );
 
207
  /* Request info about the swap space size and the units it is
 
208
   * measured in.  The requested info will be received by
 
209
   * answerReceived(). */
 
210
  KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/used?",
 
211
                                 (KSGRD::SensorClient*)this, 7 );
 
212
  updateStatusBar();
 
213
 
 
214
  KToggleAction *sb = dynamic_cast<KToggleAction*>(action("options_show_statusbar"));
 
215
  if (sb)
 
216
     connect(sb, SIGNAL(toggled(bool)), this, SLOT(updateStatusBar()));
 
217
}
 
218
 
 
219
void TopLevel::updateStatusBar()
 
220
{
 
221
  if ( mTimerId == -1 )
 
222
    mTimerId = startTimer( 2000 );
 
223
 
 
224
  // call timerEvent to fill the status bar with real values
 
225
  timerEvent( 0 );
 
226
}
 
227
 
 
228
void TopLevel::connectHost()
 
229
{
 
230
  HostConnector hostConnector( this );
 
231
 
 
232
//  hostConnector.setHostNames( mHostList );
 
233
//  hostConnector.setCommands( mCommandList );
 
234
 
 
235
//  hostConnector.setCurrentHostName( "" );
 
236
 
 
237
  if ( !hostConnector.exec() )
 
238
    return;
 
239
 
 
240
//  mHostList = hostConnector.hostNames();
 
241
//  mCommandList = hostConnector.commands();
 
242
 
 
243
  QString shell = "";
 
244
  QString command = "";
 
245
  int port = -1;
 
246
 
 
247
  /* Check which radio button is selected and set parameters
 
248
   * appropriately. */
 
249
  if ( hostConnector.useSsh() )
 
250
    shell = "ssh";
 
251
  else if ( hostConnector.useRsh() )
 
252
    shell = "rsh";
 
253
  else if ( hostConnector.useDaemon() )
 
254
    port = hostConnector.port();
 
255
  else
 
256
    command = hostConnector.currentCommand();
 
257
 
 
258
  KSGRD::SensorMgr->engage( hostConnector.currentHostName(), shell, command, port );
 
259
}
 
260
 
 
261
void TopLevel::disconnectHost()
 
262
{
 
263
  if(mSensorBrowser)
 
264
    mSensorBrowser->disconnect();
 
265
}
 
266
 
 
267
void TopLevel::editToolbars()
 
268
{
 
269
  saveMainWindowSettings( KConfigGroup( KGlobal::config(), "MainWindow" ) );
 
270
  KEditToolBar dlg( actionCollection() );
 
271
  connect( &dlg, SIGNAL( newToolbarConfig() ), this,
 
272
           SLOT( slotNewToolbarConfig() ) );
 
273
 
 
274
  dlg.exec();
 
275
}
 
276
 
 
277
void TopLevel::slotNewToolbarConfig()
 
278
{
 
279
  createGUI();
 
280
  applyMainWindowSettings( KConfigGroup( KGlobal::config(), "MainWindow" ) );
 
281
}
 
282
 
 
283
bool TopLevel::event( QEvent *e )
 
284
{
 
285
  if ( e->type() == QEvent::User ) {
 
286
    /* Due to the asynchronous communication between ksysguard and its
 
287
     * back-ends, we sometimes need to show message boxes that were
 
288
     * triggered by objects that have died already. */
 
289
    KMessageBox::error( this, static_cast<KSGRD::SensorManager::MessageEvent*>(e)->message() );
 
290
 
 
291
    return true;
 
292
  }
 
293
 
 
294
  return KXmlGuiWindow::event( e );
 
295
}
 
296
 
 
297
void TopLevel::timerEvent( QTimerEvent* )
 
298
{
 
299
  if ( statusBar()->isVisibleTo( this ) ) {
 
300
    /* Request some info about the memory status. The requested
 
301
     * information will be received by answerReceived(). */
 
302
    KSGRD::SensorMgr->sendRequest( "localhost", "pscount",
 
303
                                   (KSGRD::SensorClient*)this, 0 );
 
304
    KSGRD::SensorMgr->sendRequest( "localhost", "cpu/system/idle",
 
305
                                   (KSGRD::SensorClient*)this, 1 );
 
306
    KSGRD::SensorMgr->sendRequest( "localhost", "mem/physical/free",
 
307
                                   (KSGRD::SensorClient*)this, 2 );
 
308
    KSGRD::SensorMgr->sendRequest( "localhost", "mem/physical/used",
 
309
                                   (KSGRD::SensorClient*)this, 3 );
 
310
    KSGRD::SensorMgr->sendRequest( "localhost", "mem/physical/application",
 
311
                                   (KSGRD::SensorClient*)this, 4 );
 
312
    KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/free",
 
313
                                   (KSGRD::SensorClient*)this, 5 );
 
314
    KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/used",
 
315
                                   (KSGRD::SensorClient*)this, 6 );
 
316
  }
 
317
}
 
318
 
 
319
bool TopLevel::queryClose()
 
320
{
 
321
  if ( !mWorkSpace->saveOnQuit() )
 
322
    return false;
 
323
 
 
324
  KConfigGroup cg( KGlobal::config(), "MainWindow" );
 
325
  saveProperties( cg );
 
326
  KGlobal::config()->sync();
 
327
 
 
328
  return true;
 
329
}
 
330
 
 
331
void TopLevel::readProperties( const KConfigGroup& cfg )
 
332
{
 
333
 
 
334
  /* we can ignore 'isMaximized' because we can't set the window
 
335
     maximized, so we save the coordinates instead */
 
336
//  if ( cfg.readEntry( "isMinimized" , false) == true )
 
337
//    showMinimized();
 
338
 
 
339
  mSplitterSize = cfg.readEntry( "SplitterSizeList",QList<int>() );
 
340
  if ( mSplitterSize.isEmpty() ) {
 
341
    // start with a 30/70 ratio
 
342
    mSplitterSize.append( 10 );
 
343
    mSplitterSize.append( 90 );
 
344
  }
 
345
 
 
346
  KSGRD::SensorMgr->readProperties( cfg );
 
347
  KSGRD::Style->readProperties( cfg );
 
348
 
 
349
  mWorkSpace->readProperties( cfg );
 
350
 
 
351
  applyMainWindowSettings( cfg );
 
352
}
 
353
 
 
354
void TopLevel::saveProperties( KConfigGroup& cfg )
 
355
{
 
356
  cfg.writeEntry( "isMinimized", isMinimized() );
 
357
 
 
358
  if(mSensorBrowser && mSensorBrowser->isVisible())
 
359
    cfg.writeEntry( "SplitterSizeList",  mSplitter->sizes());
 
360
  else if(mSplitterSize.size() == 2 && mSplitterSize.value(0) != 0 && mSplitterSize.value(1) != 0)
 
361
    cfg.writeEntry( "SplitterSizeList", mSplitterSize );
 
362
 
 
363
  KSGRD::Style->saveProperties( cfg );
 
364
  KSGRD::SensorMgr->saveProperties( cfg );
 
365
 
 
366
  saveMainWindowSettings( cfg );
 
367
  mWorkSpace->saveProperties( cfg );
 
368
}
 
369
 
 
370
void TopLevel::answerReceived( int id, const QList<QByteArray> &answerList )
 
371
{
 
372
  // we have received an answer from the daemon.
 
373
  QByteArray answer;
 
374
  if(!answerList.isEmpty()) answer = answerList[0];
 
375
  QString s;
 
376
  static QString unit;
 
377
  static long mFree = 0;
 
378
  static long mUsedApplication = 0;
 
379
  static long mUsedTotal = 0;
 
380
  static long sUsed = 0;
 
381
  static long sFree = 0;
 
382
 
 
383
  switch ( id ) {
 
384
    case 0:
 
385
      s = i18n( " %1 processes ", answer.toInt() );
 
386
      statusBar()->changeItem( s, 0 );
 
387
      break;
 
388
 
 
389
    case 1:
 
390
      s = i18n( " CPU: %1% ", (int) (100 - answer.toFloat()) );
 
391
      statusBar()->changeItem( s, 1 );
 
392
      break;
 
393
 
 
394
    case 2:
 
395
      mFree = answer.toLong();
 
396
      break;
 
397
 
 
398
    case 3:
 
399
      mUsedTotal = answer.toLong();
 
400
      break;
 
401
 
 
402
    case 4:
 
403
      mUsedApplication = answer.toLong();
 
404
      s = i18n( " Memory: %1 / %2 " ,
 
405
                KGlobal::locale()->formatByteSize( mUsedApplication*1024),
 
406
                KGlobal::locale()->formatByteSize( (mFree+mUsedTotal)*1024 ) );
 
407
      statusBar()->changeItem( s, 2 );
 
408
      break;
 
409
 
 
410
    case 5:
 
411
      sFree = answer.toLong();
 
412
      break;
 
413
 
 
414
    case 6:
 
415
      sUsed = answer.toLong();
 
416
      setSwapInfo( sUsed, sFree, unit );
 
417
      break;
 
418
 
 
419
    case 7: {
 
420
      KSGRD::SensorIntegerInfo info( answer );
 
421
      unit = KSGRD::SensorMgr->translateUnit( info.unit() );
 
422
      break;
 
423
    }
 
424
  }
 
425
}
 
426
 
 
427
void TopLevel::setSwapInfo( long used, long free, const QString & )
 
428
{
 
429
  QString msg;
 
430
  if ( used == 0 && free == 0 ) // no swap available
 
431
    msg = i18n( " No swap space available " );
 
432
  else {
 
433
    msg = i18n( " Swap: %1 / %2 " ,
 
434
                KGlobal::locale()->formatByteSize( used*1024 ),
 
435
                KGlobal::locale()->formatByteSize( free*1024) );
 
436
  }
 
437
 
 
438
  statusBar()->changeItem( msg, 3 );
 
439
}
 
440
 
 
441
/*
 
442
 * Once upon a time...
 
443
 */
 
444
extern "C" KDE_EXPORT int kdemain( int argc, char** argv )
 
445
{
 
446
  // initpipe is used to keep the parent process around till the child
 
447
  // has registered with dbus
 
448
#ifdef FORK_KSYSGUARD
 
449
  int initpipe[ 2 ];
 
450
  pipe( initpipe );
 
451
#endif
 
452
  /* This forking will put ksysguard in it's own session not having a
 
453
   * controlling terminal attached to it. This prevents ssh from
 
454
   * using this terminal for password requests. Thus, you
 
455
   * need a ssh with ssh-askpass support to popup an X dialog to
 
456
   * enter the password. */
 
457
#ifdef FORK_KSYSGUARD
 
458
  pid_t pid;
 
459
  if ( ( pid = fork() ) < 0 )
 
460
    return -1;
 
461
  else
 
462
    if ( pid != 0 ) {
 
463
      close( initpipe[ 1 ] );
 
464
 
 
465
      // wait till init is complete
 
466
      char c;
 
467
      while( read( initpipe[ 0 ], &c, 1 ) < 0 );
 
468
 
 
469
      // then exit
 
470
      close( initpipe[ 0 ] );
 
471
      exit( 0 );
 
472
    }
 
473
 
 
474
  close( initpipe[ 0 ] );
 
475
  setsid();
 
476
#endif
 
477
 
 
478
  KAboutData aboutData( "ksysguard", 0, ki18n( "System Monitor" ),
 
479
                        KSYSGUARD_VERSION, ki18n(Description), KAboutData::License_GPL,
 
480
                        ki18n( "(c) 1996-2006 The KDE System Monitor Developers" ) );
 
481
  aboutData.addAuthor( ki18n("John Tapsell"), ki18n("Current Maintainer"), "john.tapsell@kde.org" );
 
482
  aboutData.addAuthor( ki18n("Chris Schlaeger"), ki18n("Previous Maintainer"), "cs@kde.org" );
 
483
  aboutData.addAuthor( ki18n("Greg Martyn"), KLocalizedString(), "greg.martyn@gmail.com" );
 
484
  aboutData.addAuthor( ki18n("Tobias Koenig"), KLocalizedString(), "tokoe@kde.org" );
 
485
  aboutData.addAuthor( ki18n("Nicolas Leclercq"), KLocalizedString(), "nicknet@planete.net" );
 
486
  aboutData.addAuthor( ki18n("Alex Sanda"), KLocalizedString(), "alex@darkstart.ping.at" );
 
487
  aboutData.addAuthor( ki18n("Bernd Johannes Wuebben"), KLocalizedString(), "wuebben@math.cornell.edu" );
 
488
  aboutData.addAuthor( ki18n("Ralf Mueller"), KLocalizedString(), "rlaf@bj-ig.de" );
 
489
  aboutData.addAuthor( ki18n("Hamish Rodda"), KLocalizedString(), "rodda@kde.org" );
 
490
  aboutData.addAuthor( ki18n("Torsten Kasch"), ki18n( "Solaris Support\n"
 
491
                       "Parts derived (by permission) from the sunos5\n"
 
492
                       "module of William LeFebvre's \"top\" utility." ),
 
493
                       "tk@Genetik.Uni-Bielefeld.DE" );
 
494
 
 
495
  KCmdLineArgs::init( argc, argv, &aboutData );
 
496
 
 
497
  KCmdLineOptions options;
 
498
  options.add("+[worksheet]", ki18n( "Optional worksheet files to load" ));
 
499
  KCmdLineArgs::addCmdLineOptions( options );
 
500
  // initialize KDE application
 
501
  KApplication *app = new KApplication;
 
502
 
 
503
  KSGRD::SensorMgr = new KSGRD::SensorManager();
 
504
  KSGRD::Style = new KSGRD::StyleEngine();
 
505
 
 
506
 
 
507
#ifdef FORK_KSYSGUARD
 
508
  char c = 0;
 
509
  write( initpipe[ 1 ], &c, 1 );
 
510
  close( initpipe[ 1 ] );
 
511
#endif
 
512
  topLevel = new TopLevel();
 
513
 
 
514
  // create top-level widget
 
515
  if ( app->isSessionRestored() )
 
516
    topLevel->restore( 1 );
 
517
  else
 
518
  {
 
519
    topLevel->readProperties( KConfigGroup( KGlobal::config(), "MainWindow" ) );
 
520
  }
 
521
 
 
522
  topLevel->initStatusBar();
 
523
  topLevel->show();
 
524
  KSGRD::SensorMgr->setBroadcaster( topLevel );
 
525
 
 
526
  // run the application
 
527
  int result = app->exec();
 
528
 
 
529
  delete KSGRD::Style;
 
530
  delete KSGRD::SensorMgr;
 
531
  delete app;
 
532
 
 
533
  return result;
 
534
}
 
535
 
 
536
#include "ksysguard.moc"