2 * Copyright (C) 2006 Aaron Seigo <aseigo@kde.org>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License version 2 as
6 * published by the Free Software Foundation
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details
13 * You should have received a copy of the GNU Library General Public
14 * License along with this program; if not, write to the
15 * Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #include "krunnerapp.h"
29 #include <QtDBus/QtDBus>
33 #include <KActionCollection>
36 #include <KAuthorized>
37 #include <KGlobalAccel>
38 #include <KGlobalSettings>
40 #include <KMessageBox>
41 #include <KWindowSystem>
43 #include <Plasma/RunnerManager>
46 #include "processui/ksysguardprocesslist.h"
49 #include "appadaptor.h"
50 #include "kworkspace.h"
51 #include "interfaces/default/interface.h"
52 #include "interfaces/quicksand/qs_dialog.h"
54 #include "startupid.h"
56 #include "klaunchsettings.h"
57 #include "krunnersettings.h"
60 #include <X11/extensions/Xrender.h>
63 Colormap colormap
= 0;
70 // thanks to zack rusin and frederik for pointing me in the right direction
71 // for the following bits of X11 code
72 dpy
= XOpenDisplay(0); // open default display
75 kError() << "Cannot connect to the X server";
78 if( qgetenv( "KDE_SKIP_ARGB_VISUALS" ) == "1" )
81 int screen
= DefaultScreen(dpy
);
82 int eventBase
, errorBase
;
84 if (XRenderQueryExtension(dpy
, &eventBase
, &errorBase
))
88 templ
.screen
= screen
;
90 templ
.c_class
= TrueColor
;
91 XVisualInfo
*xvi
= XGetVisualInfo(dpy
, VisualScreenMask
|
95 for (int i
= 0; i
< nvi
; ++i
)
97 XRenderPictFormat
*format
= XRenderFindVisualFormat(dpy
,
99 if (format
->type
== PictTypeDirect
&& format
->direct
.alphaMask
)
101 visual
= xvi
[i
].visual
;
102 colormap
= XCreateColormap(dpy
, RootWindow(dpy
, screen
),
112 KRunnerApp
* KRunnerApp::self()
117 return new KRunnerApp(dpy
, visual
? Qt::HANDLE(visual
) : 0, colormap
? Qt::HANDLE(colormap
) : 0);
119 return new KRunnerApp(0, 0, 0);
123 return qobject_cast
<KRunnerApp
*>(kapp
);
126 KRunnerApp::KRunnerApp(Display
*display
, Qt::HANDLE visual
, Qt::HANDLE colormap
)
128 : KUniqueApplication(display
, visual
, colormap
),
130 : KUniqueApplication(),
137 connect(this, SIGNAL(aboutToQuit()), this, SLOT(cleanUp()));
140 KRunnerApp::~KRunnerApp()
144 void KRunnerApp::cleanUp()
146 disconnect(KRunnerSettings::self(), SIGNAL(configChanged()), this, SLOT(reloadConfig()));
149 delete m_runnerManager
;
153 void KRunnerApp::initialize()
155 setWindowIcon(KIcon("system-run"));
157 setQuitOnLastWindowClosed(false);
158 KCrash::setFlags(KCrash::AutoRestart
);
159 initializeStartupNotification();
161 connect(KRunnerSettings::self(), SIGNAL(configChanged()), this, SLOT(reloadConfig()));
163 m_runnerManager
= new Plasma::RunnerManager
;
165 switch (KRunnerSettings::interface()) {
167 case KRunnerSettings::EnumInterface::CommandOriented
:
168 m_interface
= new Interface(m_runnerManager
);
170 case KRunnerSettings::EnumInterface::TaskOriented
:
171 m_interface
= new QsDialog(m_runnerManager
);
175 new AppAdaptor(this);
176 QDBusConnection::sessionBus().registerObject( "/App", this );
179 //FIXME: if argb visuals enabled Qt will always set WM_CLASS as "qt-subapplication" no matter what
180 //the application name is we set the proper XClassHint here, hopefully won't be necessary anymore when
181 //qapplication will manage apps with argvisuals in a better way
182 XClassHint classHint
;
183 classHint
.res_name
= const_cast<char*>("krunner");
184 classHint
.res_class
= const_cast<char*>("krunner");
185 XSetClassHint(QX11Info::display(), m_interface
->winId(), &classHint
);
189 m_actionCollection
= new KActionCollection(this);
192 if ( KAuthorized::authorizeKAction( "run_command" ) ) {
193 a
= m_actionCollection
->addAction( I18N_NOOP("Run Command") );
194 a
->setText( i18n( I18N_NOOP( "Run Command" ) ) );
195 a
->setGlobalShortcut(KShortcut(Qt::ALT
+Qt::Key_F2
));
196 connect( a
, SIGNAL(triggered(bool)), SLOT(display()) );
198 a
= m_actionCollection
->addAction( I18N_NOOP("Run Command on clipboard contents") );
199 a
->setText( i18n( I18N_NOOP( "Run Command on clipboard contents" ) ) );
200 a
->setGlobalShortcut(KShortcut(Qt::ALT
+Qt::SHIFT
+Qt::Key_F2
));
201 connect( a
, SIGNAL(triggered(bool)), SLOT(displayWithClipboardContents()) );
204 a
= m_actionCollection
->addAction( I18N_NOOP( "Show System Activity" ) );
205 a
->setText( i18n( I18N_NOOP( "Show System Activity" ) ) );
206 a
->setGlobalShortcut( KShortcut( Qt::CTRL
+Qt::Key_Escape
) );
207 connect( a
, SIGNAL(triggered(bool)), SLOT(showTaskManager()) );
210 * TODO: doesn't this belong in the window manager?
211 a = m_actionCollection->addAction( I18N_NOOP( "Show Window List") );
212 a->setText( i18n( I18N_NOOP( "Show Window List") ) );
213 a->setGlobalShortcut( KShortcut( Qt::ALT+Qt::Key_F5 ) );
214 connect( a, SIGNAL(triggered(bool)), SLOT(slotShowWindowList()) );
216 a
= m_actionCollection
->addAction( I18N_NOOP("Switch User") );
217 a
->setText( i18n( I18N_NOOP("Switch User") ) );
218 a
->setGlobalShortcut( KShortcut( Qt::ALT
+Qt::CTRL
+Qt::Key_Insert
) );
219 connect(a
, SIGNAL(triggered(bool)), SLOT(switchUser()));
222 if ( KAuthorized::authorizeKAction( "lock_screen" ) ) {
223 a
= m_actionCollection
->addAction( I18N_NOOP( "Lock Session" ) );
224 a
->setText( i18n( I18N_NOOP( "Lock Session" ) ) );
225 a
->setGlobalShortcut( KShortcut( Qt::ALT
+Qt::CTRL
+Qt::Key_L
) );
226 connect( a
, SIGNAL(triggered(bool)), &m_saver
, SLOT(Lock()) );
230 if ( KAuthorized::authorizeKAction( "logout" ) ) {
231 a
= m_actionCollection
->addAction( I18N_NOOP("Log Out") );
232 a
->setText( i18n(I18N_NOOP("Log Out")) );
233 a
->setGlobalShortcut(KShortcut(Qt::ALT
+Qt::CTRL
+Qt::Key_Delete
));
234 connect(a
, SIGNAL(triggered(bool)), SLOT(logout()));
236 a
= m_actionCollection
->addAction( I18N_NOOP("Log Out Without Confirmation") );
237 a
->setText( i18n(I18N_NOOP("Log Out Without Confirmation")) );
238 a
->setGlobalShortcut(KShortcut(Qt::ALT
+Qt::CTRL
+Qt::SHIFT
+Qt::Key_Delete
));
239 connect(a
, SIGNAL(triggered(bool)), SLOT(logoutWithoutConfirmation()));
241 a
= m_actionCollection
->addAction( I18N_NOOP("Halt Without Confirmation") );
242 a
->setText( i18n(I18N_NOOP("Halt Without Confirmation")) );
243 a
->setGlobalShortcut(KShortcut(Qt::ALT
+Qt::CTRL
+Qt::SHIFT
+Qt::Key_PageDown
));
244 connect(a
, SIGNAL(triggered(bool)), SLOT(haltWithoutConfirmation()));
246 a
= m_actionCollection
->addAction( I18N_NOOP("Reboot Without Confirmation") );
247 a
->setText( i18n(I18N_NOOP("Reboot Without Confirmation")) );
248 a
->setGlobalShortcut(KShortcut(Qt::ALT
+Qt::CTRL
+Qt::SHIFT
+Qt::Key_PageUp
));
249 connect(a
, SIGNAL(triggered(bool)), SLOT(rebootWithoutConfirmation()));
252 m_actionCollection
->readSettings();
254 m_runnerManager
->reloadConfiguration(); // pre-load the runners
256 } // end void KRunnerApp::initializeBindings
258 void KRunnerApp::initializeStartupNotification()
260 // Startup notification
261 KLaunchSettings::self()->readConfig();
263 if( !KLaunchSettings::busyCursor() ) {
267 if( m_startupId
== NULL
) {
268 m_startupId
= new StartupId
;
271 m_startupId
->configure();
276 /*TODO: fixme - move to kwin
277 void KRunnerApp::showWindowList()
279 //KRootWm::self()->slotWindowList();
283 void KRunnerApp::showTaskManager()
286 //kDebug(1204) << "Launching KSysGuard...";
287 KSysGuardProcessList
* w
= NULL
;
289 //TODO: move this dialog into its own KDialog subclass
290 // add an expander widget (as seen in the main
291 // krunner window when options get shown)
292 // and put some basic feedback plasmoids there
293 // BLOCKEDBY: said plasmoids and the dataengine
294 // currently being worked on, so the
295 // wait shouldn't be too long =)
297 m_tasks
= new KDialog(0);
298 m_tasks
->setWindowTitle(i18n("System Activity"));
299 m_tasks
->setWindowIcon(KIcon("utilities-system-monitor"));
300 connect(m_tasks
, SIGNAL(finished()),
301 this, SLOT(taskDialogFinished()));
302 m_tasks
->setButtons(KDialog::Close
);
303 w
= new KSysGuardProcessList(m_tasks
);
304 m_tasks
->setMainWidget(w
);
306 m_tasks
->setInitialSize(QSize(650, 420));
307 KConfigGroup cg
= KGlobal::config()->group("TaskDialog");
308 m_tasks
->restoreDialogSize(cg
);
310 // Since we default to forcing the window to be KeepAbove, if the user turns this off, remember this
311 bool keepAbove
= KRunnerSettings::keepTaskDialogAbove();
313 KWindowSystem::setState( m_tasks
->winId(), NET::KeepAbove
);
317 w
= static_cast<KSysGuardProcessList
*> (m_tasks
->mainWidget());
322 KWindowSystem::setOnDesktop(m_tasks
->winId(), KWindowSystem::currentDesktop());
323 KWindowSystem::forceActiveWindow(m_tasks
->winId());
326 w
->filterLineEdit()->setFocus();
331 void KRunnerApp::display()
333 m_interface
->display();
336 void KRunnerApp::query(const QString
&term
)
338 m_interface
->display(term
);
341 void KRunnerApp::displayWithClipboardContents()
343 QString clipboardData
= QApplication::clipboard()->text(QClipboard::Selection
);
344 m_interface
->display(clipboardData
);
347 void KRunnerApp::switchUser()
349 m_interface
->switchUser();
352 void KRunnerApp::clearHistory()
354 m_interface
->clearHistory();
357 void KRunnerApp::taskDialogFinished()
360 KConfigGroup cg
= KGlobal::config()->group("TaskDialog");
361 m_tasks
->saveDialogSize(cg
);
362 KSysGuardProcessList
*w
= static_cast<KSysGuardProcessList
*> (m_tasks
->mainWidget());
367 // Since we default to forcing the window to be KeepAbove, if the user turns this off, remember this
368 bool keepAbove
= KWindowSystem::windowInfo(m_tasks
->winId(), NET::WMState
).hasState(NET::KeepAbove
);
369 KRunnerSettings::setKeepTaskDialogAbove(keepAbove
);
370 KGlobal::config()->sync();
372 m_tasks
->deleteLater();
377 void KRunnerApp::logout()
379 logout( KWorkSpace::ShutdownConfirmDefault
,
380 KWorkSpace::ShutdownTypeDefault
);
383 void KRunnerApp::logoutWithoutConfirmation()
385 logout( KWorkSpace::ShutdownConfirmNo
,
386 KWorkSpace::ShutdownTypeNone
);
389 void KRunnerApp::haltWithoutConfirmation()
391 logout( KWorkSpace::ShutdownConfirmNo
,
392 KWorkSpace::ShutdownTypeHalt
);
395 void KRunnerApp::rebootWithoutConfirmation()
397 logout( KWorkSpace::ShutdownConfirmNo
,
398 KWorkSpace::ShutdownTypeReboot
);
401 void KRunnerApp::logout( KWorkSpace::ShutdownConfirm confirm
,
402 KWorkSpace::ShutdownType sdtype
)
405 if ( !KWorkSpace::requestShutDown( confirm
, sdtype
) ) {
406 // TODO: should we show these errors in Interface?
407 KMessageBox::error( 0, i18n("Could not log out properly.\nThe session manager cannot "
408 "be contacted. You can try to force a shutdown by pressing "
409 "Ctrl+Alt+Backspace; note, however, that your current session "
410 "will not be saved with a forced shutdown." ) );
415 int KRunnerApp::newInstance()
417 static bool firstTime
= true;
421 m_interface
->display();
424 return KUniqueApplication::newInstance();
428 bool KRunnerApp::hasCompositeManager() const
431 return colormap
&& KWindowSystem::compositingActive();
437 void KRunnerApp::reloadConfig()
439 //Prevent Interface destructor from triggering this method
440 disconnect(KRunnerSettings::self(), SIGNAL(configChanged()), this, SLOT(reloadConfig()));
442 int interface
= KRunnerSettings::interface();
443 if (qobject_cast
<Interface
*>(m_interface
) &&
444 interface
== KRunnerSettings::EnumInterface::TaskOriented
) {
446 m_interface
= new QsDialog(m_runnerManager
);
447 m_interface
->display();
448 } else if (interface
== KRunnerSettings::EnumInterface::CommandOriented
) {
450 m_interface
= new Interface(m_runnerManager
);
451 m_interface
->display();
454 connect(KRunnerSettings::self(), SIGNAL(configChanged()), this, SLOT(reloadConfig()));
457 #include "krunnerapp.moc"