ksysguard.cpp 19.7 KB
Newer Older
1
2
3
/*
    KSysGuard, the KDE System Guard

4
    Copyright (c) 2006 - 2008 John Tapsell <john.tapsell@kde.org>
5
6
    Copyright (c) 1999 - 2001 Chris Schlaeger <cs@kde.org>

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as
 published by the Free Software Foundation; either version 2 of
 the License or (at your option) version 3 or any later version
 accepted by the membership of KDE e.V. (or its successor approved
 by the membership of KDE e.V.), which shall act as a proxy 
 defined in Section 14 of version 3 of the license.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

    KSysGuard has been written with some source code and ideas from
    ktop (<1.0). Early versions of ktop have been written by Bernd
    Johannes Wuebben <wuebben@math.cornell.edu> and Nicolas Leclercq
    <nicknet@planete.net>.

*/

#include <assert.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

37
#include <k4aboutdata.h>
38
#include <kactioncollection.h>
39
#include <kapplication.h>
Hrvoje Senjan's avatar
Hrvoje Senjan committed
40
#include <KDBusService>
41
42
43
44
#include <kdebug.h>
#include <kedittoolbar.h>
#include <kglobal.h>
#include <kglobalsettings.h>
Laurent Montel's avatar
Laurent Montel committed
45
#include <QIcon>
Laurent Montel's avatar
Laurent Montel committed
46
#include <KLocalizedString>
47
48
49
50
#include <kmessagebox.h>
#include <ksgrd/SensorAgent.h>
#include <ksgrd/SensorManager.h>
#include <kstatusbar.h>
Aaron J. Seigo's avatar
Aaron J. Seigo committed
51
#include <kstandardaction.h>
52
53
#include <ktoggleaction.h>
#include <kurl.h>
Luboš Luňák's avatar
Luboš Luňák committed
54
#include <kwindowsystem.h>
55
56
#include <QSplitter>

57
#include <config-workspace.h>
Laurent Montel's avatar
Laurent Montel committed
58
#include <KFormat>
Laurent Montel's avatar
Laurent Montel committed
59
60
#include <QCommandLineParser>
#include <QCommandLineOption>
61
62
#include "SensorBrowser.h"
#include "Workspace.h"
John Tapsell's avatar
John Tapsell committed
63
#include "WorkSheet.h"
64
65
#include "StyleEngine.h"
#include "HostConnector.h"
66
#include "ProcessController.h"
67
#include "processui/ksysguardprocesslist.h"
68
69
70
71
72
73

#include "ksysguard.h"

//Comment out to stop ksysguard from forking.  Good for debugging
//#define FORK_KSYSGUARD

74
static const char Description[] = I18N_NOOP( "KDE System Monitor" );
75
TopLevel* Toplevel;
76

Urs Wolfer's avatar
Urs Wolfer committed
77
TopLevel::TopLevel()
78
  : KXmlGuiWindow( NULL, Qt::WindowFlags(KDE_DEFAULT_WINDOWFLAGS) | Qt::WindowContextHelpButtonHint)
79
{
Stephan Kulow's avatar
Stephan Kulow committed
80
  QDBusConnection::sessionBus().registerObject("/", this, QDBusConnection::ExportScriptableSlots);
81
  mTimerId = -1;
82
  mLocalProcessController = NULL;
83
84
85
86
87
88

  mSplitter = new QSplitter( this );
  mSplitter->setOrientation( Qt::Horizontal );
  mSplitter->setOpaqueResize( KGlobalSettings::opaqueResize() );
  setCentralWidget( mSplitter );

89
  mSensorBrowser = 0;
90
91

  mWorkSpace = new Workspace( mSplitter );
Laurent Montel's avatar
Laurent Montel committed
92
93
94
95
  connect( mWorkSpace, SIGNAL(setCaption(QString)),
           SLOT(setCaption(QString)) );
  connect( mWorkSpace, SIGNAL(currentChanged(int)),
           SLOT(currentTabChanged(int)) );
96
97
98
99

  /* Create the status bar. It displays some information about the
   * number of processes and the memory consumption of the local
   * host. */
Greg Martyn's avatar
Greg Martyn committed
100
  const int STATUSBAR_STRETCH=1;
Greg Martyn's avatar
Greg Martyn committed
101
102
103
104
105
106
107
108
109
110
111
112
113

  sbProcessCount = new QLabel();
  statusBar()->addWidget( sbProcessCount, STATUSBAR_STRETCH );

  sbCpuStat = new QLabel();
  statusBar()->addWidget( sbCpuStat, STATUSBAR_STRETCH );

  sbMemTotal = new QLabel();
  statusBar()->addWidget( sbMemTotal, STATUSBAR_STRETCH );

  sbSwapTotal = new QLabel();
  statusBar()->addWidget( sbSwapTotal, STATUSBAR_STRETCH );

114
115
  statusBar()->hide();

Greg Martyn's avatar
Greg Martyn committed
116
  // create actions for menu entries
Laurent Montel's avatar
Laurent Montel committed
117
  mRefreshTabAction = KStandardAction::redisplay(mWorkSpace,SLOT(refreshActiveWorksheet()),actionCollection());
118
  mNewWorksheetAction = actionCollection()->addAction("new_worksheet");
Laurent Montel's avatar
Laurent Montel committed
119
  mNewWorksheetAction->setIcon(QIcon::fromTheme("tab-new"));
Laurent Montel's avatar
Laurent Montel committed
120
  connect(mNewWorksheetAction, SIGNAL(triggered(bool)), mWorkSpace, SLOT(newWorkSheet()));
121
  mInsertWorksheetAction = actionCollection()->addAction("import_worksheet");
Laurent Montel's avatar
Laurent Montel committed
122
  mInsertWorksheetAction->setIcon(QIcon::fromTheme("document-open") );
Laurent Montel's avatar
Laurent Montel committed
123
  connect(mInsertWorksheetAction, SIGNAL(triggered(bool)), mWorkSpace, SLOT(importWorkSheet()));
124
  mTabExportAction = actionCollection()->addAction( "export_worksheet" );
Laurent Montel's avatar
Laurent Montel committed
125
  mTabExportAction->setIcon( QIcon::fromTheme("document-save-as") );
Laurent Montel's avatar
Laurent Montel committed
126
  connect(mTabExportAction, SIGNAL(triggered(bool)), mWorkSpace, SLOT(exportWorkSheet()));
127
  mTabRemoveAction = actionCollection()->addAction( "remove_worksheet" );
Laurent Montel's avatar
Laurent Montel committed
128
  mTabRemoveAction->setIcon( QIcon::fromTheme("tab-close") );
Laurent Montel's avatar
Laurent Montel committed
129
  connect(mTabRemoveAction, SIGNAL(triggered(bool)), mWorkSpace, SLOT(removeWorkSheet()));
130
  mMonitorRemoteAction = actionCollection()->addAction( "connect_host" );
Laurent Montel's avatar
Laurent Montel committed
131
  mMonitorRemoteAction->setIcon( QIcon::fromTheme("network-connect") );
Laurent Montel's avatar
Laurent Montel committed
132
  connect(mMonitorRemoteAction, SIGNAL(triggered(bool)), SLOT(connectHost()));
133
  //knewstuff2 action
134
  mHotNewWorksheetAction = actionCollection()->addAction( "get_new_worksheet" );
Laurent Montel's avatar
Laurent Montel committed
135
  mHotNewWorksheetAction->setIcon( QIcon::fromTheme("network-server") );
Laurent Montel's avatar
Laurent Montel committed
136
  connect(mHotNewWorksheetAction, SIGNAL(triggered(bool)), mWorkSpace, SLOT(getHotNewWorksheet()));
137
  mHotNewWorksheetUploadAction = actionCollection()->addAction( "upload_worksheet" );
Laurent Montel's avatar
Laurent Montel committed
138
  mHotNewWorksheetUploadAction->setIcon( QIcon::fromTheme("network-server") );
Laurent Montel's avatar
Laurent Montel committed
139
  connect(mHotNewWorksheetUploadAction, SIGNAL(triggered(bool)), mWorkSpace, SLOT(uploadHotNewWorksheet()));
140
141

  mQuitAction = NULL;
142

143
  mConfigureSheetAction = actionCollection()->addAction( "configure_sheet" );
Laurent Montel's avatar
Laurent Montel committed
144
  mConfigureSheetAction->setIcon( QIcon::fromTheme("configure") );
Laurent Montel's avatar
Laurent Montel committed
145
  connect(mConfigureSheetAction, SIGNAL(triggered(bool)), SLOT(configureCurrentSheet()));
146

147
  retranslateUi();
148
149
}

150
151
152
153
154
155
156
157
158
159
void TopLevel::setLocalProcessController(ProcessController * localProcessController)
{
  Q_ASSERT(!mLocalProcessController);
  mLocalProcessController = localProcessController;
  connect( mLocalProcessController, SIGNAL(processListChanged()), this, SLOT(updateProcessCount()));
  for(int i = 0; i < mLocalProcessController->actions().size(); i++) {
    actionCollection()->addAction("processAction" + QString::number(i), mLocalProcessController->actions().at(i));
  }
}

160
161
162
void TopLevel::retranslateUi()
{
  setPlainCaption( i18n( "System Monitor" ) );
163
  mRefreshTabAction->setText(i18n("&Refresh Tab"));
164
165
166
167
168
169
  mNewWorksheetAction->setText(i18n( "&New Tab..." ));
  mInsertWorksheetAction->setText(i18n( "Import Tab Fr&om File..." ));
  mTabExportAction->setText( i18n( "Save Tab &As..." ) );
  mTabRemoveAction->setText( i18n( "&Close Tab" ) );
  mMonitorRemoteAction->setText( i18n( "Monitor &Remote Machine..." ) );
  mHotNewWorksheetAction->setText( i18n( "&Download New Tabs..." ) );
170
171
  mHotNewWorksheetUploadAction->setText( i18n( "&Upload Current Tab..." ) );

172
  mConfigureSheetAction->setText( i18n( "Tab &Properties" ) );
173
  if(mQuitAction) {
174
    QAction *tmpQuitAction = KStandardAction::quit( NULL, NULL, NULL );
175
176
177
    mQuitAction->setText(tmpQuitAction->text());
    mQuitAction->setWhatsThis(tmpQuitAction->whatsThis());
    mQuitAction->setToolTip(tmpQuitAction->toolTip());
John Tapsell's avatar
John Tapsell committed
178
    delete tmpQuitAction;
179
  } else
Laurent Montel's avatar
Laurent Montel committed
180
    mQuitAction = KStandardAction::quit( this, SLOT(close()), actionCollection() );
181
182
}

183
184
185
186
void TopLevel::configureCurrentSheet() {
  mWorkSpace->configure();
  mRefreshTabAction->setVisible( mWorkSpace->currentWorkSheet()->updateInterval() == 0 );
}
John Tapsell's avatar
John Tapsell committed
187
188
189
190
191
192
193
194
void TopLevel::currentTabChanged(int index)
{
  QWidget *wdg = mWorkSpace->widget(index);
  WorkSheet *sheet = (WorkSheet *)(wdg);
  Q_ASSERT(sheet);
  bool locked = !sheet || sheet->isLocked();
  mTabRemoveAction->setVisible(!locked);
  mTabExportAction->setVisible(!locked);
195
  mHotNewWorksheetUploadAction->setVisible(!locked);
196
197
  mMonitorRemoteAction->setVisible(!locked);

198
199
200
  //only show refresh option is update interval is 0 (manual)
  mRefreshTabAction->setVisible( sheet->updateInterval() == 0 );

201
  if(!locked && !mSensorBrowser) {
202
    startSensorBrowserWidget();
203
  }
204
205
206
  if(mSensorBrowser) {
    if(mSensorBrowser->isVisible() && locked) //going from visible to not visible to save the state
      mSplitterSize = mSplitter->sizes();
207
    mSensorBrowser->setVisible(!locked);
208

209
210
211
212
213
214
  }
}
void TopLevel::startSensorBrowserWidget()
{
  if(mSensorBrowser) return;
  mSensorBrowser = new SensorBrowserWidget( 0, KSGRD::SensorMgr );
215
  mSplitter->insertWidget(2,mSensorBrowser);
216
  mSplitter->setSizes( mSplitterSize );
John Tapsell's avatar
John Tapsell committed
217
}
218
219

/*
220
 * DBUS Interface functions
221
222
223
224
 */

void TopLevel::showOnCurrentDesktop()
{
Luboš Luňák's avatar
Luboš Luňák committed
225
  KWindowSystem::setOnDesktop( winId(), KWindowSystem::currentDesktop() );
226
  kapp->updateUserTimestamp();
Luboš Luňák's avatar
Luboš Luňák committed
227
  KWindowSystem::forceActiveWindow( winId() );
228
229
}

230
void TopLevel::importWorkSheet( const QString &fileName )
231
{
232
  mWorkSpace->importWorkSheet( KUrl( fileName ) );
233
234
235
236
}

void TopLevel::removeWorkSheet( const QString &fileName )
{
237
  mWorkSpace->removeWorkSheet( fileName );
238
239
}

240
void TopLevel::getHotNewWorksheet()
241
{
242
  mWorkSpace->getHotNewWorksheet( );
243
244
}

245
246
QStringList TopLevel::listSensors( const QString &hostName )
{
247
248
249
250
251
252
  if(!mSensorBrowser) {
    setUpdatesEnabled(false);
    startSensorBrowserWidget();
    mSensorBrowser->setVisible(false);
    setUpdatesEnabled(true);
  }
253
  return mSensorBrowser->listSensors( hostName );
254
255
256
257
}

QStringList TopLevel::listHosts()
{
258
259
260
261
262
263
  if(!mSensorBrowser) {
    setUpdatesEnabled(false);
    startSensorBrowserWidget();
    mSensorBrowser->setVisible(false);
    setUpdatesEnabled(true);
  }
264
  return mSensorBrowser->listHosts();
265
266
267
268
269
270
271
272
273
}

void TopLevel::initStatusBar()
{
  KSGRD::SensorMgr->engage( "localhost", "", "ksysguardd" );
  /* Request info about the swap space size and the units it is
   * measured in.  The requested info will be received by
   * answerReceived(). */
  KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/used?",
Greg Martyn's avatar
GUI:    
Greg Martyn committed
274
                                 (KSGRD::SensorClient*)this, 7 );
275
276
277
278

  KToggleAction *sb = dynamic_cast<KToggleAction*>(action("options_show_statusbar"));
  if (sb)
     connect(sb, SIGNAL(toggled(bool)), this, SLOT(updateStatusBar()));
John Tapsell's avatar
John Tapsell committed
279
  setupGUI(QSize(800,600), ToolBar | Keys | StatusBar | Save | Create);
280
281

  updateStatusBar();
282
283
284
285
286
287
288
289
290
291
292
293
294
}

void TopLevel::updateStatusBar()
{
  if ( mTimerId == -1 )
    mTimerId = startTimer( 2000 );

  // call timerEvent to fill the status bar with real values
  timerEvent( 0 );
}

void TopLevel::connectHost()
{
295
  HostConnector hostConnector( this );
296

297
298
299
300
301
302
303
304
305
306
//  hostConnector.setHostNames( mHostList );
//  hostConnector.setCommands( mCommandList );

//  hostConnector.setCurrentHostName( "" );

  if ( !hostConnector.exec() )
    return;

//  mHostList = hostConnector.hostNames();
//  mCommandList = hostConnector.commands();
307

308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  QString shell = "";
  QString command = "";
  int port = -1;

  /* Check which radio button is selected and set parameters
   * appropriately. */
  if ( hostConnector.useSsh() )
    shell = "ssh";
  else if ( hostConnector.useRsh() )
    shell = "rsh";
  else if ( hostConnector.useDaemon() )
    port = hostConnector.port();
  else
    command = hostConnector.currentCommand();

  KSGRD::SensorMgr->engage( hostConnector.currentHostName(), shell, command, port );
324
325
326
327
}

void TopLevel::disconnectHost()
{
328
329
  if(mSensorBrowser)
    mSensorBrowser->disconnect();
330
331
}

332
bool TopLevel::event( QEvent *e )
333
334
335
336
337
{
  if ( e->type() == QEvent::User ) {
    /* Due to the asynchronous communication between ksysguard and its
     * back-ends, we sometimes need to show message boxes that were
     * triggered by objects that have died already. */
Kevin Ottens's avatar
Kevin Ottens committed
338
    KMessageBox::error( this, static_cast<KSGRD::SensorManager::MessageEvent*>(e)->message() );
339
340

    return true;
341
  }
342

343
  return KXmlGuiWindow::event( e );
344
345
346
347
348
349
350
}

void TopLevel::timerEvent( QTimerEvent* )
{
  if ( statusBar()->isVisibleTo( this ) ) {
    /* Request some info about the memory status. The requested
     * information will be received by answerReceived(). */
351
    KSGRD::SensorMgr->sendRequest( "localhost", "cpu/idle",
352
                                   (KSGRD::SensorClient*)this, 1 );
Greg Martyn's avatar
GUI:    
Greg Martyn committed
353
    KSGRD::SensorMgr->sendRequest( "localhost", "mem/physical/free",
354
                                   (KSGRD::SensorClient*)this, 2 );
Greg Martyn's avatar
GUI:    
Greg Martyn committed
355
    KSGRD::SensorMgr->sendRequest( "localhost", "mem/physical/used",
356
                                   (KSGRD::SensorClient*)this, 3 );
357
    KSGRD::SensorMgr->sendRequest( "localhost", "mem/physical/application",
Greg Martyn's avatar
GUI:    
Greg Martyn committed
358
359
360
361
                                   (KSGRD::SensorClient*)this, 4 );
    KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/free",
                                   (KSGRD::SensorClient*)this, 5 );
    KSGRD::SensorMgr->sendRequest( "localhost", "mem/swap/used",
362
                                   (KSGRD::SensorClient*)this, 6 );
363
364
365
  }
}

366
void TopLevel::updateProcessCount()  {
367
    const QString s = i18np( "1 process" "\xc2\x9c" "1", "%1 processes" "\xc2\x9c" "%1", mLocalProcessController->processList()->visibleProcessesCount() );
368
369
    sbProcessCount->setText( s );
}
370
void TopLevel::changeEvent( QEvent * event )
371
372
373
{
  if (event->type() == QEvent::LanguageChange) {
    KSGRD::SensorMgr->retranslate();
374
375
376
377
    setUpdatesEnabled(false);
    setupGUI(ToolBar | Keys | StatusBar | Create);
    retranslateUi();
    setUpdatesEnabled(true);
378
379
380
381
  }
  KXmlGuiWindow::changeEvent(event);
}

382
383
384
385
386
bool TopLevel::queryClose()
{
  if ( !mWorkSpace->saveOnQuit() )
    return false;

Laurent Montel's avatar
Laurent Montel committed
387
  KConfigGroup cg( KSharedConfig::openConfig(), "MainWindow" );
388
  saveProperties( cg );
Laurent Montel's avatar
Laurent Montel committed
389
  KSharedConfig::openConfig()->sync();
390
391
392
393

  return true;
}

394
void TopLevel::readProperties( const KConfigGroup& cfg )
395
396
397
398
{

  /* we can ignore 'isMaximized' because we can't set the window
     maximized, so we save the coordinates instead */
399
400
//  if ( cfg.readEntry( "isMinimized" , false) == true )
//    showMinimized();
401

402
  mSplitterSize = cfg.readEntry( "SplitterSizeList",QList<int>() );
403
  if ( mSplitterSize.isEmpty() ) {
404
    // start with a 30/70 ratio
405
406
    mSplitterSize.append( 10 );
    mSplitterSize.append( 90 );
407
  }
408
409
410
411
412
413
414

  KSGRD::SensorMgr->readProperties( cfg );
  KSGRD::Style->readProperties( cfg );

  mWorkSpace->readProperties( cfg );
}

415
void TopLevel::saveProperties( KConfigGroup& cfg )
416
{
417
  cfg.writeEntry( "isMinimized", isMinimized() );
418

419
  if(mSensorBrowser && mSensorBrowser->isVisible())
420
    cfg.writeEntry( "SplitterSizeList",  mSplitter->sizes());
421
  else if(mSplitterSize.size() == 2 && mSplitterSize.value(0) != 0 && mSplitterSize.value(1) != 0)
422
    cfg.writeEntry( "SplitterSizeList", mSplitterSize );
423
424
425
426
427
428
429
430

  KSGRD::Style->saveProperties( cfg );
  KSGRD::SensorMgr->saveProperties( cfg );

  saveMainWindowSettings( cfg );
  mWorkSpace->saveProperties( cfg );
}

431
void TopLevel::answerReceived( int id, const QList<QByteArray> &answerList )
432
433
{
  // we have received an answer from the daemon.
434
  QByteArray answer;
435
436
437
  if(!answerList.isEmpty()) answer = answerList[0];
  QString s;
  static QString unit;
438
439
440
441
442
  static qlonglong mFree = 0;
  static qlonglong mUsedApplication = 0;
  static qlonglong mUsedTotal = 0;
  static qlonglong sUsed = 0;
  static qlonglong sFree = 0;
443
444
445

  switch ( id ) {
    case 1:
446
      s = i18n( "CPU: %1%\xc2\x9c%1%", (int) (100 - answer.toFloat()) );
Greg Martyn's avatar
Greg Martyn committed
447
      sbCpuStat->setText( s );
448
449
450
      break;

    case 2:
451
      mFree = answer.toLongLong();
452
453
454
      break;

    case 3:
455
      mUsedTotal = answer.toLongLong();
456
457
458
      break;

    case 4:
459
      mUsedApplication = answer.toLongLong();
460
461
      //Use a multi-length string
      s = i18nc( "Arguments are formatted byte sizes (used/total)", "Memory: %1 / %2" "\xc2\x9c" "Mem: %1 / %2" "\xc2\x9c" "Mem: %1" "\xc2\x9c" "%1",
Laurent Montel's avatar
Laurent Montel committed
462
463
                 KFormat().formatByteSize( mUsedApplication*1024),
                 KFormat().formatByteSize( (mFree+mUsedTotal)*1024 ) );
Greg Martyn's avatar
Greg Martyn committed
464
      sbMemTotal->setText( s );
Greg Martyn's avatar
GUI:    
Greg Martyn committed
465
466
467
      break;

    case 5:
468
      sFree = answer.toLongLong();
Greg Martyn's avatar
GUI:    
Greg Martyn committed
469
470
471
      break;

    case 6:
472
      sUsed = answer.toLongLong();
473
      setSwapInfo( sUsed, sFree, unit );
474
475
      break;

Greg Martyn's avatar
GUI:    
Greg Martyn committed
476
    case 7: {
477
478
      KSGRD::SensorIntegerInfo info( answer );
      unit = KSGRD::SensorMgr->translateUnit( info.unit() );
479
      break;
480
481
482
483
    }
  }
}

484
void TopLevel::setSwapInfo( qlonglong used, qlonglong free, const QString & )
485
486
487
{
  QString msg;
  if ( used == 0 && free == 0 ) // no swap available
Greg Martyn's avatar
GUI:    
Greg Martyn committed
488
    msg = i18n( " No swap space available " );
489
  else {
490
    msg = i18nc( "Arguments are formatted byte sizes (used/total)", "Swap: %1 / %2" "\xc2\x9c" "Swap: %1" "\xc2\x9c" "%1" ,
Laurent Montel's avatar
Laurent Montel committed
491
492
                 KFormat().formatByteSize( used*1024 ),
                 KFormat().formatByteSize( (free+used)*1024) );
493
494
  }

Greg Martyn's avatar
Greg Martyn committed
495
  sbSwapTotal->setText( msg );
496
497
498
499
500
}

/*
 * Once upon a time...
 */
501
extern "C" Q_DECL_EXPORT int kdemain( int argc, char** argv )
502
503
{
  // initpipe is used to keep the parent process around till the child
504
  // has registered with dbus
505
506
#ifdef FORK_KSYSGUARD
  int initpipe[ 2 ];
John Tapsell's avatar
John Tapsell committed
507
  pipe( initpipe );
508
509
  /* This forking will put ksysguard in it's own session not having a
   * controlling terminal attached to it. This prevents ssh from
510
511
512
   * using this terminal for password requests. Thus, you
   * need a ssh with ssh-askpass support to popup an X dialog to
   * enter the password. */
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
  pid_t pid;
  if ( ( pid = fork() ) < 0 )
    return -1;
  else
    if ( pid != 0 ) {
      close( initpipe[ 1 ] );

      // wait till init is complete
      char c;
      while( read( initpipe[ 0 ], &c, 1 ) < 0 );

      // then exit
      close( initpipe[ 0 ] );
      exit( 0 );
    }

  close( initpipe[ 0 ] );
  setsid();
#endif

Lasse Liehu's avatar
Lasse Liehu committed
533
534
  QApplication app(argc, argv);

Laurent Montel's avatar
Laurent Montel committed
535
536
537
  KAboutData aboutData( "ksysguard", i18n( "System Monitor" ),
                        PROJECT_VERSION, i18n(Description), KAboutLicense::GPL,
                        i18n( "(c) 1996-2008 The KDE System Monitor Developers" ) );
Hrvoje Senjan's avatar
Hrvoje Senjan committed
538
  aboutData.setOrganizationDomain(QByteArray("kde.org"));
Laurent Montel's avatar
Laurent Montel committed
539
540
541
542
543
544
545
546
547
548
  aboutData.addAuthor( i18n("John Tapsell"), i18n("Current Maintainer"), "john.tapsell@kde.org" );
  aboutData.addAuthor( i18n("Chris Schlaeger"), i18n("Previous Maintainer"), "cs@kde.org" );
  aboutData.addAuthor( i18n("Greg Martyn"), QString(), "greg.martyn@gmail.com" );
  aboutData.addAuthor( i18n("Tobias Koenig"), QString(), "tokoe@kde.org" );
  aboutData.addAuthor( i18n("Nicolas Leclercq"), QString(), "nicknet@planete.net" );
  aboutData.addAuthor( i18n("Alex Sanda"), QString(), "alex@darkstart.ping.at" );
  aboutData.addAuthor( i18n("Bernd Johannes Wuebben"), QString(), "wuebben@math.cornell.edu" );
  aboutData.addAuthor( i18n("Ralf Mueller"), QString(), "rlaf@bj-ig.de" );
  aboutData.addAuthor( i18n("Hamish Rodda"), QString(), "rodda@kde.org" );
  aboutData.addAuthor( i18n("Torsten Kasch"), i18n( "Solaris Support\n"
549
550
551
552
                       "Parts derived (by permission) from the sunos5\n"
                       "module of William LeFebvre's \"top\" utility." ),
                       "tk@Genetik.Uni-Bielefeld.DE" );

Laurent Montel's avatar
Laurent Montel committed
553
554
555
556
557
558
559
560
561
    QCommandLineParser parser;
    KAboutData::setApplicationData(aboutData);
    parser.addVersionOption();
    parser.addHelpOption();
    parser.addPositionalArgument(QLatin1String("[worksheet]"), i18n( "Optional worksheet files to load" ));

    aboutData.setupCommandLine(&parser);
    parser.process(app);
    aboutData.processCommandLine(&parser);
562

Laurent Montel's avatar
Laurent Montel committed
563
  app.setWindowIcon(QIcon::fromTheme("utilities-system-monitor"));
John Tapsell's avatar
John Tapsell committed
564

565
566
567
568
  KSGRD::SensorMgr = new KSGRD::SensorManager();
  KSGRD::Style = new KSGRD::StyleEngine();

#ifdef FORK_KSYSGUARD
569
570
571
  char c = 0;
  write( initpipe[ 1 ], &c, 1 );
  close( initpipe[ 1 ] );
572
#endif
573
  Toplevel = new TopLevel();
574

John Tapsell's avatar
John Tapsell committed
575

576
  // create top-level widget
Laurent Montel's avatar
Laurent Montel committed
577
  Toplevel->readProperties( KConfigGroup( KSharedConfig::openConfig(), "MainWindow" ) );
578
579
580
  // setup the statusbar, toolbar etc.
  // Note that this comes after creating the top-level widgets whcih also 
  // sets up the various QActions that the user may have added to the toolbar
581
  Toplevel->initStatusBar();
John Tapsell's avatar
John Tapsell committed
582

583
584
  //There seems to be some serious bugs with the session restore code.  Disabling
//  if ( app->isSessionRestored() )
585
//    Toplevel->restore( 1 );
586

587
588
  Toplevel->show();
  KSGRD::SensorMgr->setBroadcaster( Toplevel );  // SensorMgr uses a QPointer for toplevel, so it is okay if Toplevel is deleted first
589

Hrvoje Senjan's avatar
Hrvoje Senjan committed
590
591
592
  // register to DBus
  const KDBusService dbusService(KDBusService::Multiple);

593
  // run the application
Laurent Montel's avatar
Laurent Montel committed
594
  int result = app.exec();
595

John Tapsell's avatar
John Tapsell committed
596
597
  delete KSGRD::SensorMgr;
  delete KSGRD::Style;
598
599
600
601

  return result;
}

602