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"
32 #include <kseparator.h>
33 #include <kstandarddirs.h>
34 #include <KStandardGuiItem>
38 #include <QApplication>
44 #include <QHeaderView>
48 #include <QStylePainter>
50 #include <QTreeWidget>
51 #include <QTreeWidgetItem>
55 int KDMShutdownBase::curPlugin
= -1;
56 PluginList
KDMShutdownBase::pluginList
;
58 KDMShutdownBase::KDMShutdownBase( int _uid
, QWidget
*_parent
)
59 : inherited( _parent
)
60 , box( new QVBoxLayout( this ) )
75 KDMShutdownBase::~KDMShutdownBase()
82 KDMShutdownBase::complete( QWidget
*prevWidget
)
84 QSizePolicy
fp( QSizePolicy::Fixed
, QSizePolicy::Fixed
);
87 ((willShut
&& _allowShutdown
== SHUT_ROOT
) ||
88 (mayNuke
&& _allowNuke
== SHUT_ROOT
)))
90 rootlab
= new QLabel( i18n("Root authorization required."), this );
91 box
->addWidget( rootlab
);
94 pluginList
= KGVerify::init( _pluginsShutdown
);
96 verify
= new KGStdVerify( this, this,
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 );
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()) );
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
);
131 cancelButton
->setDefault( true );
132 hlay
->addWidget( cancelButton
);
133 hlay
->addStretch( 1 );
134 connect( cancelButton
, SIGNAL(clicked()), SLOT(reject()) );
139 layout()->activate();
143 KDMShutdownBase::slotActivatePlugMenu()
146 QMenu
*cmnu
= verify
->getPlugMenu();
149 QSize
sh( cmnu
->sizeHint() / 2 );
150 cmnu
->exec( geometry().center() - QPoint( sh
.width(), sh
.height() ) );
155 KDMShutdownBase::accept()
164 KDMShutdownBase::slotSched()
170 KDMShutdownBase::updateNeedRoot()
172 int nNeedRoot
= uid
&&
173 (((willShut
&& _allowShutdown
== SHUT_ROOT
) ||
174 (_allowNuke
== SHUT_ROOT
&& doesNuke
)));
175 if (verify
&& nNeedRoot
!= needRoot
) {
178 needRoot
= nNeedRoot
;
179 rootlab
->setEnabled( needRoot
);
180 verify
->setEnabled( needRoot
);
187 KDMShutdownBase::accepted()
189 inherited::done( needRoot
? (int)Authed
: (int)Accepted
);
193 KDMShutdownBase::verifyPluginChanged( int id
)
200 KDMShutdownBase::verifyOk()
206 KDMShutdownBase::verifyFailed()
208 okButton
->setEnabled( false );
209 cancelButton
->setEnabled( false );
213 KDMShutdownBase::verifyRetry()
215 okButton
->setEnabled( true );
216 cancelButton
->setEnabled( true );
220 KDMShutdownBase::verifySetUser( const QString
& )
226 doShutdown( int type
, const QString
&os
)
229 gSendInt( G_Shutdown
);
233 gSendInt( SHUT_FORCE
);
234 gSendInt( 0 ); /* irrelevant, will timeout immediately anyway */
235 gSendStr( os
.toUtf8().data() );
241 getBootOptions( QStringList
*options
, int *defaultTarget
, int *oldTarget
)
245 gSendInt( G_ListBootOpts
);
246 if (gRecvInt() == BO_OK
) {
247 *options
= qStringList( gRecvStrArr( 0 ) );
248 *defaultTarget
= gRecvInt();
249 *oldTarget
= gRecvInt();
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
);
268 rb
= new KDMRadioButton( i18n("&Turn off computer"), howGroup
);
269 rb
->setChecked( true );
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()) );
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
);
290 style()->pixelMetric( QStyle::PM_ExclusiveIndicatorWidth
)
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()) );
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" );
329 le_timeout
->setText( "0" );
330 if (_defSdMode
== SHUT_FORCENOW
&& cb_force
->isEnabled())
331 cb_force
->setChecked( true );
334 complete( schedGroup
);
338 getDate( const char *str
)
341 prc
.setOutputChannelMode( KProcess::OnlyStdoutChannel
);
342 prc
<< "/bin/date" << "+%s" << "-d" << str
;
345 return prc
.readAll().simplified().toInt();
349 KDMShutdown::accept()
351 if (le_start
->text() == "0" || le_start
->text() == "now")
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();
360 if (le_timeout
->text() == "-1" || le_timeout
->text().startsWith( "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();
374 KDMShutdown::slotTargetChanged()
376 restart_rb
->setChecked( true );
380 KDMShutdown::slotWhenChanged()
382 doesNuke
= cb_force
->isChecked();
387 KDMShutdown::accepted()
390 gSendInt( G_Shutdown
);
391 gSendInt( restart_rb
->isChecked() ? SHUT_REBOOT
: SHUT_HALT
);
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 );
400 inherited::accepted();
404 KDMShutdown::scheduleShutdown( QWidget
*_parent
)
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();
417 KDMCancelShutdown( how
, start
, timeout
, force
, uid
, os
,
422 uid
= ret
== Authed
? 0 : -1;
427 KDMShutdown( uid
, _parent
).exec();
431 KDMRadioButton::KDMRadioButton( const QString
&label
, QWidget
*parent
)
432 : inherited( label
, parent
)
437 KDMRadioButton::mouseDoubleClickEvent( QMouseEvent
* )
439 emit
doubleClicked();
443 KDMDelayedPushButton::KDMDelayedPushButton( const KGuiItem
&item
,
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
)
454 disconnect( this, 0, this, 0 ); // Internal button -> popup connection
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()) );
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() );
527 KDMSlimShutdown::slotSched()
530 KDMShutdown::scheduleShutdown();
534 KDMSlimShutdown::slotHalt()
536 if (checkShutdown( SHUT_HALT
, 0 ))
537 doShutdown( SHUT_HALT
, 0 );
541 KDMSlimShutdown::slotReboot()
543 if (checkShutdown( SHUT_REBOOT
, 0 ))
544 doShutdown( SHUT_REBOOT
, 0 );
548 KDMSlimShutdown::slotReboot( QAction
*action
)
550 int opt
= action
->data().toInt();
551 if (checkShutdown( SHUT_REBOOT
, targetList
[opt
] ))
552 doShutdown( SHUT_REBOOT
, targetList
[opt
] );
556 KDMSlimShutdown::checkShutdown( int type
, const QString
&os
)
559 QList
<DpySpec
> sess
= fetchSessions( lstRemote
| lstTTY
);
560 if (sess
.isEmpty() && _allowShutdown
!= SHUT_ROOT
)
562 int ret
= KDMConfShutdown( -1, sess
, type
, os
).exec();
563 if (ret
== Schedule
) {
564 KDMShutdown::scheduleShutdown();
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();
576 KDMShutdown( uid
).exec();
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
)
587 if (type
== SHUT_CONSOLE
)
590 box
->addWidget( new QLabel( QString( "<qt><center><b><nobr>"
592 "</nobr></b></center></qt>" )
593 .arg( (type
== SHUT_HALT
) ?
594 i18n("Turn Off Computer") :
596 (type
== SHUT_CONSOLE
) ?
597 i18n("Switch to Console") :
599 i18n("Restart Computer") )
600 .arg( !os
.isEmpty() ?
601 i18n("<br/>(Next boot: %1)", os
) :
605 if (!sessions
.isEmpty()) {
606 if (willShut
&& _scheduledSd
!= SHUT_NEVER
)
608 mayNuke
= doesNuke
= true;
609 if (_allowNuke
== SHUT_NONE
)
611 QLabel
*lab
= new QLabel( mayOk
?
612 i18n("Abort active sessions:") :
613 i18n("No permission to abort active sessions:"),
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") );
628 foreach (const DpySpec
&sess
, sessions
) {
629 decodeSession( sess
, user
, loc
);
630 new QTreeWidgetItem( lv
, QStringList() << user
<< loc
);
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
);
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
);
654 KDMCancelShutdown::KDMCancelShutdown( int how
, int start
, int timeout
,
655 int force
, int uid
, const QString
&os
,
657 : inherited( -1, _parent
)
659 if (force
== SHUT_FORCE
) {
660 if (_allowNuke
== SHUT_NONE
)
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:"),
669 box
->addWidget( lab
);
672 if (start
< time( 0 ))
673 strt
= i18nc("start of shutdown:", "now");
675 qdt
.setTime_t( start
);
676 strt
= qdt
.toString( Qt::LocalDate
);
678 if (timeout
== TO_INF
)
679 end
= i18nc("timeout of shutdown:", "infinite");
681 qdt
.setTime_t( timeout
);
682 end
= qdt
.toString( Qt::LocalDate
);
690 i18nc("owner of shutdown:", "console user") :
692 i18nc("owner of shutdown:", "control socket") :
693 KUser( uid
).loginName() ,
695 i18n("turn off computer") :
696 i18n("restart computer") ,
699 i18n("\nNext boot: %1", os
) :
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
);
713 #include "kdmshutdown.moc"