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 #pragma once 21 22 #include "shadow.h" 23 24 #include <QMarginsF> 25 #include <QObject> 26 27 #include <cassert> 28 #include <type_traits> 29 #include <wayland-shadow-server-protocol.h> 30 31 #include <wayland-server.h> 32 33 namespace Wrapland::Server 34 { 35 36 class Buffer; 37 class Display; 38 39 constexpr uint32_t ShadowManagerVersion = 2; 40 using ShadowManagerGlobal = Wayland::Global<ShadowManager, ShadowManagerVersion>; 41 using ShadowManagerBind = Wayland::Bind<ShadowManagerGlobal>; 42 43 class ShadowManager::Private : public ShadowManagerGlobal 44 { 45 public: 46 Private(Display* display, ShadowManager* qptr); 47 48 private: 49 static void createCallback(ShadowManagerBind* bind, uint32_t id, wl_resource* surface); 50 static void unsetCallback(ShadowManagerBind* bind, wl_resource* surface); 51 52 static const struct org_kde_kwin_shadow_manager_interface s_interface; 53 }; 54 55 class Shadow::Private : public Wayland::Resource<Shadow> 56 { 57 public: 58 Private(Client* client, uint32_t version, uint32_t id, Shadow* q); 59 ~Private() override; 60 61 enum class AttachSide { 62 Left, 63 TopLeft, 64 Top, 65 TopRight, 66 Right, 67 BottomRight, 68 Bottom, 69 BottomLeft, 70 }; 71 72 enum class OffsetSide { 73 Left, 74 Top, 75 Right, 76 Bottom, 77 }; 78 79 struct State { 80 template<AttachSide side> getState81 std::shared_ptr<Buffer>& get() 82 { 83 if constexpr (side == AttachSide::Left) { 84 return left; 85 } else if constexpr (side == AttachSide::TopLeft) { 86 return topLeft; 87 } else if constexpr (side == AttachSide::Top) { 88 return top; 89 } else if constexpr (side == AttachSide::TopRight) { 90 return topRight; 91 } else if constexpr (side == AttachSide::Right) { 92 return right; 93 } else if constexpr (side == AttachSide::BottomRight) { 94 return bottomRight; 95 } else if constexpr (side == AttachSide::Bottom) { 96 return bottom; 97 } else { 98 static_assert(side == AttachSide::BottomLeft); 99 return bottomLeft; 100 } 101 } 102 103 // We need this for our QObject connections. Once we use a signal system with good template 104 // support it can be replaced by above templated getter. getState105 std::shared_ptr<Buffer>& get(AttachSide side) 106 { 107 if (side == AttachSide::Left) { 108 return left; 109 } 110 if (side == AttachSide::TopLeft) { 111 return topLeft; 112 } 113 if (side == AttachSide::Top) { 114 return top; 115 } 116 if (side == AttachSide::TopRight) { 117 return topRight; 118 } 119 if (side == AttachSide::Right) { 120 return right; 121 } 122 if (side == AttachSide::BottomRight) { 123 return bottomRight; 124 } 125 if (side == AttachSide::Bottom) { 126 return bottom; 127 } 128 assert(side == AttachSide::BottomLeft); 129 return bottomLeft; 130 } 131 132 template<OffsetSide side> setOffsetState133 void setOffset(double _offset) 134 { 135 if constexpr (side == OffsetSide::Left) { 136 offset.setLeft(_offset); 137 } else if constexpr (side == OffsetSide::Top) { 138 offset.setTop(_offset); 139 } else if constexpr (side == OffsetSide::Right) { 140 offset.setRight(_offset); 141 } else { 142 static_assert(side == OffsetSide::Bottom); 143 offset.setBottom(_offset); 144 } 145 offsetIsSet = true; 146 } 147 148 template<AttachSide side> commitState149 void commit(State& pending) 150 { 151 auto& currentBuf = get<side>(); 152 auto& pendingBuf = pending.get<side>(); 153 154 currentBuf = pendingBuf; 155 pendingBuf.reset(); 156 } 157 158 template<AttachSide side> unrefState159 void unref() 160 { 161 if (auto buf = get<side>()) { 162 buf.reset(); 163 } 164 } 165 166 // TODO(romangg): unique_ptr? 167 std::shared_ptr<Buffer> left = nullptr; 168 std::shared_ptr<Buffer> topLeft = nullptr; 169 std::shared_ptr<Buffer> top = nullptr; 170 std::shared_ptr<Buffer> topRight = nullptr; 171 std::shared_ptr<Buffer> right = nullptr; 172 std::shared_ptr<Buffer> bottomRight = nullptr; 173 std::shared_ptr<Buffer> bottom = nullptr; 174 std::shared_ptr<Buffer> bottomLeft = nullptr; 175 176 QMarginsF offset; 177 bool offsetIsSet = false; 178 }; 179 State current; 180 State pending; 181 182 private: 183 template<AttachSide side> attachCallback(wl_client * wlClient,wl_resource * wlResource,wl_resource * wlBuffer)184 static void attachCallback([[maybe_unused]] wl_client* wlClient, 185 wl_resource* wlResource, 186 wl_resource* wlBuffer) 187 { 188 auto priv = handle(wlResource)->d_ptr; 189 priv->attach<side>(wlBuffer); 190 } 191 192 template<OffsetSide side> offsetCallback(wl_client * wlClient,wl_resource * wlResource,wl_fixed_t wlOffset)193 static void offsetCallback([[maybe_unused]] wl_client* wlClient, 194 wl_resource* wlResource, 195 wl_fixed_t wlOffset) 196 { 197 auto priv = handle(wlResource)->d_ptr; 198 priv->pending.setOffset<side>(wl_fixed_to_double(wlOffset)); 199 } 200 201 static void commitCallback(wl_client* client, wl_resource* resource); 202 203 template<AttachSide side> attach(wl_resource * wlBuffer)204 void attach(wl_resource* wlBuffer) 205 { 206 auto display = client()->display()->handle(); 207 auto buffer = Buffer::get(display, wlBuffer); 208 209 attachConnect(side, buffer.get()); 210 pending.get<side>() = buffer; 211 } 212 213 void attachConnect(AttachSide side, Buffer* buffer); 214 void commit(); 215 216 static const struct org_kde_kwin_shadow_interface s_interface; 217 }; 218 219 } 220