1 | /* |
2 | * Copyright (C) 2006 Aaron Seigo <aseigo@kde.org> |
3 | * |
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 |
7 | * |
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 |
12 | * |
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. |
17 | */ |
18 | |
19 | #include "krunnerapp.h" |
20 | |
21 | #include <stdio.h> |
22 | #include <stdlib.h> |
23 | #include <unistd.h> |
24 | |
25 | #include <QClipboard> |
26 | #include <QObject> |
27 | #include <QtDBus/QtDBus> |
28 | |
29 | #include <KAction> |
30 | #include <KActionCollection> |
31 | #include <KCrash> |
32 | #include <KAuthorized> |
33 | #include <KLocale> |
34 | #include <KWindowSystem> |
35 | |
36 | #include <Plasma/RunnerManager> |
37 | #include <Plasma/AbstractRunner> |
38 | |
39 | #include "kworkspace/kdisplaymanager.h" |
40 | |
41 | #include "appadaptor.h" |
42 | #include "ksystemactivitydialog.h" |
43 | #include "interfaces/default/interface.h" |
44 | #include "interfaces/quicksand/qs_dialog.h" |
45 | #ifdef Q_WS_X11 |
46 | #include "startupid.h" |
47 | #endif |
48 | #include "klaunchsettings.h" |
49 | #include "krunnersettings.h" |
50 | |
51 | #ifdef Q_WS_X11 |
52 | #include <X11/extensions/Xrender.h> |
53 | #endif |
54 | |
55 | KRunnerApp* KRunnerApp::self() |
56 | { |
57 | if (!kapp) { |
58 | return new KRunnerApp(); |
59 | } |
60 | |
61 | return qobject_cast<KRunnerApp*>(kapp); |
62 | } |
63 | |
64 | KRunnerApp::KRunnerApp() |
65 | : KUniqueApplication(), |
66 | m_interface(0), |
67 | m_tasks(0), |
68 | m_startupId(NULL), |
69 | m_firstTime(true) |
70 | { |
71 | initialize(); |
72 | connect(this, SIGNAL(aboutToQuit()), this, SLOT(cleanUp())); |
73 | } |
74 | |
75 | KRunnerApp::~KRunnerApp() |
76 | { |
77 | } |
78 | |
79 | void KRunnerApp::cleanUp() |
80 | { |
81 | disconnect(KRunnerSettings::self(), SIGNAL(configChanged()), this, SLOT(reloadConfig())); |
82 | kDebug() << "deleting interface" ; |
83 | delete m_interface; |
84 | m_interface = 0; |
85 | delete m_runnerManager; |
86 | m_runnerManager = 0; |
87 | #ifndef Q_WS_WIN |
88 | delete m_tasks; |
89 | m_tasks = 0; |
90 | #endif |
91 | KGlobal::config()->sync(); |
92 | } |
93 | |
94 | KActionCollection* KRunnerApp::actionCollection() |
95 | { |
96 | return m_actionCollection; |
97 | } |
98 | |
99 | void KRunnerApp::initialize() |
100 | { |
101 | setWindowIcon(KIcon(QLatin1String("system-run" ))); |
102 | |
103 | setQuitOnLastWindowClosed(false); |
104 | KCrash::setFlags(KCrash::AutoRestart); |
105 | initializeStartupNotification(); |
106 | |
107 | connect(KRunnerSettings::self(), SIGNAL(configChanged()), this, SLOT(reloadConfig())); |
108 | |
109 | m_runnerManager = new Plasma::RunnerManager; |
110 | |
111 | new AppAdaptor(this); |
112 | QDBusConnection::sessionBus().registerObject(QLatin1String("/App" ), this); |
113 | |
114 | // Global keys |
115 | m_actionCollection = new KActionCollection(this); |
116 | KAction* a = 0; |
117 | |
118 | if (KAuthorized::authorize(QLatin1String("run_command" ))) { |
119 | a = m_actionCollection->addAction(QLatin1String("Run Command" )); |
120 | a->setText(i18n("Run Command" )); |
121 | a->setGlobalShortcut(KShortcut(Qt::ALT+Qt::Key_F2)); |
122 | connect(a, SIGNAL(triggered(bool)), SLOT(displayOrHide())); |
123 | |
124 | a = m_actionCollection->addAction(QLatin1String("Run Command on clipboard contents" )); |
125 | a->setText(i18n("Run Command on clipboard contents" )); |
126 | a->setGlobalShortcut(KShortcut(Qt::ALT+Qt::SHIFT+Qt::Key_F2)); |
127 | connect(a, SIGNAL(triggered(bool)), SLOT(displayWithClipboardContents())); |
128 | } |
129 | |
130 | a = m_actionCollection->addAction(QLatin1String("Show System Activity" )); |
131 | a->setText(i18n("Show System Activity" )); |
132 | a->setGlobalShortcut(KShortcut(Qt::CTRL+Qt::Key_Escape)); |
133 | connect(a, SIGNAL(triggered(bool)), SLOT(showTaskManager())); |
134 | |
135 | if (KAuthorized::authorize(QLatin1String("switch_user" ))) { |
136 | a = m_actionCollection->addAction(QLatin1String("Switch User" )); |
137 | a->setText(i18n("Switch User" )); |
138 | a->setGlobalShortcut(KShortcut(Qt::ALT+Qt::CTRL+Qt::Key_Insert)); |
139 | connect(a, SIGNAL(triggered(bool)), SLOT(switchUser())); |
140 | } |
141 | |
142 | //Setup the interface after we have set up the actions |
143 | //TODO: if !KAuthorized::authorize("run_comand") (and !"switch_user" i suppose?) |
144 | // then we probably don't need the interface at all. would be another place |
145 | // for some small improvements in footprint in that case |
146 | switch (KRunnerSettings::interface()) { |
147 | default: |
148 | case KRunnerSettings::EnumInterface::CommandOriented: |
149 | m_interface = new Interface(m_runnerManager); |
150 | break; |
151 | case KRunnerSettings::EnumInterface::TaskOriented: |
152 | m_interface = new QsDialog(m_runnerManager); |
153 | break; |
154 | } |
155 | |
156 | #ifdef Q_WS_X11 |
157 | //FIXME: if argb visuals enabled Qt will always set WM_CLASS as "qt-subapplication" no matter what |
158 | //the application name is we set the proper XClassHint here, hopefully won't be necessary anymore when |
159 | //qapplication will manage apps with argvisuals in a better way |
160 | XClassHint classHint; |
161 | classHint.res_name = const_cast<char*>("krunner" ); |
162 | classHint.res_class = const_cast<char*>("krunner" ); |
163 | XSetClassHint(QX11Info::display(), m_interface->winId(), &classHint); |
164 | #endif |
165 | |
166 | |
167 | m_actionCollection->readSettings(); |
168 | if (KAuthorized::authorize(QLatin1String("run_command" ))) { |
169 | //m_runnerManager->setAllowedRunners(QStringList() << "shell"); |
170 | m_runnerManager->reloadConfiguration(); // pre-load the runners |
171 | |
172 | // Single runner mode actions shortcuts |
173 | |
174 | foreach (const QString &runnerId, m_runnerManager->singleModeAdvertisedRunnerIds()) { |
175 | a = m_actionCollection->addAction(runnerId); |
176 | a->setText(i18nc("Run krunner restricting the search only to runner %1" , "Run Command (runner \"%1\" only)" , |
177 | m_runnerManager->runnerName(runnerId))); |
178 | a->setGlobalShortcut(KShortcut()); |
179 | connect(a, SIGNAL(triggered(bool)), SLOT(singleRunnerModeActionTriggered())); |
180 | } |
181 | } |
182 | } |
183 | |
184 | void KRunnerApp::singleRunnerModeActionTriggered() |
185 | { |
186 | KAction * action = qobject_cast<KAction*>(sender()); |
187 | if (action) { |
188 | displaySingleRunner(action->objectName()); |
189 | } |
190 | } |
191 | |
192 | void KRunnerApp::querySingleRunner(const QString& runnerId, const QString &term) |
193 | { |
194 | if (!KAuthorized::authorize(QLatin1String("run_command" ))) { |
195 | return; |
196 | } |
197 | |
198 | m_runnerManager->setSingleModeRunnerId(runnerId); |
199 | m_runnerManager->setSingleMode(!runnerId.isEmpty()); |
200 | |
201 | if (m_runnerManager->singleMode()) { |
202 | m_interface->display(term); |
203 | } |
204 | } |
205 | |
206 | QStringList KRunnerApp::singleModeAdvertisedRunnerIds() const |
207 | { |
208 | return m_runnerManager->singleModeAdvertisedRunnerIds(); |
209 | } |
210 | |
211 | void KRunnerApp::initializeStartupNotification() |
212 | { |
213 | // Startup notification |
214 | KLaunchSettings::self()->readConfig(); |
215 | #ifdef Q_WS_X11 |
216 | if (!KLaunchSettings::busyCursor()) { |
217 | delete m_startupId; |
218 | m_startupId = NULL; |
219 | } else { |
220 | if (m_startupId == NULL ) { |
221 | m_startupId = new StartupId; |
222 | } |
223 | |
224 | m_startupId->configure(); |
225 | } |
226 | #endif |
227 | } |
228 | |
229 | void KRunnerApp::showTaskManager() |
230 | { |
231 | showTaskManagerWithFilter(QString()); |
232 | } |
233 | |
234 | void KRunnerApp::showTaskManagerWithFilter(const QString &filterText) |
235 | { |
236 | #ifndef Q_WS_WIN |
237 | //kDebug(1204) << "Launching KSysGuard..."; |
238 | if (!m_tasks) { |
239 | m_tasks = new KSystemActivityDialog; |
240 | connect(m_tasks, SIGNAL(finished()), |
241 | this, SLOT(taskDialogFinished())); |
242 | } else if ((filterText.isEmpty() || m_tasks->filterText() == filterText) && |
243 | KWindowSystem::activeWindow() == m_tasks->winId()) { |
244 | m_tasks->hide(); |
245 | return; |
246 | } |
247 | |
248 | m_tasks->run(); |
249 | m_tasks->setFilterText(filterText); |
250 | #endif |
251 | } |
252 | |
253 | void KRunnerApp::display() |
254 | { |
255 | if (!KAuthorized::authorize(QLatin1String("run_command" ))) { |
256 | return; |
257 | } |
258 | |
259 | m_runnerManager->setSingleMode(false); |
260 | m_interface->display(); |
261 | } |
262 | |
263 | void KRunnerApp::displaySingleRunner(const QString &runnerId) |
264 | { |
265 | if (!KAuthorized::authorize(QLatin1String("run_command" ))) { |
266 | return; |
267 | } |
268 | |
269 | m_runnerManager->setSingleModeRunnerId(runnerId); |
270 | m_runnerManager->setSingleMode(!runnerId.isEmpty()); |
271 | m_interface->display(); |
272 | } |
273 | |
274 | void KRunnerApp::displayOrHide() |
275 | { |
276 | if (!KAuthorized::authorize(QLatin1String("run_command" ))) { |
277 | m_interface->hide(); |
278 | return; |
279 | } |
280 | |
281 | if (!m_interface->isVisible()) { |
282 | m_runnerManager->setSingleMode(false); |
283 | } |
284 | |
285 | if (m_interface->freeFloating()) { |
286 | if (m_interface->isVisible()) { |
287 | m_interface->hide(); |
288 | } else { |
289 | m_interface->display(); |
290 | } |
291 | } else if (m_interface->isActiveWindow()) { |
292 | m_interface->hide(); |
293 | } else { |
294 | m_interface->display(); |
295 | } |
296 | } |
297 | |
298 | void KRunnerApp::query(const QString &term) |
299 | { |
300 | if (!KAuthorized::authorize(QLatin1String("run_command" ))) { |
301 | return; |
302 | } |
303 | |
304 | m_interface->display(term); |
305 | } |
306 | |
307 | void KRunnerApp::displayWithClipboardContents() |
308 | { |
309 | if (!KAuthorized::authorize(QLatin1String("run_command" ))) { |
310 | return; |
311 | } |
312 | |
313 | QString clipboardData = QApplication::clipboard()->text(QClipboard::Selection); |
314 | m_interface->display(clipboardData); |
315 | } |
316 | |
317 | void KRunnerApp::switchUser() |
318 | { |
319 | const KService::Ptr service = KService::serviceByStorageId(QLatin1String("plasma-runner-sessions.desktop" )); |
320 | KPluginInfo info(service); |
321 | |
322 | if (info.isValid()) { |
323 | SessList sessions; |
324 | KDisplayManager dm; |
325 | dm.localSessions(sessions); |
326 | |
327 | if (sessions.isEmpty()) { |
328 | // no sessions to switch between, let's just start up another session directly |
329 | Plasma::AbstractRunner *sessionRunner = m_runnerManager->runner(info.pluginName()); |
330 | if (sessionRunner) { |
331 | Plasma::QueryMatch switcher(sessionRunner); |
332 | sessionRunner->run(*m_runnerManager->searchContext(), switcher); |
333 | } |
334 | } else { |
335 | m_runnerManager->setSingleModeRunnerId(info.pluginName()); |
336 | m_runnerManager->setSingleMode(true); |
337 | m_interface->display(); |
338 | //TODO: ugh, magic strings. See sessions/sessionrunner.cpp |
339 | m_runnerManager->launchQuery(QLatin1String("SESSIONS" ), info.pluginName()); |
340 | } |
341 | } |
342 | } |
343 | |
344 | void KRunnerApp::clearHistory() |
345 | { |
346 | m_interface->clearHistory(); |
347 | } |
348 | |
349 | void KRunnerApp::taskDialogFinished() |
350 | { |
351 | #ifndef Q_WS_WIN |
352 | m_tasks->deleteLater(); |
353 | m_tasks = 0; |
354 | #endif |
355 | } |
356 | |
357 | int KRunnerApp::newInstance() |
358 | { |
359 | if (m_firstTime) { |
360 | m_firstTime = false; |
361 | } else { |
362 | display(); |
363 | } |
364 | |
365 | return KUniqueApplication::newInstance(); |
366 | //return 0; |
367 | } |
368 | |
369 | void KRunnerApp::reloadConfig() |
370 | { |
371 | //Prevent Interface destructor from triggering this method |
372 | disconnect(KRunnerSettings::self(), SIGNAL(configChanged()), this, SLOT(reloadConfig())); |
373 | |
374 | const int interface = KRunnerSettings::interface(); |
375 | if (!qobject_cast<QsDialog*>(m_interface) && |
376 | interface == KRunnerSettings::EnumInterface::TaskOriented) { |
377 | m_interface->deleteLater(); |
378 | m_interface = new QsDialog(m_runnerManager); |
379 | } else if (!qobject_cast<Interface*>(m_interface) && |
380 | interface == KRunnerSettings::EnumInterface::CommandOriented) { |
381 | m_interface->deleteLater(); |
382 | m_interface = new Interface(m_runnerManager); |
383 | } |
384 | |
385 | m_interface->setFreeFloating(KRunnerSettings::freeFloating()); |
386 | connect(KRunnerSettings::self(), SIGNAL(configChanged()), this, SLOT(reloadConfig())); |
387 | display(); |
388 | } |
389 | |
390 | #include "krunnerapp.moc" |
391 | |