1 /*
2 SPDX-FileCopyrightText: 2020 Michail Vourlakos <mvourlakos@gmail.com>
3 SPDX-License-Identifier: GPL-2.0-or-later
4 */
5
6 #include "subconfigview.h"
7
8 //local
9 #include <config-latte.h>
10 #include "../view.h"
11 #include "../../lattecorona.h"
12 #include "../../layouts/manager.h"
13 #include "../../plasma/extended/theme.h"
14 #include "../../settings/universalsettings.h"
15 #include "../../shortcuts/globalshortcuts.h"
16 #include "../../shortcuts/shortcutstracker.h"
17 #include "../../wm/abstractwindowinterface.h"
18
19 // KDE
20 #include <KLocalizedContext>
21 #include <KDeclarative/KDeclarative>
22 #include <KWayland/Client/plasmashell.h>
23 #include <KWayland/Client/surface.h>
24 #include <KWindowSystem>
25
26 namespace Latte {
27 namespace ViewPart {
28
SubConfigView(Latte::View * view,const QString & title,const bool & isNormalWindow)29 SubConfigView::SubConfigView(Latte::View *view, const QString &title, const bool &isNormalWindow)
30 : QQuickView(nullptr),
31 m_isNormalWindow(isNormalWindow)
32 {
33 m_corona = qobject_cast<Latte::Corona *>(view->containment()->corona());
34
35 setupWaylandIntegration();
36
37 if (KWindowSystem::isPlatformX11()) {
38 m_corona->wm()->registerIgnoredWindow(winId());
39 } else {
40 connect(this, &QWindow::windowTitleChanged, this, &SubConfigView::updateWaylandId);
41 connect(m_corona->wm(), &WindowSystem::AbstractWindowInterface::latteWindowAdded, this, &SubConfigView::updateWaylandId);
42 }
43
44 m_validTitle = title;
45 setTitle(m_validTitle);
46
47 setScreen(view->screen());
48 setIcon(qGuiApp->windowIcon());
49
50 if (!m_isNormalWindow) {
51 setFlags(wFlags());
52 m_corona->wm()->setViewExtraFlags(this, true);
53 }
54
55 m_screenSyncTimer.setSingleShot(true);
56 m_screenSyncTimer.setInterval(100);
57
58 connections << connect(&m_screenSyncTimer, &QTimer::timeout, this, [this]() {
59 if (!m_latteView) {
60 return;
61 }
62
63 setScreen(m_latteView->screen());
64
65 if (KWindowSystem::isPlatformX11()) {
66 if (m_isNormalWindow) {
67 setFlags(wFlags());
68 m_corona->wm()->setViewExtraFlags(this, false, Latte::Types::NormalWindow);
69 }
70 }
71
72 syncGeometry();
73 });
74
75 m_showTimer.setSingleShot(true);
76 m_showTimer.setInterval(0);
77
78 connections << connect(&m_showTimer, &QTimer::timeout, this, [this]() {
79 syncSlideEffect();
80 show();
81 });
82 }
83
~SubConfigView()84 SubConfigView::~SubConfigView()
85 {
86 qDebug() << validTitle() << " deleting...";
87
88 m_corona->dialogShadows()->removeWindow(this);
89
90 m_corona->wm()->unregisterIgnoredWindow(KWindowSystem::isPlatformX11() ? winId() : m_waylandWindowId);
91
92 for (const auto &var : connections) {
93 QObject::disconnect(var);
94 }
95
96 for (const auto &var : viewconnections) {
97 QObject::disconnect(var);
98 }
99 }
100
init()101 void SubConfigView::init()
102 {
103 qDebug() << validTitle() << " : initialization started...";
104
105 setDefaultAlphaBuffer(true);
106 setColor(Qt::transparent);
107
108 rootContext()->setContextProperty(QStringLiteral("viewConfig"), this);
109 rootContext()->setContextProperty(QStringLiteral("shortcutsEngine"), m_corona->globalShortcuts()->shortcutsTracker());
110
111 if (m_corona) {
112 rootContext()->setContextProperty(QStringLiteral("universalSettings"), m_corona->universalSettings());
113 rootContext()->setContextProperty(QStringLiteral("layoutsManager"), m_corona->layoutsManager());
114 rootContext()->setContextProperty(QStringLiteral("themeExtended"), m_corona->themeExtended());
115 }
116
117 KDeclarative::KDeclarative kdeclarative;
118 kdeclarative.setDeclarativeEngine(engine());
119 kdeclarative.setTranslationDomain(QStringLiteral("latte-dock"));
120 #if KF5_VERSION_MINOR >= 45
121 kdeclarative.setupContext();
122 kdeclarative.setupEngine(engine());
123 #else
124 kdeclarative.setupBindings();
125 #endif
126 }
127
wFlags() const128 Qt::WindowFlags SubConfigView::wFlags() const
129 {
130 return (flags() | Qt::FramelessWindowHint) & ~Qt::WindowDoesNotAcceptFocus;
131 }
132
validTitle() const133 QString SubConfigView::validTitle() const
134 {
135 return m_validTitle;
136 }
137
trackedWindowId()138 Latte::WindowSystem::WindowId SubConfigView::trackedWindowId()
139 {
140 if (KWindowSystem::isPlatformWayland() && m_waylandWindowId.toInt() <= 0) {
141 updateWaylandId();
142 }
143
144 return !KWindowSystem::isPlatformWayland() ? winId() : m_waylandWindowId;
145 }
146
corona() const147 Latte::Corona *SubConfigView::corona() const
148 {
149 return m_corona;
150 }
151
parentView() const152 Latte::View *SubConfigView::parentView() const
153 {
154 return m_latteView;
155 }
156
setParentView(Latte::View * view,const bool & immediate)157 void SubConfigView::setParentView(Latte::View *view, const bool &immediate)
158 {
159 if (m_latteView == view) {
160 return;
161 }
162
163 initParentView(view);
164 }
165
initParentView(Latte::View * view)166 void SubConfigView::initParentView(Latte::View *view)
167 {
168 for (const auto &var : viewconnections) {
169 QObject::disconnect(var);
170 }
171
172 m_latteView = view;
173
174 viewconnections << connect(m_latteView->positioner(), &ViewPart::Positioner::canvasGeometryChanged, this, &SubConfigView::syncGeometry);
175
176 //! Assign app interfaces in be accessible through containment graphic item
177 QQuickItem *containmentGraphicItem = qobject_cast<QQuickItem *>(m_latteView->containment()->property("_plasma_graphicObject").value<QObject *>());
178 rootContext()->setContextProperty(QStringLiteral("plasmoid"), containmentGraphicItem);
179 rootContext()->setContextProperty(QStringLiteral("latteView"), m_latteView);
180 }
181
requestActivate()182 void SubConfigView::requestActivate()
183 {
184 if (KWindowSystem::isPlatformWayland() && m_shellSurface) {
185 updateWaylandId();
186 m_corona->wm()->requestActivate(m_waylandWindowId);
187 } else {
188 QQuickView::requestActivate();
189 }
190 }
191
showAfter(int msecs)192 void SubConfigView::showAfter(int msecs)
193 {
194 if (isVisible()) {
195 return;
196 }
197
198 m_showTimer.setInterval(msecs);
199 m_showTimer.start();
200
201 }
202
syncSlideEffect()203 void SubConfigView::syncSlideEffect()
204 {
205 if (!m_latteView || !m_latteView->containment()) {
206 return;
207 }
208
209 auto slideLocation = WindowSystem::AbstractWindowInterface::Slide::None;
210
211 switch (m_latteView->containment()->location()) {
212 case Plasma::Types::TopEdge:
213 slideLocation = WindowSystem::AbstractWindowInterface::Slide::Top;
214 break;
215
216 case Plasma::Types::RightEdge:
217 slideLocation = WindowSystem::AbstractWindowInterface::Slide::Right;
218 break;
219
220 case Plasma::Types::BottomEdge:
221 slideLocation = WindowSystem::AbstractWindowInterface::Slide::Bottom;
222 break;
223
224 case Plasma::Types::LeftEdge:
225 slideLocation = WindowSystem::AbstractWindowInterface::Slide::Left;
226 break;
227
228 default:
229 qDebug() << staticMetaObject.className() << "wrong location";
230 break;
231 }
232
233 m_corona->wm()->slideWindow(*this, slideLocation);
234 }
235
surface()236 KWayland::Client::PlasmaShellSurface *SubConfigView::surface()
237 {
238 return m_shellSurface;
239 }
240
setupWaylandIntegration()241 void SubConfigView::setupWaylandIntegration()
242 {
243 if (m_shellSurface || !KWindowSystem::isPlatformWayland() || !m_latteView || !m_latteView->containment()) {
244 // already setup
245 return;
246 }
247
248 if (m_corona) {
249 using namespace KWayland::Client;
250 PlasmaShell *interface = m_corona->waylandCoronaInterface();
251
252 if (!interface) {
253 return;
254 }
255
256 Surface *s = Surface::fromWindow(this);
257
258 if (!s) {
259 return;
260 }
261
262 qDebug() << "wayland " << title() << " surface was created...";
263
264 m_shellSurface = interface->createSurface(s, this);
265
266 if (m_isNormalWindow) {
267 m_corona->wm()->setViewExtraFlags(m_shellSurface, false);
268 } else {
269 m_corona->wm()->setViewExtraFlags(m_shellSurface, true);
270 }
271
272 updateWaylandId();
273 syncGeometry();
274 }
275 }
276
showEvent(QShowEvent * ev)277 void SubConfigView::showEvent(QShowEvent *ev)
278 {
279 QQuickView::showEvent(ev);
280
281 if (m_shellSurface) {
282 //! readd shadows after hiding because the window shadows are not shown again after first showing
283 m_corona->dialogShadows()->addWindow(this, m_enabledBorders);
284 }
285 }
286
event(QEvent * e)287 bool SubConfigView::event(QEvent *e)
288 {
289 if (e->type() == QEvent::PlatformSurface) {
290 if (auto pe = dynamic_cast<QPlatformSurfaceEvent *>(e)) {
291 switch (pe->surfaceEventType()) {
292 case QPlatformSurfaceEvent::SurfaceCreated:
293
294 if (m_shellSurface) {
295 break;
296 }
297
298 setupWaylandIntegration();
299 break;
300
301 case QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed:
302 if (m_shellSurface) {
303 delete m_shellSurface;
304 m_shellSurface = nullptr;
305 qDebug() << "WAYLAND " << title() << " window surface was deleted...";
306 }
307
308 break;
309 }
310 }
311 }
312
313 return QQuickView::event(e);
314 }
315
updateWaylandId()316 void SubConfigView::updateWaylandId()
317 {
318 Latte::WindowSystem::WindowId newId = m_corona->wm()->winIdFor("latte-dock", validTitle());
319
320 if (m_waylandWindowId != newId) {
321 if (!m_waylandWindowId.isNull()) {
322 m_corona->wm()->unregisterIgnoredWindow(m_waylandWindowId);
323 }
324
325 m_waylandWindowId = newId;
326 m_corona->wm()->registerIgnoredWindow(m_waylandWindowId);
327 }
328 }
329
enabledBorders() const330 Plasma::FrameSvg::EnabledBorders SubConfigView::enabledBorders() const
331 {
332 return m_enabledBorders;
333 }
334
335 }
336 }
337