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