File indexing completed on 2024-11-10 04:56:51
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2008 Lubos Lunak <l.lunak@suse.cz> 0006 SPDX-FileCopyrightText: 2009 Lucas Murray <lmurray@undefinedfire.com> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 #include "monitor.h" 0012 0013 #include <KLocalizedString> 0014 #include <KSvg/FrameSvg> 0015 0016 #include <QApplication> 0017 #include <QDebug> 0018 #include <QGraphicsScene> 0019 #include <QGraphicsSceneEvent> 0020 #include <QGraphicsView> 0021 #include <QMenu> 0022 #include <QScreen> 0023 #include <QWindow> 0024 0025 namespace KWin 0026 { 0027 0028 static QScreen *screenFromWidget(const QWidget *widget) 0029 { 0030 QScreen *screen = widget->screen(); 0031 if (screen) { 0032 return screen; 0033 } 0034 0035 return QGuiApplication::primaryScreen(); 0036 } 0037 0038 Monitor::Monitor(QWidget *parent) 0039 : ScreenPreviewWidget(parent) 0040 { 0041 for (auto &popup : m_popups) { 0042 popup = std::make_unique<QMenu>(this); 0043 } 0044 m_scene = std::make_unique<QGraphicsScene>(this); 0045 m_view = std::make_unique<QGraphicsView>(m_scene.get(), this); 0046 m_view->setBackgroundBrush(Qt::black); 0047 m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0048 m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 0049 m_view->setFocusPolicy(Qt::NoFocus); 0050 m_view->setFrameShape(QFrame::NoFrame); 0051 for (size_t i = 0; i < m_items.size(); i++) { 0052 m_items[i] = std::make_unique<Corner>(this); 0053 m_scene->addItem(m_items[i].get()); 0054 m_hidden[i] = false; 0055 m_actionGroups[i] = std::make_unique<QActionGroup>(this); 0056 } 0057 QRect avail = screenFromWidget(this)->geometry(); 0058 setMinimumContentWidth(20 * 3 + 5 * 2); // 3 buttons in a row and some spacing between them 0059 setRatio((qreal)avail.width() / (qreal)avail.height()); 0060 checkSize(); 0061 } 0062 0063 Monitor::~Monitor() = default; 0064 0065 void Monitor::clear() 0066 { 0067 for (size_t i = 0; i < m_popups.size(); i++) { 0068 m_popups[i]->clear(); 0069 m_items[i]->setActive(false); 0070 setEdgeHidden(i, false); 0071 m_actionGroups[i] = std::make_unique<QActionGroup>(this); 0072 } 0073 } 0074 0075 void Monitor::resizeEvent(QResizeEvent *e) 0076 { 0077 ScreenPreviewWidget::resizeEvent(e); 0078 checkSize(); 0079 } 0080 0081 bool Monitor::event(QEvent *event) 0082 { 0083 const bool r = ScreenPreviewWidget::event(event); 0084 if (event->type() == QEvent::ScreenChangeInternal) { 0085 QRect avail = screenFromWidget(this)->geometry(); 0086 setRatio((qreal)avail.width() / (qreal)avail.height()); 0087 checkSize(); 0088 } 0089 return r; 0090 } 0091 0092 void Monitor::checkSize() 0093 { 0094 QRect contentsRect = previewRect(); 0095 m_view->setGeometry(contentsRect); 0096 m_scene->setSceneRect(QRect(QPoint(0, 0), contentsRect.size())); 0097 const int x2 = (contentsRect.width() - 20) / 2; 0098 const int x3 = contentsRect.width() - 20; 0099 const int y2 = (contentsRect.height() - 20) / 2; 0100 const int y3 = contentsRect.height() - 20; 0101 m_items[0]->setRect(0, y2, 20, 20); 0102 m_items[1]->setRect(x3, y2, 20, 20); 0103 m_items[2]->setRect(x2, 0, 20, 20); 0104 m_items[3]->setRect(x2, y3, 20, 20); 0105 m_items[4]->setRect(0, 0, 20, 20); 0106 m_items[5]->setRect(x3, 0, 20, 20); 0107 m_items[6]->setRect(0, y3, 20, 20); 0108 m_items[7]->setRect(x3, y3, 20, 20); 0109 } 0110 0111 void Monitor::setEdgeEnabled(int edge, bool enabled) 0112 { 0113 for (QAction *action : std::as_const(m_popupActions[edge])) { 0114 action->setEnabled(enabled); 0115 } 0116 } 0117 0118 void Monitor::setEdgeHidden(int edge, bool set) 0119 { 0120 m_hidden[edge] = set; 0121 if (set) { 0122 m_items[edge]->hide(); 0123 } else { 0124 m_items[edge]->show(); 0125 } 0126 } 0127 0128 bool Monitor::edgeHidden(int edge) const 0129 { 0130 return m_hidden[edge]; 0131 } 0132 0133 void Monitor::addEdgeItem(int edge, const QString &item) 0134 { 0135 QAction *act = m_popups[edge]->addAction(item); 0136 act->setCheckable(true); 0137 m_popupActions[edge].append(act); 0138 m_actionGroups[edge]->addAction(act); 0139 if (m_popupActions[edge].count() == 1) { 0140 act->setChecked(true); 0141 m_items[edge]->setToolTip(item); 0142 } 0143 m_items[edge]->setActive(!m_popupActions[edge].front()->isChecked()); 0144 } 0145 0146 void Monitor::setEdgeItemEnabled(int edge, int index, bool enabled) 0147 { 0148 m_popupActions[edge][index]->setEnabled(enabled); 0149 } 0150 0151 bool Monitor::edgeItemEnabled(int edge, int index) const 0152 { 0153 return m_popupActions[edge][index]->isEnabled(); 0154 } 0155 0156 void Monitor::selectEdgeItem(int edge, int index) 0157 { 0158 m_popupActions[edge][index]->setChecked(true); 0159 m_items[edge]->setActive(!m_popupActions[edge].front()->isChecked()); 0160 QString actionText = m_popupActions[edge][index]->text(); 0161 // remove accelerators added by KAcceleratorManager 0162 actionText = KLocalizedString::removeAcceleratorMarker(actionText); 0163 m_items[edge]->setToolTip(actionText); 0164 } 0165 0166 int Monitor::selectedEdgeItem(int edge) const 0167 { 0168 const auto &actions = m_popupActions[edge]; 0169 for (QAction *act : actions) { 0170 if (act->isChecked()) { 0171 return actions.indexOf(act); 0172 } 0173 } 0174 Q_UNREACHABLE(); 0175 } 0176 0177 void Monitor::popup(Corner *c, QPoint pos) 0178 { 0179 for (size_t i = 0; i < m_items.size(); i++) { 0180 if (m_items[i].get() == c) { 0181 if (m_popupActions[i].empty()) { 0182 return; 0183 } 0184 if (QAction *a = m_popups[i]->exec(pos)) { 0185 selectEdgeItem(i, m_popupActions[i].indexOf(a)); 0186 Q_EMIT changed(); 0187 Q_EMIT edgeSelectionChanged(i, m_popupActions[i].indexOf(a)); 0188 c->setToolTip(KLocalizedString::removeAcceleratorMarker(a->text())); 0189 } 0190 return; 0191 } 0192 } 0193 Q_UNREACHABLE(); 0194 } 0195 0196 void Monitor::flip(Corner *c, QPoint pos) 0197 { 0198 for (size_t i = 0; i < m_items.size(); i++) { 0199 if (m_items[i].get() == c) { 0200 if (m_popupActions[i].empty()) { 0201 m_items[i]->setActive(m_items[i]->brush() != Qt::green); 0202 } else { 0203 popup(c, pos); 0204 } 0205 return; 0206 } 0207 } 0208 Q_UNREACHABLE(); 0209 } 0210 0211 Monitor::Corner::Corner(Monitor *m) 0212 : m_monitor(m) 0213 , m_button(std::make_unique<KSvg::FrameSvg>()) 0214 { 0215 m_button->setImageSet(m->svgImageSet()); 0216 m_button->setImagePath("widgets/button"); 0217 setAcceptHoverEvents(true); 0218 } 0219 0220 Monitor::Corner::~Corner() = default; 0221 0222 void Monitor::Corner::contextMenuEvent(QGraphicsSceneContextMenuEvent *e) 0223 { 0224 m_monitor->popup(this, e->screenPos()); 0225 } 0226 0227 void Monitor::Corner::mousePressEvent(QGraphicsSceneMouseEvent *e) 0228 { 0229 m_monitor->flip(this, e->screenPos()); 0230 } 0231 0232 void Monitor::Corner::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) 0233 { 0234 if (m_hover) { 0235 m_button->setElementPrefix("normal"); 0236 0237 qreal left, top, right, bottom; 0238 m_button->getMargins(left, top, right, bottom); 0239 0240 m_button->setElementPrefix("active"); 0241 qreal activeLeft, activeTop, activeRight, activeBottom; 0242 m_button->getMargins(activeLeft, activeTop, activeRight, activeBottom); 0243 0244 QRectF activeRect = QRectF(QPointF(0, 0), rect().size()); 0245 activeRect.adjust(left - activeLeft, top - activeTop, 0246 -(right - activeRight), -(bottom - activeBottom)); 0247 m_button->setElementPrefix("active"); 0248 m_button->resizeFrame(activeRect.size()); 0249 m_button->paintFrame(painter, rect().topLeft() + activeRect.topLeft()); 0250 } else { 0251 m_button->setElementPrefix(m_active ? "pressed" : "normal"); 0252 m_button->resizeFrame(rect().size()); 0253 m_button->paintFrame(painter, rect().topLeft()); 0254 } 0255 0256 if (m_active) { 0257 QPainterPath roundedRect; 0258 painter->setRenderHint(QPainter::Antialiasing); 0259 roundedRect.addRoundedRect(rect().adjusted(5, 5, -5, -5), 2, 2); 0260 painter->fillPath(roundedRect, QApplication::palette().text()); 0261 } 0262 } 0263 0264 void Monitor::Corner::hoverEnterEvent(QGraphicsSceneHoverEvent *e) 0265 { 0266 m_hover = true; 0267 update(); 0268 } 0269 0270 void Monitor::Corner::hoverLeaveEvent(QGraphicsSceneHoverEvent *e) 0271 { 0272 m_hover = false; 0273 update(); 0274 } 0275 0276 void Monitor::Corner::setActive(bool active) 0277 { 0278 m_active = active; 0279 update(); 0280 } 0281 0282 bool Monitor::Corner::active() const 0283 { 0284 return m_active; 0285 } 0286 } // namespace 0287 0288 #include "moc_monitor.cpp"