1 /********************************************************************
2 Copyright 2020 Adrien Faveraux <ad1rie3@hotmail.fr>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), which shall
10 act as a proxy defined in Section 6 of version 3 of the license.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 *********************************************************************/
20
21 #include "buffer.h"
22 #include "display.h"
23 #include "surface.h"
24 #include "surface_p.h"
25
26 #include "wayland/global.h"
27 #include "wayland/resource.h"
28
29 #include "shadow_p.h"
30
31 namespace Wrapland::Server
32 {
33
34 const struct org_kde_kwin_shadow_manager_interface ShadowManager::Private::s_interface = {
35 cb<createCallback>,
36 cb<unsetCallback>,
37 resourceDestroyCallback,
38 };
39
Private(Display * display,ShadowManager * qptr)40 ShadowManager::Private::Private(Display* display, ShadowManager* qptr)
41 : ShadowManagerGlobal(qptr, display, &org_kde_kwin_shadow_manager_interface, &s_interface)
42 {
43 create();
44 }
45
createCallback(ShadowManagerBind * bind,uint32_t id,wl_resource * wlSurface)46 void ShadowManager::Private::createCallback(ShadowManagerBind* bind,
47 uint32_t id,
48 wl_resource* wlSurface)
49 {
50 auto surface = Wayland::Resource<Surface>::handle(wlSurface);
51
52 auto shadow = new Shadow(bind->client()->handle(), bind->version(), id);
53 if (!shadow->d_ptr->resource()) {
54 bind->post_no_memory();
55 delete shadow;
56 return;
57 }
58 surface->d_ptr->setShadow(QPointer<Shadow>(shadow));
59 }
60
unsetCallback(ShadowManagerBind * bind,wl_resource * wlSurface)61 void ShadowManager::Private::unsetCallback([[maybe_unused]] ShadowManagerBind* bind,
62 wl_resource* wlSurface)
63 {
64 auto surface = Wayland::Resource<Surface>::handle(wlSurface);
65 surface->d_ptr->setShadow(QPointer<Shadow>());
66 }
67
ShadowManager(Display * display,QObject * parent)68 ShadowManager::ShadowManager(Display* display, QObject* parent)
69 : QObject(parent)
70 , d_ptr(new Private(display, this))
71 {
72 }
73
74 ShadowManager::~ShadowManager() = default;
75
76 const struct org_kde_kwin_shadow_interface Shadow::Private::s_interface = {
77 commitCallback,
78 attachCallback<AttachSide::Left>,
79 attachCallback<AttachSide::TopLeft>,
80 attachCallback<AttachSide::Top>,
81 attachCallback<AttachSide::TopRight>,
82 attachCallback<AttachSide::Right>,
83 attachCallback<AttachSide::BottomRight>,
84 attachCallback<AttachSide::Bottom>,
85 attachCallback<AttachSide::BottomLeft>,
86 offsetCallback<OffsetSide::Left>,
87 offsetCallback<OffsetSide::Top>,
88 offsetCallback<OffsetSide::Right>,
89 offsetCallback<OffsetSide::Bottom>,
90 destroyCallback,
91 };
92
commitCallback(wl_client * wlClient,wl_resource * wlResource)93 void Shadow::Private::commitCallback([[maybe_unused]] wl_client* wlClient, wl_resource* wlResource)
94 {
95 auto priv = handle(wlResource)->d_ptr;
96 priv->commit();
97 }
98
commit()99 void Shadow::Private::commit()
100 {
101 current.commit<AttachSide::Left>(pending);
102 current.commit<AttachSide::TopLeft>(pending);
103 current.commit<AttachSide::Top>(pending);
104 current.commit<AttachSide::TopRight>(pending);
105 current.commit<AttachSide::Right>(pending);
106 current.commit<AttachSide::BottomRight>(pending);
107 current.commit<AttachSide::Bottom>(pending);
108 current.commit<AttachSide::BottomLeft>(pending);
109
110 if (pending.offsetIsSet) {
111 current.offset = pending.offset;
112 }
113 pending = State();
114 }
115
attachConnect(AttachSide side,Buffer * buffer)116 void Shadow::Private::attachConnect(AttachSide side, Buffer* buffer)
117 {
118 if (!buffer) {
119 return;
120 }
121
122 QObject::connect(buffer, &Buffer::resourceDestroyed, handle(), [this, buffer, side]() {
123 if (auto& buf = pending.get(side); buf.get() == buffer) {
124 buf.reset();
125 }
126 if (auto& buf = current.get(side); buf.get() == buffer) {
127 buf.reset();
128 }
129 });
130 }
131
Private(Client * client,uint32_t version,uint32_t id,Shadow * q)132 Shadow::Private::Private(Client* client, uint32_t version, uint32_t id, Shadow* q)
133 : Wayland::Resource<Shadow>(client,
134 version,
135 id,
136 &org_kde_kwin_shadow_interface,
137 &s_interface,
138 q)
139 {
140 }
141
~Private()142 Shadow::Private::~Private()
143 {
144 current.unref<AttachSide::Left>();
145 current.unref<AttachSide::TopLeft>();
146 current.unref<AttachSide::Top>();
147 current.unref<AttachSide::TopRight>();
148 current.unref<AttachSide::Right>();
149 current.unref<AttachSide::BottomRight>();
150 current.unref<AttachSide::Bottom>();
151 current.unref<AttachSide::BottomLeft>();
152 }
153
Shadow(Client * client,uint32_t version,uint32_t id)154 Shadow::Shadow(Client* client, uint32_t version, uint32_t id)
155 : QObject(nullptr)
156 , d_ptr(new Shadow::Private(client, version, id, this))
157 {
158 }
159
offset() const160 QMarginsF Shadow::offset() const
161 {
162 return d_ptr->current.offset;
163 }
164
165 // TODO(romangg): replace this with template function once we can use headers-only classes.
166 #define BUFFER(__PART__, __UPPER_) \
167 std::shared_ptr<Buffer> Shadow::__PART__() const \
168 { \
169 return d_ptr->current.get<Private::AttachSide::__UPPER_>(); \
170 }
171
172 BUFFER(left, Left)
173 BUFFER(topLeft, TopLeft)
174 BUFFER(top, Top)
175 BUFFER(topRight, TopRight)
176 BUFFER(right, Right)
177 BUFFER(bottomRight, BottomRight)
178 BUFFER(bottom, Bottom)
179 BUFFER(bottomLeft, BottomLeft)
180
181 }
182