KWin
Loading...
Searching...
No Matches
monitor.cpp
Go to the documentation of this file.
1/*
2 KWin - the KDE window manager
3 This file is part of the KDE project.
4
5 SPDX-FileCopyrightText: 2008 Lubos Lunak <l.lunak@suse.cz>
6 SPDX-FileCopyrightText: 2009 Lucas Murray <lmurray@undefinedfire.com>
7
8 SPDX-License-Identifier: GPL-2.0-or-later
9*/
10
11#include "monitor.h"
12
13#include <KLocalizedString>
14#include <KSvg/FrameSvg>
15
16#include <QApplication>
17#include <QDebug>
18#include <QGraphicsScene>
19#include <QGraphicsSceneEvent>
20#include <QGraphicsView>
21#include <QMenu>
22#include <QScreen>
23#include <QWindow>
24
25namespace KWin
26{
27
28static QScreen *screenFromWidget(const QWidget *widget)
29{
30 QScreen *screen = widget->screen();
31 if (screen) {
32 return screen;
33 }
34
35 return QGuiApplication::primaryScreen();
36}
37
38Monitor::Monitor(QWidget *parent)
39 : ScreenPreviewWidget(parent)
40{
41 for (auto &popup : m_popups) {
42 popup = std::make_unique<QMenu>(this);
43 }
44 m_scene = std::make_unique<QGraphicsScene>(this);
45 m_view = std::make_unique<QGraphicsView>(m_scene.get(), this);
46 m_view->setBackgroundBrush(Qt::black);
47 m_view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
48 m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
49 m_view->setFocusPolicy(Qt::NoFocus);
50 m_view->setFrameShape(QFrame::NoFrame);
51 for (size_t i = 0; i < m_items.size(); i++) {
52 m_items[i] = std::make_unique<Corner>(this);
53 m_scene->addItem(m_items[i].get());
54 m_hidden[i] = false;
55 m_actionGroups[i] = std::make_unique<QActionGroup>(this);
56 }
57 QRect avail = screenFromWidget(this)->geometry();
58 setMinimumContentWidth(20 * 3 + 5 * 2); // 3 buttons in a row and some spacing between them
59 setRatio((qreal)avail.width() / (qreal)avail.height());
60 checkSize();
61}
62
63Monitor::~Monitor() = default;
64
66{
67 for (size_t i = 0; i < m_popups.size(); i++) {
68 m_popups[i]->clear();
69 m_items[i]->setActive(false);
70 setEdgeHidden(i, false);
71 m_actionGroups[i] = std::make_unique<QActionGroup>(this);
72 }
73}
74
75void Monitor::resizeEvent(QResizeEvent *e)
76{
78 checkSize();
79}
80
81bool Monitor::event(QEvent *event)
82{
83 const bool r = ScreenPreviewWidget::event(event);
84 if (event->type() == QEvent::ScreenChangeInternal) {
85 QRect avail = screenFromWidget(this)->geometry();
86 setRatio((qreal)avail.width() / (qreal)avail.height());
87 checkSize();
88 }
89 return r;
90}
91
92void Monitor::checkSize()
93{
94 QRect contentsRect = previewRect();
95 m_view->setGeometry(contentsRect);
96 m_scene->setSceneRect(QRect(QPoint(0, 0), contentsRect.size()));
97 const int x2 = (contentsRect.width() - 20) / 2;
98 const int x3 = contentsRect.width() - 20;
99 const int y2 = (contentsRect.height() - 20) / 2;
100 const int y3 = contentsRect.height() - 20;
101 m_items[0]->setRect(0, y2, 20, 20);
102 m_items[1]->setRect(x3, y2, 20, 20);
103 m_items[2]->setRect(x2, 0, 20, 20);
104 m_items[3]->setRect(x2, y3, 20, 20);
105 m_items[4]->setRect(0, 0, 20, 20);
106 m_items[5]->setRect(x3, 0, 20, 20);
107 m_items[6]->setRect(0, y3, 20, 20);
108 m_items[7]->setRect(x3, y3, 20, 20);
109}
110
111void Monitor::setEdgeEnabled(int edge, bool enabled)
112{
113 for (QAction *action : std::as_const(m_popupActions[edge])) {
114 action->setEnabled(enabled);
115 }
116}
117
118void Monitor::setEdgeHidden(int edge, bool set)
119{
120 m_hidden[edge] = set;
121 if (set) {
122 m_items[edge]->hide();
123 } else {
124 m_items[edge]->show();
125 }
126}
127
128bool Monitor::edgeHidden(int edge) const
129{
130 return m_hidden[edge];
131}
132
133void Monitor::addEdgeItem(int edge, const QString &item)
134{
135 QAction *act = m_popups[edge]->addAction(item);
136 act->setCheckable(true);
137 m_popupActions[edge].append(act);
138 m_actionGroups[edge]->addAction(act);
139 if (m_popupActions[edge].count() == 1) {
140 act->setChecked(true);
141 m_items[edge]->setToolTip(item);
142 }
143 m_items[edge]->setActive(!m_popupActions[edge].front()->isChecked());
144}
145
146void Monitor::setEdgeItemEnabled(int edge, int index, bool enabled)
147{
148 m_popupActions[edge][index]->setEnabled(enabled);
149}
150
151bool Monitor::edgeItemEnabled(int edge, int index) const
152{
153 return m_popupActions[edge][index]->isEnabled();
154}
155
156void Monitor::selectEdgeItem(int edge, int index)
157{
158 m_popupActions[edge][index]->setChecked(true);
159 m_items[edge]->setActive(!m_popupActions[edge].front()->isChecked());
160 QString actionText = m_popupActions[edge][index]->text();
161 // remove accelerators added by KAcceleratorManager
162 actionText = KLocalizedString::removeAcceleratorMarker(actionText);
163 m_items[edge]->setToolTip(actionText);
164}
165
166int Monitor::selectedEdgeItem(int edge) const
167{
168 const auto &actions = m_popupActions[edge];
169 for (QAction *act : actions) {
170 if (act->isChecked()) {
171 return actions.indexOf(act);
172 }
173 }
174 Q_UNREACHABLE();
175}
176
177void Monitor::popup(Corner *c, QPoint pos)
178{
179 for (size_t i = 0; i < m_items.size(); i++) {
180 if (m_items[i].get() == c) {
181 if (m_popupActions[i].empty()) {
182 return;
183 }
184 if (QAction *a = m_popups[i]->exec(pos)) {
185 selectEdgeItem(i, m_popupActions[i].indexOf(a));
186 Q_EMIT changed();
187 Q_EMIT edgeSelectionChanged(i, m_popupActions[i].indexOf(a));
188 c->setToolTip(KLocalizedString::removeAcceleratorMarker(a->text()));
189 }
190 return;
191 }
192 }
193 Q_UNREACHABLE();
194}
195
196void Monitor::flip(Corner *c, QPoint pos)
197{
198 for (size_t i = 0; i < m_items.size(); i++) {
199 if (m_items[i].get() == c) {
200 if (m_popupActions[i].empty()) {
201 m_items[i]->setActive(m_items[i]->brush() != Qt::green);
202 } else {
203 popup(c, pos);
204 }
205 return;
206 }
207 }
208 Q_UNREACHABLE();
209}
210
212 : m_monitor(m)
213 , m_button(std::make_unique<KSvg::FrameSvg>())
214{
215 m_button->setImageSet(m->svgImageSet());
216 m_button->setImagePath("widgets/button");
217 setAcceptHoverEvents(true);
218}
219
220Monitor::Corner::~Corner() = default;
221
222void Monitor::Corner::contextMenuEvent(QGraphicsSceneContextMenuEvent *e)
223{
224 m_monitor->popup(this, e->screenPos());
225}
226
227void Monitor::Corner::mousePressEvent(QGraphicsSceneMouseEvent *e)
228{
229 m_monitor->flip(this, e->screenPos());
230}
231
232void Monitor::Corner::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
233{
234 if (m_hover) {
235 m_button->setElementPrefix("normal");
236
237 qreal left, top, right, bottom;
238 m_button->getMargins(left, top, right, bottom);
239
240 m_button->setElementPrefix("active");
241 qreal activeLeft, activeTop, activeRight, activeBottom;
242 m_button->getMargins(activeLeft, activeTop, activeRight, activeBottom);
243
244 QRectF activeRect = QRectF(QPointF(0, 0), rect().size());
245 activeRect.adjust(left - activeLeft, top - activeTop,
246 -(right - activeRight), -(bottom - activeBottom));
247 m_button->setElementPrefix("active");
248 m_button->resizeFrame(activeRect.size());
249 m_button->paintFrame(painter, rect().topLeft() + activeRect.topLeft());
250 } else {
251 m_button->setElementPrefix(m_active ? "pressed" : "normal");
252 m_button->resizeFrame(rect().size());
253 m_button->paintFrame(painter, rect().topLeft());
254 }
255
256 if (m_active) {
257 QPainterPath roundedRect;
258 painter->setRenderHint(QPainter::Antialiasing);
259 roundedRect.addRoundedRect(rect().adjusted(5, 5, -5, -5), 2, 2);
260 painter->fillPath(roundedRect, QApplication::palette().text());
261 }
262}
263
264void Monitor::Corner::hoverEnterEvent(QGraphicsSceneHoverEvent *e)
265{
266 m_hover = true;
267 update();
268}
269
270void Monitor::Corner::hoverLeaveEvent(QGraphicsSceneHoverEvent *e)
271{
272 m_hover = false;
273 update();
274}
275
277{
278 m_active = active;
279 update();
280}
281
283{
284 return m_active;
285}
286} // namespace
287
288#include "moc_monitor.cpp"
bool active() const
Definition monitor.cpp:282
void mousePressEvent(QGraphicsSceneMouseEvent *e) override
Definition monitor.cpp:227
void contextMenuEvent(QGraphicsSceneContextMenuEvent *e) override
Definition monitor.cpp:222
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget=nullptr) override
Definition monitor.cpp:232
void hoverEnterEvent(QGraphicsSceneHoverEvent *e) override
Definition monitor.cpp:264
void setActive(bool active)
Definition monitor.cpp:276
void hoverLeaveEvent(QGraphicsSceneHoverEvent *e) override
Definition monitor.cpp:270
bool edgeHidden(int edge) const
Definition monitor.cpp:128
int selectedEdgeItem(int edge) const
Definition monitor.cpp:166
void selectEdgeItem(int edge, int index)
Definition monitor.cpp:156
bool edgeItemEnabled(int edge, int index) const
Definition monitor.cpp:151
void clear()
Definition monitor.cpp:65
void addEdgeItem(int edge, const QString &item)
Definition monitor.cpp:133
void setEdgeEnabled(int edge, bool enabled)
Definition monitor.cpp:111
bool event(QEvent *event) override
Definition monitor.cpp:81
void resizeEvent(QResizeEvent *e) override
Definition monitor.cpp:75
void setEdgeHidden(int edge, bool set)
Definition monitor.cpp:118
void setEdgeItemEnabled(int edge, int index, bool enabled)
Definition monitor.cpp:146
void edgeSelectionChanged(int edge, int index)
Monitor(QWidget *parent)
Definition monitor.cpp:38
void setRatio(const qreal ratio)
void resizeEvent(QResizeEvent *event) override
void setMinimumContentWidth(qreal minw)
KSvg::ImageSet * svgImageSet() const
Definition monitor.h:27