not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / krunner / krunnerapp.cpp
blob610fa298027c61844c683b00b645198d57b8bd95
1 /*
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"
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
25 #include <QClipboard>
26 #include <QObject>
27 #include <QProcess>
28 #include <QTimer>
29 #include <QtDBus/QtDBus>
30 #include <QLineEdit>
32 #include <KAction>
33 #include <KActionCollection>
34 #include <KCrash>
35 #include <KDialog>
36 #include <KAuthorized>
37 #include <KGlobalAccel>
38 #include <KGlobalSettings>
39 #include <KLocale>
40 #include <KMessageBox>
41 #include <KWindowSystem>
43 #include <Plasma/RunnerManager>
45 #ifdef Q_WS_X11
46 #include "processui/ksysguardprocesslist.h"
47 #endif
49 #include "appadaptor.h"
50 #include "kworkspace.h"
51 #include "interfaces/default/interface.h"
52 #include "interfaces/quicksand/qs_dialog.h"
53 #ifdef Q_WS_X11
54 #include "startupid.h"
55 #endif
56 #include "klaunchsettings.h"
57 #include "krunnersettings.h"
59 #ifdef Q_WS_X11
60 #include <X11/extensions/Xrender.h>
62 Display* dpy = 0;
63 Colormap colormap = 0;
64 Visual *visual = 0;
65 #endif
67 void checkComposite()
69 #ifdef Q_WS_X11
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
73 if (!dpy)
75 kError() << "Cannot connect to the X server";
76 return;
78 if( qgetenv( "KDE_SKIP_ARGB_VISUALS" ) == "1" )
79 return;
81 int screen = DefaultScreen(dpy);
82 int eventBase, errorBase;
84 if (XRenderQueryExtension(dpy, &eventBase, &errorBase))
86 int nvi;
87 XVisualInfo templ;
88 templ.screen = screen;
89 templ.depth = 32;
90 templ.c_class = TrueColor;
91 XVisualInfo *xvi = XGetVisualInfo(dpy, VisualScreenMask |
92 VisualDepthMask |
93 VisualClassMask,
94 &templ, &nvi);
95 for (int i = 0; i < nvi; ++i)
97 XRenderPictFormat *format = XRenderFindVisualFormat(dpy,
98 xvi[i].visual);
99 if (format->type == PictTypeDirect && format->direct.alphaMask)
101 visual = xvi[i].visual;
102 colormap = XCreateColormap(dpy, RootWindow(dpy, screen),
103 visual, AllocNone);
104 break;
109 #endif
112 KRunnerApp* KRunnerApp::self()
114 if (!kapp) {
115 checkComposite();
116 #ifdef Q_WS_X11
117 return new KRunnerApp(dpy, visual ? Qt::HANDLE(visual) : 0, colormap ? Qt::HANDLE(colormap) : 0);
118 #else
119 return new KRunnerApp(0, 0, 0);
120 #endif
123 return qobject_cast<KRunnerApp*>(kapp);
126 KRunnerApp::KRunnerApp(Display *display, Qt::HANDLE visual, Qt::HANDLE colormap)
127 #ifdef Q_WS_X11
128 : KUniqueApplication(display, visual, colormap),
129 #else
130 : KUniqueApplication(),
131 #endif
132 m_interface(0),
133 m_tasks(0),
134 m_startupId(NULL)
136 initialize();
137 connect(this, SIGNAL(aboutToQuit()), this, SLOT(cleanUp()));
140 KRunnerApp::~KRunnerApp()
144 void KRunnerApp::cleanUp()
146 disconnect(KRunnerSettings::self(), SIGNAL(configChanged()), this, SLOT(reloadConfig()));
147 delete m_interface;
148 m_interface = 0;
149 delete m_runnerManager;
150 m_runnerManager = 0;
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()) {
166 default:
167 case KRunnerSettings::EnumInterface::CommandOriented:
168 m_interface = new Interface(m_runnerManager);
169 break;
170 case KRunnerSettings::EnumInterface::TaskOriented:
171 m_interface = new QsDialog(m_runnerManager);
172 break;
175 new AppAdaptor(this);
176 QDBusConnection::sessionBus().registerObject( "/App", this );
178 #ifdef Q_WS_X11
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);
186 #endif
188 // Global keys
189 m_actionCollection = new KActionCollection(this);
190 KAction* a = 0;
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()));
221 #ifdef Q_WS_X11
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()) );
228 #endif
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();
262 #ifdef Q_WS_X11
263 if( !KLaunchSettings::busyCursor() ) {
264 delete m_startupId;
265 m_startupId = NULL;
266 } else {
267 if( m_startupId == NULL ) {
268 m_startupId = new StartupId;
271 m_startupId->configure();
273 #endif
276 /*TODO: fixme - move to kwin
277 void KRunnerApp::showWindowList()
279 //KRootWm::self()->slotWindowList();
283 void KRunnerApp::showTaskManager()
285 #ifndef Q_WS_WIN
286 //kDebug(1204) << "Launching KSysGuard...";
287 KSysGuardProcessList* w = NULL;
288 if (!m_tasks) {
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);
309 w->loadSettings(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();
312 if (keepAbove) {
313 KWindowSystem::setState( m_tasks->winId(), NET::KeepAbove );
316 } else
317 w = static_cast<KSysGuardProcessList *> (m_tasks->mainWidget());
320 m_tasks->show();
321 m_tasks->raise();
322 KWindowSystem::setOnDesktop(m_tasks->winId(), KWindowSystem::currentDesktop());
323 KWindowSystem::forceActiveWindow(m_tasks->winId());
325 if (w) {
326 w->filterLineEdit()->setFocus();
328 #endif
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()
359 #ifndef Q_WS_WIN
360 KConfigGroup cg = KGlobal::config()->group("TaskDialog");
361 m_tasks->saveDialogSize(cg);
362 KSysGuardProcessList *w = static_cast<KSysGuardProcessList *> (m_tasks->mainWidget());
363 if (w) {
364 w->saveSettings(cg);
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();
373 m_tasks = 0;
374 #endif
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 )
404 #ifndef Q_WS_WIN
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." ) );
412 #endif
415 int KRunnerApp::newInstance()
417 static bool firstTime = true;
418 if ( firstTime ) {
419 firstTime = false;
420 } else {
421 m_interface->display();
424 return KUniqueApplication::newInstance();
425 //return 0;
428 bool KRunnerApp::hasCompositeManager() const
430 #ifdef Q_WS_X11
431 return colormap && KWindowSystem::compositingActive();
432 #else
433 return false;
434 #endif
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) {
445 delete m_interface;
446 m_interface = new QsDialog(m_runnerManager);
447 m_interface->display();
448 } else if (interface == KRunnerSettings::EnumInterface::CommandOriented) {
449 delete m_interface;
450 m_interface = new Interface(m_runnerManager);
451 m_interface->display();
454 connect(KRunnerSettings::self(), SIGNAL(configChanged()), this, SLOT(reloadConfig()));
457 #include "krunnerapp.moc"