1 /******************************************************************** 2 Copyright © 2020 Roman Gilg <subdiff@gmail.com> 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 <QDebug> 23 24 #include "bind.h" 25 #include "display.h" 26 #include "nucleus.h" 27 #include "resource.h" 28 29 #include <cstdint> 30 #include <functional> 31 #include <memory> 32 #include <tuple> 33 #include <vector> 34 35 #include <wayland-server.h> 36 37 namespace Wrapland::Server 38 { 39 class Client; 40 class Display; 41 42 namespace Wayland 43 { 44 class Client; 45 46 template<typename Handle, int Version = 1> 47 class Global 48 { 49 public: 50 using type = Global<Handle, Version>; 51 static int constexpr version = Version; 52 53 Global(Global const&) = delete; 54 Global& operator=(Global const&) = delete; 55 Global(Global&&) noexcept = delete; 56 Global& operator=(Global&&) noexcept = delete; 57 ~Global()58 virtual ~Global() 59 { 60 m_nucleus->remove(); 61 } 62 create()63 void create() 64 { 65 m_nucleus->create(); 66 } 67 display()68 Display* display() 69 { 70 return m_nucleus->display(); 71 } 72 handle(wl_resource * wlResource)73 static Handle* handle(wl_resource* wlResource) 74 { 75 auto bind = static_cast<Bind<type>*>(wl_resource_get_user_data(wlResource)); 76 77 if (auto global = bind->global()) { 78 return global->handle(); 79 } 80 81 // If we are here the global has been removed while not yet destroyed. 82 return nullptr; 83 } 84 85 template<auto sender, uint32_t minVersion = 0, typename... Args> send(Bind<type> * bind,Args &&...args)86 void send(Bind<type>* bind, Args&&... args) 87 { 88 // See Vandevoorde et al.: C++ Templates - The Complete Guide p.79 89 // or https://stackoverflow.com/a/4942746. 90 bind->template send<sender, minVersion>(std::forward<Args>(args)...); 91 } 92 93 template<auto sender, uint32_t minVersion = 0, typename... Args> send(Client * client,Args &&...args)94 void send(Client* client, Args&&... args) 95 { 96 for (auto bind : m_nucleus->binds()) { 97 if (bind->client() == client) { 98 bind->template send<sender, minVersion>(std::forward<Args>(args)...); 99 } 100 } 101 } 102 103 template<auto sender, uint32_t minVersion = 0, typename... Args> send(Args &&...args)104 void send(Args&&... args) 105 { 106 for (auto bind : m_nucleus->binds()) { 107 bind->template send<sender, minVersion>(std::forward<Args>(args)...); 108 } 109 } 110 handle()111 Handle* handle() 112 { 113 return m_handle; 114 } 115 getBind(wl_resource * wlResource)116 Bind<type>* getBind(wl_resource* wlResource) 117 { 118 for (auto bind : m_nucleus->binds()) { 119 if (bind->resource() == wlResource) { 120 return bind; 121 } 122 } 123 return nullptr; 124 } 125 getBinds()126 std::vector<Bind<type>*> getBinds() 127 { 128 return m_nucleus->binds(); 129 } 130 getBinds(Server::Client * client)131 std::vector<Bind<type>*> getBinds(Server::Client* client) 132 { 133 std::vector<Bind<type>*> ret; 134 for (auto bind : m_nucleus->binds()) { 135 if (bind->client()->handle() == client) { 136 ret.push_back(bind); 137 } 138 } 139 return ret; 140 } 141 bindInit(Bind<type> * bind)142 virtual void bindInit([[maybe_unused]] Bind<type>* bind) 143 { 144 } 145 prepareUnbind(Bind<type> * bind)146 virtual void prepareUnbind([[maybe_unused]] Bind<type>* bind) 147 { 148 } 149 150 protected: Global(Handle * handle,Server::Display * display,const wl_interface * interface,void const * implementation)151 Global(Handle* handle, 152 Server::Display* display, 153 const wl_interface* interface, 154 void const* implementation) 155 : m_handle(handle) 156 , m_nucleus{new Nucleus<type>(this, display, interface, implementation)} 157 { 158 // TODO(romangg): allow to create and destroy Globals while keeping the object existing (but 159 // always create on ctor call?). 160 } 161 resourceDestroyCallback(wl_client * wlClient,wl_resource * wlResource)162 static void resourceDestroyCallback(wl_client* wlClient, wl_resource* wlResource) 163 { 164 Bind<type>::destroy_callback(wlClient, wlResource); 165 } 166 167 template<auto callback, typename... Args> cb(wl_client * client,wl_resource * resource,Args...args)168 static void cb([[maybe_unused]] wl_client* client, wl_resource* resource, Args... args) 169 { 170 // The global might be destroyed already on the compositor side. 171 if (handle(resource)) { 172 auto bind = static_cast<Bind<type>*>(wl_resource_get_user_data(resource)); 173 callback(bind, std::forward<Args>(args)...); 174 } 175 } 176 177 private: 178 Handle* m_handle; 179 Nucleus<type>* m_nucleus; 180 }; 181 182 } 183 } 184