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