1 /*
2   SPDX-FileCopyrightText: 2008-2014 Eike Hein <hein@kde.org>
3   SPDX-FileCopyrightText: 2009 Juan Carlos Torres <carlosdgtorres@gmail.com>
4 
5   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
6 */
7 
8 #include "sessionstack.h"
9 #include "settings.h"
10 #include "terminal.h"
11 #include "visualeventoverlay.h"
12 
13 #include <config-yakuake.h>
14 
15 #include <KLocalizedString>
16 #include <KMessageBox>
17 #include <KNotification>
18 
19 #include <QDBusConnection>
20 
21 static bool show_disallow_certain_dbus_methods_message = true;
22 
SessionStack(QWidget * parent)23 SessionStack::SessionStack(QWidget *parent)
24     : QStackedWidget(parent)
25 {
26     QDBusConnection::sessionBus().registerObject(QStringLiteral("/yakuake/sessions"), this, QDBusConnection::ExportScriptableSlots);
27 
28     m_activeSessionId = -1;
29 
30     m_visualEventOverlay = new VisualEventOverlay(this);
31     connect(this, SIGNAL(removeTerminalHighlight()), m_visualEventOverlay, SLOT(removeTerminalHighlight()));
32 }
33 
~SessionStack()34 SessionStack::~SessionStack()
35 {
36 }
37 
addSessionImpl(Session::SessionType type)38 int SessionStack::addSessionImpl(Session::SessionType type)
39 {
40     Session *currentSession = m_sessions.value(activeSessionId());
41     Terminal *currentTerminal = currentSession ? currentSession->getTerminal(currentSession->activeTerminalId()) : nullptr;
42     QString workingDir = currentTerminal ? currentTerminal->currentWorkingDirectory() : QString();
43 
44     Session *session = new Session(workingDir, type, this);
45     // clang-format off
46     connect(session, SIGNAL(titleChanged(int,QString)), this, SIGNAL(titleChanged(int,QString)));
47     connect(session, SIGNAL(terminalManuallyActivated(Terminal*)), this, SLOT(handleManualTerminalActivation(Terminal*)));
48     connect(session, SIGNAL(keyboardInputBlocked(Terminal*)), m_visualEventOverlay, SLOT(indicateKeyboardInputBlocked(Terminal*)));
49     connect(session, SIGNAL(activityDetected(Terminal*)), parentWidget(), SLOT(handleTerminalActivity(Terminal*)));
50     connect(session, SIGNAL(silenceDetected(Terminal*)), parentWidget(), SLOT(handleTerminalSilence(Terminal*)));
51     connect(parentWidget(), SIGNAL(windowClosed()), session, SLOT(reconnectMonitorActivitySignals()));
52     // clang-format on
53     connect(session, SIGNAL(destroyed(int)), this, SLOT(cleanup(int)));
54 
55     addWidget(session->widget());
56 
57     m_sessions.insert(session->id(), session);
58 
59     if (Settings::dynamicTabTitles())
60         Q_EMIT sessionAdded(session->id(), session->title());
61     else
62         Q_EMIT sessionAdded(session->id(), QString());
63 
64     return session->id();
65 }
66 
addSession()67 int SessionStack::addSession()
68 {
69     return addSessionImpl(Session::Single);
70 }
71 
addSessionTwoHorizontal()72 int SessionStack::addSessionTwoHorizontal()
73 {
74     return addSessionImpl(Session::TwoHorizontal);
75 }
76 
addSessionTwoVertical()77 int SessionStack::addSessionTwoVertical()
78 {
79     return addSessionImpl(Session::TwoVertical);
80 }
81 
addSessionQuad()82 int SessionStack::addSessionQuad()
83 {
84     return addSessionImpl(Session::Quad);
85 }
86 
raiseSession(int sessionId)87 void SessionStack::raiseSession(int sessionId)
88 {
89     if (sessionId == -1 || !m_sessions.contains(sessionId))
90         return;
91     Session *session = m_sessions.value(sessionId);
92 
93     if (!m_visualEventOverlay->isHidden())
94         m_visualEventOverlay->hide();
95 
96     if (m_activeSessionId != -1 && m_sessions.contains(m_activeSessionId)) {
97         Session *oldActiveSession = m_sessions.value(m_activeSessionId);
98 
99         disconnect(oldActiveSession, SLOT(closeTerminal()));
100         disconnect(oldActiveSession, SLOT(focusPreviousTerminal()));
101         disconnect(oldActiveSession, SLOT(focusNextTerminal()));
102         disconnect(oldActiveSession, SLOT(manageProfiles()));
103         disconnect(oldActiveSession, SIGNAL(titleChanged(QString)), this, SIGNAL(activeTitleChanged(QString)));
104 
105         oldActiveSession->reconnectMonitorActivitySignals();
106     }
107 
108     m_activeSessionId = sessionId;
109 
110     setCurrentWidget(session->widget());
111 
112     if (session->widget()->focusWidget())
113         session->widget()->focusWidget()->setFocus();
114 
115     if (session->hasTerminalsWithKeyboardInputDisabled())
116         m_visualEventOverlay->show();
117 
118     connect(this, SIGNAL(closeTerminal()), session, SLOT(closeTerminal()));
119     connect(this, SIGNAL(previousTerminal()), session, SLOT(focusPreviousTerminal()));
120     connect(this, SIGNAL(nextTerminal()), session, SLOT(focusNextTerminal()));
121     connect(this, SIGNAL(manageProfiles()), session, SLOT(manageProfiles()));
122     connect(session, SIGNAL(titleChanged(QString)), this, SIGNAL(activeTitleChanged(QString)));
123 
124     Q_EMIT sessionRaised(sessionId);
125 
126     Q_EMIT activeTitleChanged(session->title());
127 }
128 
removeSession(int sessionId)129 void SessionStack::removeSession(int sessionId)
130 {
131     if (sessionId == -1)
132         sessionId = m_activeSessionId;
133     if (sessionId == -1)
134         return;
135     if (!m_sessions.contains(sessionId))
136         return;
137 
138     if (queryClose(sessionId, QueryCloseSession))
139         m_sessions.value(sessionId)->deleteLater();
140 }
141 
removeTerminal(int terminalId)142 void SessionStack::removeTerminal(int terminalId)
143 {
144     int sessionId = sessionIdForTerminalId(terminalId);
145 
146     if (terminalId == -1) {
147         if (m_activeSessionId == -1)
148             return;
149         if (!m_sessions.contains(m_activeSessionId))
150             return;
151 
152         if (m_sessions.value(m_activeSessionId)->closable())
153             m_sessions.value(m_activeSessionId)->closeTerminal();
154     } else {
155         if (m_sessions.value(sessionId)->closable())
156             m_sessions.value(sessionId)->closeTerminal(terminalId);
157     }
158 }
159 
closeActiveTerminal(int sessionId)160 void SessionStack::closeActiveTerminal(int sessionId)
161 {
162     if (sessionId == -1)
163         sessionId = m_activeSessionId;
164     if (sessionId == -1)
165         return;
166     if (!m_sessions.contains(sessionId))
167         return;
168 
169     if (queryClose(sessionId, QueryCloseTerminal))
170         m_sessions.value(sessionId)->closeTerminal();
171 }
172 
cleanup(int sessionId)173 void SessionStack::cleanup(int sessionId)
174 {
175     if (sessionId == m_activeSessionId)
176         m_activeSessionId = -1;
177 
178     m_sessions.remove(sessionId);
179 
180     Q_EMIT sessionRemoved(sessionId);
181 }
182 
activeTerminalId()183 int SessionStack::activeTerminalId()
184 {
185     if (!m_sessions.contains(m_activeSessionId))
186         return -1;
187 
188     return m_sessions.value(m_activeSessionId)->activeTerminalId();
189 }
190 
sessionIdList()191 const QString SessionStack::sessionIdList()
192 {
193     QList<int> keyList = m_sessions.keys();
194     QStringList idList;
195 
196     QListIterator<int> i(keyList);
197 
198     while (i.hasNext())
199         idList << QString::number(i.next());
200 
201     return idList.join(QLatin1Char(','));
202 }
203 
terminalIdList()204 const QString SessionStack::terminalIdList()
205 {
206     QStringList idList;
207 
208     QHashIterator<int, Session *> it(m_sessions);
209 
210     while (it.hasNext()) {
211         it.next();
212 
213         idList << it.value()->terminalIdList();
214     }
215 
216     return idList.join(QLatin1Char(','));
217 }
218 
terminalIdsForSessionId(int sessionId)219 const QString SessionStack::terminalIdsForSessionId(int sessionId)
220 {
221     if (!m_sessions.contains(sessionId))
222         return QString::number(-1);
223 
224     return m_sessions.value(sessionId)->terminalIdList();
225 }
226 
sessionIdForTerminalId(int terminalId)227 int SessionStack::sessionIdForTerminalId(int terminalId)
228 {
229     int sessionId = -1;
230 
231     QHashIterator<int, Session *> it(m_sessions);
232 
233     while (it.hasNext()) {
234         it.next();
235 
236         if (it.value()->hasTerminal(terminalId)) {
237             sessionId = it.key();
238 
239             break;
240         }
241     }
242 
243     return sessionId;
244 }
245 
warnAboutDBus()246 static void warnAboutDBus()
247 {
248 #if !defined(REMOVE_SENDTEXT_RUNCOMMAND_DBUS_METHODS)
249     if (show_disallow_certain_dbus_methods_message) {
250         KNotification::event(
251             KNotification::Warning,
252             QStringLiteral("Yakuake D-Bus Warning"),
253             i18n("The D-Bus method runCommand was just used.  There are security concerns about allowing these methods to be public.  If desired, these "
254                  "methods can be changed to internal use only by re-compiling Yakuake. <p>This warning will only show once for this Yakuake instance.</p>"));
255         show_disallow_certain_dbus_methods_message = false;
256     }
257 #endif
258 }
259 
runCommand(const QString & command)260 void SessionStack::runCommand(const QString &command)
261 {
262     warnAboutDBus();
263 
264     if (m_activeSessionId == -1)
265         return;
266     if (!m_sessions.contains(m_activeSessionId))
267         return;
268 
269     m_sessions.value(m_activeSessionId)->runCommand(command);
270 }
271 
runCommandInTerminal(int terminalId,const QString & command)272 void SessionStack::runCommandInTerminal(int terminalId, const QString &command)
273 {
274     warnAboutDBus();
275 
276     QHashIterator<int, Session *> it(m_sessions);
277 
278     while (it.hasNext()) {
279         it.next();
280 
281         it.value()->runCommand(command, terminalId);
282     }
283 }
284 
isSessionClosable(int sessionId)285 bool SessionStack::isSessionClosable(int sessionId)
286 {
287     if (sessionId == -1)
288         sessionId = m_activeSessionId;
289     if (sessionId == -1)
290         return false;
291     if (!m_sessions.contains(sessionId))
292         return false;
293 
294     return m_sessions.value(sessionId)->closable();
295 }
296 
setSessionClosable(int sessionId,bool closable)297 void SessionStack::setSessionClosable(int sessionId, bool closable)
298 {
299     if (sessionId == -1)
300         sessionId = m_activeSessionId;
301     if (sessionId == -1)
302         return;
303     if (!m_sessions.contains(sessionId))
304         return;
305 
306     m_sessions.value(sessionId)->setClosable(closable);
307 }
308 
hasUnclosableSessions() const309 bool SessionStack::hasUnclosableSessions() const
310 {
311     QHashIterator<int, Session *> it(m_sessions);
312 
313     while (it.hasNext()) {
314         it.next();
315 
316         if (!it.value()->closable())
317             return true;
318     }
319 
320     return false;
321 }
322 
isSessionKeyboardInputEnabled(int sessionId)323 bool SessionStack::isSessionKeyboardInputEnabled(int sessionId)
324 {
325     if (sessionId == -1)
326         sessionId = m_activeSessionId;
327     if (sessionId == -1)
328         return false;
329     if (!m_sessions.contains(sessionId))
330         return false;
331 
332     return m_sessions.value(sessionId)->keyboardInputEnabled();
333 }
334 
setSessionKeyboardInputEnabled(int sessionId,bool enabled)335 void SessionStack::setSessionKeyboardInputEnabled(int sessionId, bool enabled)
336 {
337     if (sessionId == -1)
338         sessionId = m_activeSessionId;
339     if (sessionId == -1)
340         return;
341     if (!m_sessions.contains(sessionId))
342         return;
343 
344     m_sessions.value(sessionId)->setKeyboardInputEnabled(enabled);
345 
346     if (sessionId == m_activeSessionId) {
347         if (enabled)
348             m_visualEventOverlay->hide();
349         else
350             m_visualEventOverlay->show();
351     }
352 }
353 
isTerminalKeyboardInputEnabled(int terminalId)354 bool SessionStack::isTerminalKeyboardInputEnabled(int terminalId)
355 {
356     int sessionId = sessionIdForTerminalId(terminalId);
357     if (sessionId == -1)
358         return false;
359     if (!m_sessions.contains(sessionId))
360         return false;
361 
362     return m_sessions.value(sessionId)->keyboardInputEnabled(terminalId);
363 }
364 
setTerminalKeyboardInputEnabled(int terminalId,bool enabled)365 void SessionStack::setTerminalKeyboardInputEnabled(int terminalId, bool enabled)
366 {
367     int sessionId = sessionIdForTerminalId(terminalId);
368     if (sessionId == -1)
369         return;
370     if (!m_sessions.contains(sessionId))
371         return;
372 
373     m_sessions.value(sessionId)->setKeyboardInputEnabled(terminalId, enabled);
374 
375     if (sessionId == m_activeSessionId) {
376         if (enabled)
377             m_visualEventOverlay->hide();
378         else
379             m_visualEventOverlay->show();
380     }
381 }
382 
hasTerminalsWithKeyboardInputEnabled(int sessionId)383 bool SessionStack::hasTerminalsWithKeyboardInputEnabled(int sessionId)
384 {
385     if (sessionId == -1)
386         sessionId = m_activeSessionId;
387     if (sessionId == -1)
388         return false;
389     if (!m_sessions.contains(sessionId))
390         return false;
391 
392     return m_sessions.value(sessionId)->hasTerminalsWithKeyboardInputEnabled();
393 }
394 
hasTerminalsWithKeyboardInputDisabled(int sessionId)395 bool SessionStack::hasTerminalsWithKeyboardInputDisabled(int sessionId)
396 {
397     if (sessionId == -1)
398         sessionId = m_activeSessionId;
399     if (sessionId == -1)
400         return false;
401     if (!m_sessions.contains(sessionId))
402         return false;
403 
404     return m_sessions.value(sessionId)->hasTerminalsWithKeyboardInputDisabled();
405 }
406 
isSessionMonitorActivityEnabled(int sessionId)407 bool SessionStack::isSessionMonitorActivityEnabled(int sessionId)
408 {
409     if (sessionId == -1)
410         sessionId = m_activeSessionId;
411     if (sessionId == -1)
412         return false;
413     if (!m_sessions.contains(sessionId))
414         return false;
415 
416     return m_sessions.value(sessionId)->monitorActivityEnabled();
417 }
418 
setSessionMonitorActivityEnabled(int sessionId,bool enabled)419 void SessionStack::setSessionMonitorActivityEnabled(int sessionId, bool enabled)
420 {
421     if (sessionId == -1)
422         sessionId = m_activeSessionId;
423     if (sessionId == -1)
424         return;
425     if (!m_sessions.contains(sessionId))
426         return;
427 
428     m_sessions.value(sessionId)->setMonitorActivityEnabled(enabled);
429 }
430 
isTerminalMonitorActivityEnabled(int terminalId)431 bool SessionStack::isTerminalMonitorActivityEnabled(int terminalId)
432 {
433     int sessionId = sessionIdForTerminalId(terminalId);
434     if (sessionId == -1)
435         return false;
436     if (!m_sessions.contains(sessionId))
437         return false;
438 
439     return m_sessions.value(sessionId)->monitorActivityEnabled(terminalId);
440 }
441 
setTerminalMonitorActivityEnabled(int terminalId,bool enabled)442 void SessionStack::setTerminalMonitorActivityEnabled(int terminalId, bool enabled)
443 {
444     int sessionId = sessionIdForTerminalId(terminalId);
445     if (sessionId == -1)
446         return;
447     if (!m_sessions.contains(sessionId))
448         return;
449 
450     m_sessions.value(sessionId)->setMonitorActivityEnabled(terminalId, enabled);
451 }
452 
hasTerminalsWithMonitorActivityEnabled(int sessionId)453 bool SessionStack::hasTerminalsWithMonitorActivityEnabled(int sessionId)
454 {
455     if (sessionId == -1)
456         sessionId = m_activeSessionId;
457     if (sessionId == -1)
458         return false;
459     if (!m_sessions.contains(sessionId))
460         return false;
461 
462     return m_sessions.value(sessionId)->hasTerminalsWithMonitorActivityEnabled();
463 }
464 
hasTerminalsWithMonitorActivityDisabled(int sessionId)465 bool SessionStack::hasTerminalsWithMonitorActivityDisabled(int sessionId)
466 {
467     if (sessionId == -1)
468         sessionId = m_activeSessionId;
469     if (sessionId == -1)
470         return false;
471     if (!m_sessions.contains(sessionId))
472         return false;
473 
474     return m_sessions.value(sessionId)->hasTerminalsWithMonitorActivityDisabled();
475 }
476 
isSessionMonitorSilenceEnabled(int sessionId)477 bool SessionStack::isSessionMonitorSilenceEnabled(int sessionId)
478 {
479     if (sessionId == -1)
480         sessionId = m_activeSessionId;
481     if (sessionId == -1)
482         return false;
483     if (!m_sessions.contains(sessionId))
484         return false;
485 
486     return m_sessions.value(sessionId)->monitorSilenceEnabled();
487 }
488 
setSessionMonitorSilenceEnabled(int sessionId,bool enabled)489 void SessionStack::setSessionMonitorSilenceEnabled(int sessionId, bool enabled)
490 {
491     if (sessionId == -1)
492         sessionId = m_activeSessionId;
493     if (sessionId == -1)
494         return;
495     if (!m_sessions.contains(sessionId))
496         return;
497 
498     m_sessions.value(sessionId)->setMonitorSilenceEnabled(enabled);
499 }
500 
isTerminalMonitorSilenceEnabled(int terminalId)501 bool SessionStack::isTerminalMonitorSilenceEnabled(int terminalId)
502 {
503     int sessionId = sessionIdForTerminalId(terminalId);
504     if (sessionId == -1)
505         return false;
506     if (!m_sessions.contains(sessionId))
507         return false;
508 
509     return m_sessions.value(sessionId)->monitorSilenceEnabled(terminalId);
510 }
511 
setTerminalMonitorSilenceEnabled(int terminalId,bool enabled)512 void SessionStack::setTerminalMonitorSilenceEnabled(int terminalId, bool enabled)
513 {
514     int sessionId = sessionIdForTerminalId(terminalId);
515     if (sessionId == -1)
516         return;
517     if (!m_sessions.contains(sessionId))
518         return;
519 
520     m_sessions.value(sessionId)->setMonitorSilenceEnabled(terminalId, enabled);
521 }
522 
hasTerminalsWithMonitorSilenceEnabled(int sessionId)523 bool SessionStack::hasTerminalsWithMonitorSilenceEnabled(int sessionId)
524 {
525     if (sessionId == -1)
526         sessionId = m_activeSessionId;
527     if (sessionId == -1)
528         return false;
529     if (!m_sessions.contains(sessionId))
530         return false;
531 
532     return m_sessions.value(sessionId)->hasTerminalsWithMonitorSilenceEnabled();
533 }
534 
hasTerminalsWithMonitorSilenceDisabled(int sessionId)535 bool SessionStack::hasTerminalsWithMonitorSilenceDisabled(int sessionId)
536 {
537     if (sessionId == -1)
538         sessionId = m_activeSessionId;
539     if (sessionId == -1)
540         return false;
541     if (!m_sessions.contains(sessionId))
542         return false;
543 
544     return m_sessions.value(sessionId)->hasTerminalsWithMonitorSilenceDisabled();
545 }
546 
editProfile(int sessionId)547 void SessionStack::editProfile(int sessionId)
548 {
549     if (sessionId == -1)
550         sessionId = m_activeSessionId;
551     if (sessionId == -1)
552         return;
553     if (!m_sessions.contains(sessionId))
554         return;
555 
556     m_sessions.value(sessionId)->editProfile();
557 }
558 
splitSessionLeftRight(int sessionId)559 int SessionStack::splitSessionLeftRight(int sessionId)
560 {
561     if (sessionId == -1)
562         return -1;
563     if (!m_sessions.contains(sessionId))
564         return -1;
565 
566     return m_sessions.value(sessionId)->splitLeftRight();
567 }
568 
splitSessionTopBottom(int sessionId)569 int SessionStack::splitSessionTopBottom(int sessionId)
570 {
571     if (sessionId == -1)
572         return -1;
573     if (!m_sessions.contains(sessionId))
574         return -1;
575 
576     return m_sessions.value(sessionId)->splitTopBottom();
577 }
578 
splitTerminalLeftRight(int terminalId)579 int SessionStack::splitTerminalLeftRight(int terminalId)
580 {
581     int sessionId = sessionIdForTerminalId(terminalId);
582 
583     if (sessionId == -1)
584         return -1;
585 
586     return m_sessions.value(sessionId)->splitLeftRight(terminalId);
587 }
588 
splitTerminalTopBottom(int terminalId)589 int SessionStack::splitTerminalTopBottom(int terminalId)
590 {
591     int sessionId = sessionIdForTerminalId(terminalId);
592 
593     if (sessionId == -1)
594         return -1;
595 
596     return m_sessions.value(sessionId)->splitTopBottom(terminalId);
597 }
598 
tryGrowTerminalRight(int terminalId,uint pixels)599 int SessionStack::tryGrowTerminalRight(int terminalId, uint pixels)
600 {
601     int sessionId = sessionIdForTerminalId(terminalId);
602 
603     if (sessionId == -1)
604         return -1;
605 
606     return m_sessions.value(sessionId)->tryGrowTerminal(terminalId, Session::Right, pixels);
607 }
608 
tryGrowTerminalLeft(int terminalId,uint pixels)609 int SessionStack::tryGrowTerminalLeft(int terminalId, uint pixels)
610 {
611     int sessionId = sessionIdForTerminalId(terminalId);
612 
613     if (sessionId == -1)
614         return -1;
615 
616     return m_sessions.value(sessionId)->tryGrowTerminal(terminalId, Session::Left, pixels);
617 }
618 
tryGrowTerminalTop(int terminalId,uint pixels)619 int SessionStack::tryGrowTerminalTop(int terminalId, uint pixels)
620 {
621     int sessionId = sessionIdForTerminalId(terminalId);
622 
623     if (sessionId == -1)
624         return -1;
625 
626     return m_sessions.value(sessionId)->tryGrowTerminal(terminalId, Session::Up, pixels);
627 }
628 
tryGrowTerminalBottom(int terminalId,uint pixels)629 int SessionStack::tryGrowTerminalBottom(int terminalId, uint pixels)
630 {
631     int sessionId = sessionIdForTerminalId(terminalId);
632 
633     if (sessionId == -1)
634         return -1;
635 
636     return m_sessions.value(sessionId)->tryGrowTerminal(terminalId, Session::Down, pixels);
637 }
638 
emitTitles()639 void SessionStack::emitTitles()
640 {
641     QString title;
642 
643     QHashIterator<int, Session *> it(m_sessions);
644 
645     while (it.hasNext()) {
646         it.next();
647 
648         title = it.value()->title();
649 
650         if (!title.isEmpty())
651             Q_EMIT titleChanged(it.value()->id(), title);
652     }
653 }
654 
requiresVisualEventOverlay()655 bool SessionStack::requiresVisualEventOverlay()
656 {
657     if (m_activeSessionId == -1)
658         return false;
659     if (!m_sessions.contains(m_activeSessionId))
660         return false;
661 
662     return m_sessions.value(m_activeSessionId)->hasTerminalsWithKeyboardInputDisabled();
663 }
664 
handleTerminalHighlightRequest(int terminalId)665 void SessionStack::handleTerminalHighlightRequest(int terminalId)
666 {
667     Terminal *terminal = nullptr;
668 
669     QHashIterator<int, Session *> it(m_sessions);
670 
671     while (it.hasNext()) {
672         it.next();
673 
674         terminal = it.value()->getTerminal(terminalId);
675 
676         if (terminal && it.value()->id() == m_activeSessionId) {
677             m_visualEventOverlay->highlightTerminal(terminal, true);
678 
679             break;
680         }
681     }
682 }
683 
showEvent(QShowEvent * event)684 void SessionStack::showEvent(QShowEvent *event)
685 {
686     Q_UNUSED(event)
687 
688     if (m_activeSessionId == -1)
689         return;
690     if (!m_sessions.contains(m_activeSessionId))
691         return;
692 
693     Terminal *terminal = m_sessions.value(m_activeSessionId)->getTerminal(activeTerminalId());
694 
695     if (terminal) {
696         QWidget *terminalWidget = terminal->terminalWidget();
697         if (terminalWidget)
698             terminalWidget->setFocus();
699     }
700 }
701 
handleManualTerminalActivation(Terminal * terminal)702 void SessionStack::handleManualTerminalActivation(Terminal *terminal)
703 {
704     if (!Settings::terminalHighlightOnManualActivation())
705         return;
706 
707     Session *session = qobject_cast<Session *>(QObject::sender());
708 
709     if (session->terminalCount() > 1)
710         m_visualEventOverlay->highlightTerminal(terminal, false);
711 }
712 
queryClose(int sessionId,QueryCloseType type)713 bool SessionStack::queryClose(int sessionId, QueryCloseType type)
714 {
715     if (!m_sessions.contains(sessionId))
716         return false;
717 
718     if (!m_sessions.value(sessionId)->closable()) {
719         QString closeQuestionIntro = xi18nc("@info", "<warning>You have locked this session to prevent accidental closing of terminals.</warning>");
720         QString closeQuestion;
721 
722         if (type == QueryCloseSession)
723             closeQuestion = xi18nc("@info", "Are you sure you want to close this session?");
724         else if (type == QueryCloseTerminal)
725             closeQuestion = xi18nc("@info", "Are you sure you want to close this terminal?");
726 
727         int result = KMessageBox::warningContinueCancel(this,
728                                                         closeQuestionIntro + QStringLiteral("<br/><br/>") + closeQuestion,
729                                                         xi18nc("@title:window", "Really Close?"),
730                                                         KStandardGuiItem::close(),
731                                                         KStandardGuiItem::cancel());
732 
733         if (result != KMessageBox::Continue)
734             return false;
735     }
736 
737     return true;
738 }
739 
getPartActionCollections()740 QList<KActionCollection *> SessionStack::getPartActionCollections()
741 {
742     QList<KActionCollection *> actionCollections;
743 
744     const auto sessions = m_sessions.values();
745     for (auto *session : sessions) {
746         const auto terminalIds = session->terminalIdList().split(QStringLiteral(","));
747 
748         for (const auto &terminalID : terminalIds) {
749             auto *terminal = session->getTerminal(terminalID.toInt());
750             if (terminal) {
751                 auto *collection = terminal->actionCollection();
752                 if (collection) {
753                     actionCollections.append(collection);
754                 }
755             }
756         }
757     }
758 
759     return actionCollections;
760 }
761