File indexing completed on 2024-05-05 05:57:02
0001 /* 0002 SPDX-FileCopyrightText: 2009 Eike Hein <hein@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "visualeventoverlay.h" 0008 #include "sessionstack.h" 0009 #include "settings.h" 0010 #include "terminal.h" 0011 0012 #include <KColorScheme> 0013 #include <KStatefulBrush> 0014 0015 #include <QPainter> 0016 #include <QTimer> 0017 0018 EventRect::EventRect(const QPoint &topLeft, const QPoint &bottomRight, EventType type, EventFlags flags) 0019 : QRect(topLeft, bottomRight) 0020 { 0021 m_eventType = type; 0022 0023 m_eventFlags = flags; 0024 0025 m_timeStamp.start(); 0026 } 0027 0028 EventRect::~EventRect() 0029 { 0030 } 0031 0032 bool EventRect::operator==(const EventRect &eventRect) const 0033 { 0034 if (m_eventType == eventRect.eventType() && eventRect.testFlag(EventRect::Singleton)) 0035 return true; 0036 0037 if (m_eventType != eventRect.eventType()) 0038 return false; 0039 0040 return x() == eventRect.x() && y() == eventRect.y() && width() == eventRect.width() && height() == eventRect.height(); 0041 } 0042 0043 bool EventRect::operator<(const EventRect &eventRect) const 0044 { 0045 if (!testFlag(EventRect::Exclusive) && eventRect.testFlag(EventRect::Exclusive)) 0046 return false; 0047 if (m_eventType < eventRect.eventType()) 0048 return true; 0049 else if (m_timeStamp < eventRect.timeStamp()) 0050 return true; 0051 0052 return false; 0053 } 0054 0055 VisualEventOverlay::VisualEventOverlay(SessionStack *parent) 0056 : QWidget(parent) 0057 { 0058 m_sessionStack = parent; 0059 0060 setAutoFillBackground(false); 0061 0062 setAttribute(Qt::WA_TranslucentBackground, true); 0063 0064 setFocusPolicy(Qt::NoFocus); 0065 setAttribute(Qt::WA_TransparentForMouseEvents, true); 0066 0067 m_cleanupTimer = new QTimer(this); 0068 m_cleanupTimer->setSingleShot(true); 0069 connect(m_cleanupTimer, SIGNAL(timeout()), this, SLOT(cleanupOverlay())); 0070 0071 m_cleanupTimerCeiling = 0; 0072 0073 hide(); 0074 } 0075 0076 VisualEventOverlay::~VisualEventOverlay() 0077 { 0078 } 0079 0080 void VisualEventOverlay::highlightTerminal(Terminal *terminal, bool persistent) 0081 { 0082 if (!persistent && Settings::terminalHighlightDuration() == 0) 0083 return; 0084 0085 if (isHidden()) 0086 show(); 0087 0088 EventRect::EventFlags flags = EventRect::Singleton | EventRect::Exclusive; 0089 if (persistent) 0090 flags |= EventRect::Persistent; 0091 0092 terminalEvent(terminal, EventRect::TerminalHighlight, flags); 0093 0094 if (!persistent) 0095 scheduleCleanup(Settings::terminalHighlightDuration()); 0096 } 0097 0098 void VisualEventOverlay::removeTerminalHighlight() 0099 { 0100 if (!m_eventRects.count()) 0101 return; 0102 0103 QMutableListIterator<EventRect> i(m_eventRects); 0104 0105 while (i.hasNext()) { 0106 if (i.next().eventType() == EventRect::TerminalHighlight) 0107 i.remove(); 0108 } 0109 0110 if (m_sessionStack->requiresVisualEventOverlay()) 0111 update(); 0112 else 0113 hide(); 0114 } 0115 0116 void VisualEventOverlay::indicateKeyboardInputBlocked(Terminal *terminal) 0117 { 0118 if (Settings::keyboardInputBlockIndicatorDuration() == 0) 0119 return; 0120 0121 terminalEvent(terminal, EventRect::KeyboardInputBlocked); 0122 0123 scheduleCleanup(Settings::keyboardInputBlockIndicatorDuration()); 0124 } 0125 0126 void VisualEventOverlay::terminalEvent(Terminal *terminal, EventRect::EventType type, EventRect::EventFlags flags) 0127 { 0128 QRect partRect(terminal->partWidget()->rect()); 0129 const QWidget *partWidget = terminal->partWidget(); 0130 0131 QPoint topLeft(partWidget->mapTo(parentWidget(), partRect.topLeft())); 0132 QPoint bottomRight(partWidget->mapTo(parentWidget(), partRect.bottomRight())); 0133 0134 EventRect eventRect(topLeft, bottomRight, type, flags); 0135 0136 m_eventRects.removeAll(eventRect); 0137 m_eventRects.append(eventRect); 0138 0139 std::sort(m_eventRects.begin(), m_eventRects.end()); 0140 0141 update(); 0142 } 0143 0144 void VisualEventOverlay::paintEvent(QPaintEvent *) 0145 { 0146 if (!m_eventRects.count()) 0147 return; 0148 0149 QPainter painter(this); 0150 0151 m_time.start(); 0152 bool painted = false; 0153 0154 QListIterator<EventRect> i(m_eventRects); 0155 0156 while (i.hasNext()) { 0157 const EventRect &eventRect = i.next(); 0158 0159 painted = false; 0160 0161 if (eventRect.eventType() == EventRect::TerminalHighlight 0162 && (eventRect.timeStamp().msecsTo(m_time) <= Settings::terminalHighlightDuration() || eventRect.testFlag(EventRect::Persistent))) { 0163 KStatefulBrush terminalHighlightBrush(KColorScheme::View, KColorScheme::HoverColor); 0164 0165 painter.setOpacity(Settings::terminalHighlightOpacity()); 0166 0167 painter.fillRect(eventRect, terminalHighlightBrush.brush(palette())); 0168 0169 painted = true; 0170 } else if (eventRect.eventType() == EventRect::KeyboardInputBlocked 0171 && eventRect.timeStamp().msecsTo(m_time) <= Settings::keyboardInputBlockIndicatorDuration()) { 0172 painter.setOpacity(Settings::keyboardInputBlockIndicatorOpacity()); 0173 0174 painter.fillRect(eventRect, Settings::keyboardInputBlockIndicatorColor()); 0175 0176 painted = true; 0177 } 0178 0179 if (painted && i.hasNext() && eventRect.testFlag(EventRect::Exclusive)) { 0180 if (!painter.hasClipping()) 0181 painter.setClipRect(rect()); 0182 0183 painter.setClipRegion(painter.clipRegion().subtracted(eventRect)); 0184 } 0185 } 0186 } 0187 0188 void VisualEventOverlay::showEvent(QShowEvent *) 0189 { 0190 resize(parentWidget()->rect().size()); 0191 0192 raise(); 0193 } 0194 0195 void VisualEventOverlay::hideEvent(QHideEvent *) 0196 { 0197 m_cleanupTimer->stop(); 0198 0199 m_eventRects.clear(); 0200 } 0201 0202 void VisualEventOverlay::scheduleCleanup(int in) 0203 { 0204 int left = (m_cleanupTimerStarted.isValid())? m_cleanupTimerCeiling - m_cleanupTimerStarted.elapsed() : 0; 0205 0206 if (in > left) { 0207 m_cleanupTimerCeiling = in; 0208 m_cleanupTimerStarted.start(); 0209 m_cleanupTimer->start(in); 0210 } 0211 } 0212 0213 void VisualEventOverlay::cleanupOverlay() 0214 { 0215 if (m_eventRects.count()) { 0216 m_time.start(); 0217 0218 QMutableListIterator<EventRect> i(m_eventRects); 0219 0220 while (i.hasNext()) { 0221 const EventRect &eventRect = i.next(); 0222 0223 if (eventRect.eventType() == EventRect::TerminalHighlight && eventRect.timeStamp().msecsTo(m_time) >= Settings::terminalHighlightDuration() 0224 && !eventRect.testFlag(EventRect::Persistent)) { 0225 i.remove(); 0226 } else if (eventRect.eventType() == EventRect::KeyboardInputBlocked 0227 && eventRect.timeStamp().msecsTo(m_time) >= Settings::keyboardInputBlockIndicatorDuration()) { 0228 i.remove(); 0229 } 0230 } 0231 } 0232 0233 if (m_sessionStack->requiresVisualEventOverlay()) 0234 update(); 0235 else 0236 hide(); 0237 } 0238 0239 #include "moc_visualeventoverlay.cpp"