1 /*
2 SPDX-FileCopyrightText: 2021 Michail Vourlakos <mvourlakos@gmail.com>
3 SPDX-License-Identifier: GPL-2.0-or-later
4 */
5
6 #include "widgetexplorerview.h"
7
8 // local
9 #include "../panelshadows_p.h"
10 #include "../view.h"
11 #include "../../lattecorona.h"
12 #include "../../wm/abstractwindowinterface.h"
13
14 // Qt
15 #include <QQuickItem>
16 #include <QScreen>
17
18 // KDE
19 #include <KWindowEffects>
20 #include <KWindowSystem>
21 #include <KWayland/Client/plasmashell.h>
22
23 // Plasma
24 #include <Plasma/Package>
25
26 namespace Latte {
27 namespace ViewPart {
28
WidgetExplorerView(Latte::View * view)29 WidgetExplorerView::WidgetExplorerView(Latte::View *view)
30 : SubConfigView(view, QString("#widgetexplorerview#"), true)
31 {
32 setResizeMode(QQuickView::SizeRootObjectToView);
33 //!set flags early in order for wayland to initialize properly
34 setFlags(wFlags());
35
36 connect(this, &QQuickView::widthChanged, this, &WidgetExplorerView::updateEffects);
37 connect(this, &QQuickView::heightChanged, this, &WidgetExplorerView::updateEffects);
38
39 connect(this, &QQuickView::statusChanged, [&](QQuickView::Status status) {
40 if (status == QQuickView::Ready) {
41 updateEffects();
42 }
43 });
44
45 setParentView(view);
46 init();
47 }
48
init()49 void WidgetExplorerView::init()
50 {
51 SubConfigView::init();
52
53 QByteArray tempFilePath = "widgetexplorerui";
54
55 updateEnabledBorders();
56
57 auto source = QUrl::fromLocalFile(m_latteView->containment()->corona()->kPackage().filePath(tempFilePath));
58 setSource(source);
59 syncGeometry();
60 }
61
hideOnWindowDeactivate() const62 bool WidgetExplorerView::hideOnWindowDeactivate() const
63 {
64 return m_hideOnWindowDeactivate;
65 }
66
setHideOnWindowDeactivate(bool hide)67 void WidgetExplorerView::setHideOnWindowDeactivate(bool hide)
68 {
69 if (m_hideOnWindowDeactivate == hide) {
70 return;
71 }
72
73 m_hideOnWindowDeactivate = hide;
74 emit hideOnWindowDeactivateChanged();
75 }
76
wFlags() const77 Qt::WindowFlags WidgetExplorerView::wFlags() const
78 {
79 return (flags() | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
80 }
81
geometryWhenVisible() const82 QRect WidgetExplorerView::geometryWhenVisible() const
83 {
84 return m_geometryWhenVisible;
85 }
86
initParentView(Latte::View * view)87 void WidgetExplorerView::initParentView(Latte::View *view)
88 {
89 SubConfigView::initParentView(view);
90
91 rootContext()->setContextProperty(QStringLiteral("containmentFromView"), m_latteView->containment());
92
93 updateEnabledBorders();
94 syncGeometry();
95 }
96
availableScreenGeometry() const97 QRect WidgetExplorerView::availableScreenGeometry() const
98 {
99 int currentScrId = m_latteView->positioner()->currentScreenId();
100
101 QList<Latte::Types::Visibility> ignoreModes{Latte::Types::SidebarOnDemand,Latte::Types::SidebarAutoHide};
102
103 if (m_latteView->visibility() && m_latteView->visibility()->isSidebar()) {
104 ignoreModes.removeAll(Latte::Types::SidebarOnDemand);
105 ignoreModes.removeAll(Latte::Types::SidebarAutoHide);
106 }
107
108 QString activityid = m_latteView->layout()->lastUsedActivity();
109
110 return m_corona->availableScreenRectWithCriteria(currentScrId, activityid, ignoreModes, {}, false, true);
111 }
112
syncGeometry()113 void WidgetExplorerView::syncGeometry()
114 {
115 if (!m_latteView || !m_latteView->layout() || !m_latteView->containment() || !rootObject()) {
116 return;
117 }
118 const QSize size(rootObject()->width(), rootObject()->height());
119 auto availGeometry = availableScreenGeometry();
120
121 int margin = availGeometry.height() == m_latteView->screenGeometry().height() ? 100 : 0;
122 auto geometry = QRect(availGeometry.x(), availGeometry.y(), size.width(), availGeometry.height()-margin);
123
124 updateEnabledBorders();
125
126 if (m_geometryWhenVisible == geometry) {
127 return;
128 }
129
130 m_geometryWhenVisible = geometry;
131
132 setPosition(geometry.topLeft());
133
134 if (m_shellSurface) {
135 m_shellSurface->setPosition(geometry.topLeft());
136 }
137
138 setMaximumSize(geometry.size());
139 setMinimumSize(geometry.size());
140 resize(geometry.size());
141 }
142
showEvent(QShowEvent * ev)143 void WidgetExplorerView::showEvent(QShowEvent *ev)
144 {
145 if (m_shellSurface) {
146 //! under wayland it needs to be set again after its hiding
147 m_shellSurface->setPosition(m_geometryWhenVisible.topLeft());
148 }
149
150 SubConfigView::showEvent(ev);
151
152 if (!m_latteView) {
153 return;
154 }
155
156 syncGeometry();
157
158 requestActivate();
159
160 m_screenSyncTimer.start();
161 QTimer::singleShot(400, this, &WidgetExplorerView::syncGeometry);
162
163 emit showSignal();
164 }
165
focusOutEvent(QFocusEvent * ev)166 void WidgetExplorerView::focusOutEvent(QFocusEvent *ev)
167 {
168 Q_UNUSED(ev);
169
170 if (!m_latteView) {
171 return;
172 }
173
174 hideConfigWindow();
175 }
176
updateEffects()177 void WidgetExplorerView::updateEffects()
178 {
179 //! Don't apply any effect before the wayland surface is created under wayland
180 //! https://bugs.kde.org/show_bug.cgi?id=392890
181 if (KWindowSystem::isPlatformWayland() && !m_shellSurface) {
182 return;
183 }
184
185 if (!m_background) {
186 m_background = new Plasma::FrameSvg(this);
187 }
188
189 if (m_background->imagePath() != "dialogs/background") {
190 m_background->setImagePath(QStringLiteral("dialogs/background"));
191 }
192
193 m_background->setEnabledBorders(m_enabledBorders);
194 m_background->resizeFrame(size());
195
196 QRegion mask = m_background->mask();
197
198 QRegion fixedMask = mask.isNull() ? QRegion(QRect(0,0,width(),height())) : mask;
199
200 if (!fixedMask.isEmpty()) {
201 setMask(fixedMask);
202 } else {
203 setMask(QRegion());
204 }
205
206 if (KWindowSystem::compositingActive()) {
207 KWindowEffects::enableBlurBehind(winId(), true, fixedMask);
208 } else {
209 KWindowEffects::enableBlurBehind(winId(), false);
210 }
211 }
212
hideConfigWindow()213 void WidgetExplorerView::hideConfigWindow()
214 {
215 if (!m_hideOnWindowDeactivate) {
216 return;
217 }
218
219 deleteLater();
220
221 /*QTimer::singleShot(100, [this]() {
222 //! avoid crashes under wayland because some mouse events are sended after the surface is destroyed
223
224 if (m_shellSurface) {
225 //!NOTE: Avoid crash in wayland environment with qt5.9
226 close();
227 } else {
228 hide();
229 }
230 });*/
231 }
232
syncSlideEffect()233 void WidgetExplorerView::syncSlideEffect()
234 {
235 if (!m_latteView || !m_latteView->containment()) {
236 return;
237 }
238
239 auto slideLocation = WindowSystem::AbstractWindowInterface::Slide::Left;
240
241 m_corona->wm()->slideWindow(*this, slideLocation);
242 }
243
244 //!BEGIN borders
updateEnabledBorders()245 void WidgetExplorerView::updateEnabledBorders()
246 {
247 if (!this->screen()) {
248 return;
249 }
250
251 Plasma::FrameSvg::EnabledBorders borders = Plasma::FrameSvg::AllBorders;
252
253 if (!m_geometryWhenVisible.isEmpty()) {
254 if (m_geometryWhenVisible.x() == m_latteView->screenGeometry().x()) {
255 borders &= ~Plasma::FrameSvg::LeftBorder;
256 }
257
258 if (m_geometryWhenVisible.y() == m_latteView->screenGeometry().y()) {
259 borders &= ~Plasma::FrameSvg::TopBorder;
260 }
261
262 if (m_geometryWhenVisible.height() == m_latteView->screenGeometry().height()) {
263 borders &= ~Plasma::FrameSvg::BottomBorder;
264 }
265 }
266
267 if (m_enabledBorders != borders) {
268 if (isVisible()) {
269 m_enabledBorders = borders;
270 }
271 m_corona->dialogShadows()->addWindow(this, m_enabledBorders);
272
273 emit enabledBordersChanged();
274 }
275 }
276
277 //!END borders
278
279 }
280 }
281
282