not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kdm / kfrontend / kdmshutdown.cpp
blobe21e335b788ab68c5f8b9aec774be5fb6da62ab2
1 /*
3 Shutdown dialog
5 Copyright (C) 1997, 1998, 2000 Steffen Hansen <hansen@kde.org>
6 Copyright (C) 2000-2003,2005 Oswald Buddenhagen <ossi@kde.org>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25 #include "kdmshutdown.h"
26 #include "kdm_greet.h"
27 #include "utils.h"
29 #include <kdialog.h>
30 #include <klocale.h>
31 #include <kprocess.h>
32 #include <kseparator.h>
33 #include <kstandarddirs.h>
34 #include <KStandardGuiItem>
35 #include <kuser.h>
37 #include <QAction>
38 #include <QApplication>
39 #include <QCheckBox>
40 #include <QComboBox>
41 #include <QDateTime>
42 #include <QFrame>
43 #include <QGroupBox>
44 #include <QHeaderView>
45 #include <QLabel>
46 #include <QLineEdit>
47 #include <QMenu>
48 #include <QStylePainter>
49 #include <QStyle>
50 #include <QTreeWidget>
51 #include <QTreeWidgetItem>
53 #include <stdlib.h>
55 int KDMShutdownBase::curPlugin = -1;
56 PluginList KDMShutdownBase::pluginList;
58 KDMShutdownBase::KDMShutdownBase( int _uid, QWidget *_parent )
59 : inherited( _parent )
60 , box( new QVBoxLayout( this ) )
61 #ifdef HAVE_VTS
62 , willShut( true )
63 #endif
64 , mayNuke( false )
65 , doesNuke( false )
66 , mayOk( true )
67 , maySched( false )
68 , rootlab( 0 )
69 , verify( 0 )
70 , needRoot( -1 )
71 , uid( _uid )
75 KDMShutdownBase::~KDMShutdownBase()
77 hide();
78 delete verify;
81 void
82 KDMShutdownBase::complete( QWidget *prevWidget )
84 QSizePolicy fp( QSizePolicy::Fixed, QSizePolicy::Fixed );
86 if (uid &&
87 ((willShut && _allowShutdown == SHUT_ROOT) ||
88 (mayNuke && _allowNuke == SHUT_ROOT)))
90 rootlab = new QLabel( i18n("Root authorization required."), this );
91 box->addWidget( rootlab );
92 if (curPlugin < 0) {
93 curPlugin = 0;
94 pluginList = KGVerify::init( _pluginsShutdown );
96 verify = new KGStdVerify( this, this,
97 prevWidget, "root",
98 pluginList, KGreeterPlugin::Authenticate,
99 KGreeterPlugin::Shutdown );
100 verify->selectPlugin( curPlugin );
101 box->addLayout( verify->getLayout() );
102 QAction *action = new QAction( this );
103 action->setShortcut( Qt::ALT+Qt::Key_A );
104 connect( action, SIGNAL(triggered( bool )), SLOT(slotActivatePlugMenu()) );
107 box->addWidget( new KSeparator( Qt::Horizontal, this ) );
109 QBoxLayout *hlay = new QHBoxLayout();
110 box->addLayout( hlay );
111 hlay->addStretch( 1 );
112 if (mayOk) {
113 okButton = new KPushButton( KStandardGuiItem::ok(), this );
114 okButton->setSizePolicy( fp );
115 okButton->setDefault( true );
116 hlay->addWidget( okButton );
117 hlay->addStretch( 1 );
118 connect( okButton, SIGNAL(clicked()), SLOT(accept()) );
120 if (maySched) {
121 KPushButton *schedButton =
122 new KPushButton( KGuiItem( i18nc("@action:inmenu verb", "&Schedule...") ), this );
123 schedButton->setSizePolicy( fp );
124 hlay->addWidget( schedButton );
125 hlay->addStretch( 1 );
126 connect( schedButton, SIGNAL(clicked()), SLOT(slotSched()) );
128 cancelButton = new KPushButton( KStandardGuiItem::cancel(), this );
129 cancelButton->setSizePolicy( fp );
130 if (!mayOk)
131 cancelButton->setDefault( true );
132 hlay->addWidget( cancelButton );
133 hlay->addStretch( 1 );
134 connect( cancelButton, SIGNAL(clicked()), SLOT(reject()) );
136 updateNeedRoot();
138 adjustSize();
139 layout()->activate();
142 void
143 KDMShutdownBase::slotActivatePlugMenu()
145 if (needRoot) {
146 QMenu *cmnu = verify->getPlugMenu();
147 if (!cmnu)
148 return;
149 QSize sh( cmnu->sizeHint() / 2 );
150 cmnu->exec( geometry().center() - QPoint( sh.width(), sh.height() ) );
154 void
155 KDMShutdownBase::accept()
157 if (needRoot == 1)
158 verify->accept();
159 else
160 accepted();
163 void
164 KDMShutdownBase::slotSched()
166 done( Schedule );
169 void
170 KDMShutdownBase::updateNeedRoot()
172 int nNeedRoot = uid &&
173 (((willShut && _allowShutdown == SHUT_ROOT) ||
174 (_allowNuke == SHUT_ROOT && doesNuke)));
175 if (verify && nNeedRoot != needRoot) {
176 if (needRoot == 1)
177 verify->abort();
178 needRoot = nNeedRoot;
179 rootlab->setEnabled( needRoot );
180 verify->setEnabled( needRoot );
181 if (needRoot)
182 verify->start();
186 void
187 KDMShutdownBase::accepted()
189 inherited::done( needRoot ? (int)Authed : (int)Accepted );
192 void
193 KDMShutdownBase::verifyPluginChanged( int id )
195 curPlugin = id;
196 adjustSize();
199 void
200 KDMShutdownBase::verifyOk()
202 accepted();
205 void
206 KDMShutdownBase::verifyFailed()
208 okButton->setEnabled( false );
209 cancelButton->setEnabled( false );
212 void
213 KDMShutdownBase::verifyRetry()
215 okButton->setEnabled( true );
216 cancelButton->setEnabled( true );
219 void
220 KDMShutdownBase::verifySetUser( const QString & )
225 static void
226 doShutdown( int type, const QString &os )
228 gSet( 1 );
229 gSendInt( G_Shutdown );
230 gSendInt( type );
231 gSendInt( 0 );
232 gSendInt( 0 );
233 gSendInt( SHUT_FORCE );
234 gSendInt( 0 ); /* irrelevant, will timeout immediately anyway */
235 gSendStr( os.toUtf8().data() );
236 gSet( 0 );
240 static bool
241 getBootOptions( QStringList *options, int *defaultTarget, int *oldTarget )
243 bool ret = false;
244 gSet( 1 );
245 gSendInt( G_ListBootOpts );
246 if (gRecvInt() == BO_OK) {
247 *options = qStringList( gRecvStrArr( 0 ) );
248 *defaultTarget = gRecvInt();
249 *oldTarget = gRecvInt();
250 ret = true;
252 gSet( 0 );
253 return ret;
256 KDMShutdown::KDMShutdown( int _uid, QWidget *_parent )
257 : inherited( _uid, _parent )
259 QSizePolicy fp( QSizePolicy::Fixed, QSizePolicy::Fixed );
261 QHBoxLayout *hlay = new QHBoxLayout();
262 box->addLayout( hlay );
264 howGroup = new QGroupBox( i18n("Shutdown Type"), this );
265 hlay->addWidget( howGroup, 0, Qt::AlignTop );
267 QRadioButton *rb;
268 rb = new KDMRadioButton( i18n("&Turn off computer"), howGroup );
269 rb->setChecked( true );
270 rb->setFocus();
272 restart_rb = new KDMRadioButton( i18n("&Restart computer"), howGroup );
274 QBoxLayout *hwlay = new QVBoxLayout( howGroup );
275 hwlay->addWidget( rb );
276 hwlay->addWidget( restart_rb );
278 connect( rb, SIGNAL(doubleClicked()), SLOT(accept()) );
279 connect( restart_rb, SIGNAL(doubleClicked()), SLOT(accept()) );
281 QStringList options;
282 int defaultTarget;
283 if (getBootOptions( &options, &defaultTarget, &oldTarget )) { /* XXX show dialog on failure */
284 targets = new QComboBox();
285 targets->addItems( options );
286 targets->setCurrentIndex( oldTarget == -1 ? defaultTarget : oldTarget );
287 QHBoxLayout *hb = new QHBoxLayout();
288 hwlay->addLayout( hb );
289 hb->addSpacing(
290 style()->pixelMetric( QStyle::PM_ExclusiveIndicatorWidth )
291 + hb->spacing() );
292 hb->addWidget( targets );
293 connect( targets, SIGNAL(activated( int )), SLOT(slotTargetChanged()) );
296 howGroup->setSizePolicy( fp );
298 schedGroup = new QGroupBox( i18nc("@title:group ... of shutdown", "Scheduling"), this );
299 hlay->addWidget( schedGroup, 0, Qt::AlignTop );
301 le_start = new QLineEdit( schedGroup );
302 QLabel *lab1 = new QLabel( i18n("&Start:"), schedGroup );
303 lab1->setBuddy( le_start );
305 le_timeout = new QLineEdit( schedGroup );
306 QLabel *lab2 = new QLabel( i18n("T&imeout:"), schedGroup );
307 lab2->setBuddy( le_timeout );
309 cb_force = new QCheckBox( i18n("&Force after timeout"), schedGroup );
310 if (_allowNuke != SHUT_NONE) {
311 connect( cb_force, SIGNAL(clicked()), SLOT(slotWhenChanged()) );
312 mayNuke = true;
313 } else
314 cb_force->setEnabled( false );
316 QGridLayout *grid = new QGridLayout( schedGroup );
317 grid->addWidget( lab1, 0, 0, Qt::AlignRight );
318 grid->addWidget( le_start, 0, 1 );
319 grid->addWidget( lab2, 1, 0, Qt::AlignRight );
320 grid->addWidget( le_timeout, 1, 1 );
321 grid->addWidget( cb_force, 2, 0, 1, 2 );
323 schedGroup->setSizePolicy( fp );
325 le_start->setText( "0" );
326 if (_defSdMode == SHUT_SCHEDULE)
327 le_timeout->setText( "-1" );
328 else {
329 le_timeout->setText( "0" );
330 if (_defSdMode == SHUT_FORCENOW && cb_force->isEnabled())
331 cb_force->setChecked( true );
334 complete( schedGroup );
337 static int
338 getDate( const char *str )
340 KProcess prc;
341 prc.setOutputChannelMode( KProcess::OnlyStdoutChannel );
342 prc << "/bin/date" << "+%s" << "-d" << str;
343 if (prc.execute())
344 return -1;
345 return prc.readAll().simplified().toInt();
348 void
349 KDMShutdown::accept()
351 if (le_start->text() == "0" || le_start->text() == "now")
352 sch_st = time( 0 );
353 else if (le_start->text()[0] == '+')
354 sch_st = time( 0 ) + le_start->text().toInt();
355 else if ((sch_st = getDate( le_start->text().toLatin1() )) < 0) {
356 KFMsgBox::box( this, errorbox, i18n("Entered start date is invalid.") );
357 le_start->setFocus();
358 return;
360 if (le_timeout->text() == "-1" || le_timeout->text().startsWith( "inf" ))
361 sch_to = TO_INF;
362 else if (le_timeout->text()[0] == '+')
363 sch_to = sch_st + le_timeout->text().toInt();
364 else if ((sch_to = getDate( le_timeout->text().toLatin1() )) < 0) {
365 KFMsgBox::box( this, errorbox, i18n("Entered timeout date is invalid.") );
366 le_timeout->setFocus();
367 return;
370 inherited::accept();
373 void
374 KDMShutdown::slotTargetChanged()
376 restart_rb->setChecked( true );
379 void
380 KDMShutdown::slotWhenChanged()
382 doesNuke = cb_force->isChecked();
383 updateNeedRoot();
386 void
387 KDMShutdown::accepted()
389 gSet( 1 );
390 gSendInt( G_Shutdown );
391 gSendInt( restart_rb->isChecked() ? SHUT_REBOOT : SHUT_HALT );
392 gSendInt( sch_st );
393 gSendInt( sch_to );
394 gSendInt( cb_force->isChecked() ? SHUT_FORCE : SHUT_CANCEL );
395 gSendInt( _allowShutdown == SHUT_ROOT ? 0 : -2 );
396 gSendStr( (restart_rb->isChecked() &&
397 targets && targets->currentIndex() != oldTarget) ?
398 targets->currentText().toLocal8Bit().data() : 0 );
399 gSet( 0 );
400 inherited::accepted();
403 void
404 KDMShutdown::scheduleShutdown( QWidget *_parent )
406 gSet( 1 );
407 gSendInt( G_QueryShutdown );
408 int how = gRecvInt();
409 int start = gRecvInt();
410 int timeout = gRecvInt();
411 int force = gRecvInt();
412 int uid = gRecvInt();
413 char *os = gRecvStr();
414 gSet( 0 );
415 if (how) {
416 int ret =
417 KDMCancelShutdown( how, start, timeout, force, uid, os,
418 _parent ).exec();
419 if (!ret)
420 return;
421 doShutdown( 0, 0 );
422 uid = ret == Authed ? 0 : -1;
423 } else
424 uid = -1;
425 if (os)
426 free( os );
427 KDMShutdown( uid, _parent ).exec();
431 KDMRadioButton::KDMRadioButton( const QString &label, QWidget *parent )
432 : inherited( label, parent )
436 void
437 KDMRadioButton::mouseDoubleClickEvent( QMouseEvent * )
439 emit doubleClicked();
443 KDMDelayedPushButton::KDMDelayedPushButton( const KGuiItem &item,
444 QWidget *parent )
445 : inherited( item, parent )
447 popt.setSingleShot( true );
448 popt.setInterval( style()->styleHint( QStyle::SH_ToolButton_PopupDelay, 0, this ) );
451 void KDMDelayedPushButton::setDelayedMenu( QMenu *p )
453 setMenu( p );
454 disconnect( this, 0, this, 0 ); // Internal button -> popup connection
455 if (p) {
456 connect( this, SIGNAL(pressed()), &popt, SLOT(start()) );
457 connect( this, SIGNAL(released()), &popt, SLOT(stop()) );
458 connect( &popt, SIGNAL(timeout()), SLOT(showMenu()) );
462 KDMSlimShutdown::KDMSlimShutdown( QWidget *_parent )
463 : inherited( _parent )
465 QHBoxLayout *hbox = new QHBoxLayout( this );
467 QFrame *lfrm = new QFrame( this );
468 hbox->addWidget( lfrm, Qt::AlignCenter );
469 QLabel *icon = new QLabel( lfrm );
470 icon->setPixmap( QPixmap( KStandardDirs::locate( "data", "kdm/pics/shutdown.png" ) ) );
471 icon->setFixedSize( icon->sizeHint() );
472 lfrm->setFixedSize( icon->sizeHint() );
474 QVBoxLayout *buttonlay = new QVBoxLayout();
475 hbox->addLayout( buttonlay );
477 buttonlay->addStretch( 1 );
479 KPushButton *btnHalt = new
480 KPushButton( KGuiItem( i18n("&Turn Off Computer"), "system-shutdown" ), this );
481 buttonlay->addWidget( btnHalt );
482 connect( btnHalt, SIGNAL(clicked()), SLOT(slotHalt()) );
484 buttonlay->addSpacing( KDialog::spacingHint() );
486 KDMDelayedPushButton *btnReboot = new
487 KDMDelayedPushButton( KGuiItem( i18n("&Restart Computer"), "system-restart" ), this );
488 buttonlay->addWidget( btnReboot );
489 connect( btnReboot, SIGNAL(clicked()), SLOT(slotReboot()) );
491 int dummy, cur;
492 if (getBootOptions( &targetList, &dummy, &cur )) {
493 QMenu *targets = new QMenu( this );
494 for (int i = 0; i < targetList.size(); i++)
495 (targets->addAction( i == cur ?
496 i18nc( "current option in boot loader",
497 "%1 (current)", targetList[i] ) :
498 targetList[i] ))->setData( i );
499 btnReboot->setDelayedMenu( targets );
500 connect( targets, SIGNAL(triggered( QAction * )),
501 SLOT(slotReboot( QAction * )) );
504 buttonlay->addStretch( 1 );
506 if (_scheduledSd != SHUT_NEVER) {
507 KPushButton *btnSched = new
508 KPushButton( KGuiItem( i18nc("@action:button verb", "&Schedule...") ), this );
509 buttonlay->addWidget( btnSched );
510 connect( btnSched, SIGNAL(clicked()), SLOT(slotSched()) );
512 buttonlay->addStretch( 1 );
515 buttonlay->addWidget( new KSeparator( this ) );
517 buttonlay->addSpacing( 0 );
519 KPushButton *btnBack = new KPushButton( KStandardGuiItem::cancel(), this );
520 buttonlay->addWidget( btnBack );
521 connect( btnBack, SIGNAL(clicked()), SLOT(reject()) );
523 buttonlay->addSpacing( KDialog::spacingHint() );
526 void
527 KDMSlimShutdown::slotSched()
529 reject();
530 KDMShutdown::scheduleShutdown();
533 void
534 KDMSlimShutdown::slotHalt()
536 if (checkShutdown( SHUT_HALT, 0 ))
537 doShutdown( SHUT_HALT, 0 );
540 void
541 KDMSlimShutdown::slotReboot()
543 if (checkShutdown( SHUT_REBOOT, 0 ))
544 doShutdown( SHUT_REBOOT, 0 );
547 void
548 KDMSlimShutdown::slotReboot( QAction *action )
550 int opt = action->data().toInt();
551 if (checkShutdown( SHUT_REBOOT, targetList[opt] ))
552 doShutdown( SHUT_REBOOT, targetList[opt] );
555 bool
556 KDMSlimShutdown::checkShutdown( int type, const QString &os )
558 reject();
559 QList<DpySpec> sess = fetchSessions( lstRemote | lstTTY );
560 if (sess.isEmpty() && _allowShutdown != SHUT_ROOT)
561 return true;
562 int ret = KDMConfShutdown( -1, sess, type, os ).exec();
563 if (ret == Schedule) {
564 KDMShutdown::scheduleShutdown();
565 return false;
567 return ret;
570 void
571 KDMSlimShutdown::externShutdown( int type, const QString &os, int uid )
573 QList<DpySpec> sess = fetchSessions( lstRemote | lstTTY );
574 int ret = KDMConfShutdown( uid, sess, type, os ).exec();
575 if (ret == Schedule)
576 KDMShutdown( uid ).exec();
577 else if (ret)
578 doShutdown( type, os );
582 KDMConfShutdown::KDMConfShutdown( int _uid, const QList<DpySpec> &sessions, int type,
583 const QString &os, QWidget *_parent )
584 : inherited( _uid, _parent )
586 #ifdef HAVE_VTS
587 if (type == SHUT_CONSOLE)
588 willShut = false;
589 #endif
590 box->addWidget( new QLabel( QString( "<qt><center><b><nobr>"
591 "%1%2"
592 "</nobr></b></center></qt>" )
593 .arg( (type == SHUT_HALT) ?
594 i18n("Turn Off Computer") :
595 #ifdef HAVE_VTS
596 (type == SHUT_CONSOLE) ?
597 i18n("Switch to Console") :
598 #endif
599 i18n("Restart Computer") )
600 .arg( !os.isEmpty() ?
601 i18n("<br/>(Next boot: %1)", os ) :
602 QString() ),
603 this ) );
605 if (!sessions.isEmpty()) {
606 if (willShut && _scheduledSd != SHUT_NEVER)
607 maySched = true;
608 mayNuke = doesNuke = true;
609 if (_allowNuke == SHUT_NONE)
610 mayOk = false;
611 QLabel *lab = new QLabel( mayOk ?
612 i18n("Abort active sessions:") :
613 i18n("No permission to abort active sessions:"),
614 this );
615 box->addWidget( lab );
616 QTreeWidget *lv = new QTreeWidget( this );
617 lv->setRootIsDecorated( false );
618 lv->setSelectionMode( QAbstractItemView::NoSelection );
619 lv->setAllColumnsShowFocus( true );
620 lv->setUniformRowHeights( true );
621 lv->setEditTriggers( QAbstractItemView::NoEditTriggers );
622 lv->setColumnCount( 2 );
623 lv->setHeaderLabels( QStringList()
624 << i18nc("@title:column", "Session")
625 << i18nc("@title:column ... of session", "Location") );
626 int ns = 0;
627 QString user, loc;
628 foreach (const DpySpec &sess, sessions) {
629 decodeSession( sess, user, loc );
630 new QTreeWidgetItem( lv, QStringList() << user << loc );
631 ns++;
633 int fw = lv->frameWidth() * 2;
634 int hh = lv->header()->sizeHint().height();
635 int ih = lv->itemDelegate()->sizeHint(
636 QStyleOptionViewItem(), lv->model()->index( 0, 0 ) ).height();
637 lv->setFixedHeight( fw + hh + ih * (ns < 3 ? 3 : ns > 10 ? 10 : ns) );
638 box->addWidget( lv );
639 complete( lv );
640 int cw[2];
641 for (int i = 0; i < 2; i++)
642 cw[i] = qMax( static_cast<QAbstractItemView *>(lv)->sizeHintForColumn( i ),
643 lv->header()->sectionSizeHint( i ) );
644 int w = lv->maximumViewportSize().width(), w2 = w / 2;
645 int m = (w < cw[0] + cw[1]) ?
646 (cw[0] + (w - cw[1])) / 2 :
647 (cw[0] > w2) ? cw[0] : (cw[1] > w2) ? (w - cw[1]) : w2;
648 lv->header()->resizeSection( 0, m );
649 } else
650 complete( 0 );
654 KDMCancelShutdown::KDMCancelShutdown( int how, int start, int timeout,
655 int force, int uid, const QString &os,
656 QWidget *_parent )
657 : inherited( -1, _parent )
659 if (force == SHUT_FORCE) {
660 if (_allowNuke == SHUT_NONE)
661 mayOk = false;
662 else if (_allowNuke == SHUT_ROOT)
663 mayNuke = doesNuke = true;
665 QLabel *lab = new QLabel( mayOk ?
666 i18n("Abort pending shutdown:") :
667 i18n("No permission to abort pending shutdown:"),
668 this );
669 box->addWidget( lab );
670 QDateTime qdt;
671 QString strt, end;
672 if (start < time( 0 ))
673 strt = i18nc("start of shutdown:", "now");
674 else {
675 qdt.setTime_t( start );
676 strt = qdt.toString( Qt::LocalDate );
678 if (timeout == TO_INF)
679 end = i18nc("timeout of shutdown:", "infinite");
680 else {
681 qdt.setTime_t( timeout );
682 end = qdt.toString( Qt::LocalDate );
684 QString trg =
685 i18n("Owner: %1"
686 "\nType: %2%5"
687 "\nStart: %3"
688 "\nTimeout: %4",
689 uid == -2 ?
690 i18nc("owner of shutdown:", "console user") :
691 uid == -1 ?
692 i18nc("owner of shutdown:", "control socket") :
693 KUser( uid ).loginName() ,
694 how == SHUT_HALT ?
695 i18n("turn off computer") :
696 i18n("restart computer") ,
697 strt, end ,
698 !os.isEmpty() ?
699 i18n("\nNext boot: %1", os ) :
700 QString() );
701 if (timeout != TO_INF)
702 trg += i18n("\nAfter timeout: %1",
703 force == SHUT_FORCE ?
704 i18nc("after timeout:", "abort all sessions") :
705 force == SHUT_FORCEMY ?
706 i18nc("after timeout:", "abort own sessions") :
707 i18nc("after timeout:", "cancel shutdown") );
708 lab = new QLabel( trg, this );
709 box->addWidget( lab );
710 complete( 0 );
713 #include "kdmshutdown.moc"