1 #ifndef OBJECT_HPP
2 #define OBJECT_HPP
3 
4 #include <typeinfo>
5 #include <memory>
6 #include <string>
7 
8 #include <wayfire/nonstd/observer_ptr.h>
9 #include <wayfire/nonstd/noncopyable.hpp>
10 
11 namespace wf
12 {
13 /**
14  * signal_data_t is the base class for all signal data.
15  */
16 struct signal_data_t
17 {
~signal_data_twf::signal_data_t18     virtual ~signal_data_t()
19     {}
20 };
21 
22 using signal_callback_t = std::function<void (signal_data_t*)>;
23 class signal_provider_t;
24 
25 /**
26  * Provides an interface to connect to signal providers.
27  *
28  * The same signal connection object can be used to connect to multiple signal
29  * providers.
30  */
31 class signal_connection_t : public noncopyable_t
32 {
33   public:
34     /** Initialize an empty signal connection */
35     signal_connection_t();
36     /** Automatically disconnects from all providers */
37     ~signal_connection_t();
38 
39     /** Initialize a signal connection with the given callback */
40     template<class T> using convertible_to_callback_t =
41         std::enable_if_t<std::is_constructible_v<wf::signal_callback_t, T>, void>;
42     template<class T, class U = convertible_to_callback_t<T>>
signal_connection_t(T callback)43     signal_connection_t(T callback) : signal_connection_t()
44     {
45         set_callback(callback);
46     }
47 
48     /** Set the signal callback or override the existing signal callback. */
49     void set_callback(signal_callback_t callback);
50 
51     /** Call the stored callback with the given data. */
52     void emit(signal_data_t *data);
53 
54     /** Disconnect from all connected signal providers */
55     void disconnect();
56 
57     class impl;
58     std::unique_ptr<impl> priv;
59 
60   private:
61     /* Non-movable, non-copyable */
62     signal_connection_t(signal_connection_t&& other) = delete;
63     signal_connection_t& operator =(signal_connection_t&& other) = delete;
64 };
65 
66 class signal_provider_t
67 {
68   public:
69     /** Register a connection to be called when the given signal is emitted. */
70     void connect_signal(std::string name, signal_connection_t *callback);
71     /** Unregister a connection. */
72     void disconnect_signal(signal_connection_t *callback);
73 
74     /**
75      * Deprecated.
76      * Register a callback to be called whenever the given signal is emitted
77      */
78     void connect_signal(std::string name, signal_callback_t *callback);
79     /**
80      * Deprecated.
81      * Unregister a registered callback.
82      */
83     void disconnect_signal(std::string name, signal_callback_t *callback);
84 
85     /** Emit the given signal. No type checking for data is required */
86     void emit_signal(std::string name, signal_data_t *data);
87 
88     virtual ~signal_provider_t();
89 
90   protected:
91     signal_provider_t();
92 
93   private:
94     class sprovider_impl;
95     std::unique_ptr<sprovider_impl> sprovider_priv;
96 };
97 
98 /**
99  * Subclasses of custom_data_t can be stored inside an object_base_t
100  */
101 class custom_data_t
102 {
103   public:
~custom_data_t()104     virtual ~custom_data_t()
105     {}
106 };
107 
108 /**
109  * A base class for "objects". Objects provide signals and ways for plugins to
110  * store custom data about the object.
111  */
112 class object_base_t : public signal_provider_t
113 {
114   public:
115     /** Get a human-readable description of the object */
116     std::string to_string() const;
117 
118     /** Get the ID of the object. Each object has a unique ID */
119     uint32_t get_id() const;
120 
121     /**
122      * Retrieve custom data stored with the given name. If no such data exists,
123      * then it is created with the default constructor.
124      *
125      * REQUIRES a default constructor
126      * If your type doesn't have one, use store_data + get_data
127      */
128     template<class T>
get_data_safe(std::string name=typeid (T).name ())129     nonstd::observer_ptr<T> get_data_safe(
130         std::string name = typeid(T).name())
131     {
132         auto data = get_data<T>(name);
133         if (data)
134         {
135             return data;
136         } else
137         {
138             store_data<T>(std::make_unique<T>(), name);
139 
140             return get_data<T>(name);
141         }
142     }
143 
144     /* Retrieve custom data stored with the given name. If no such
145      * data exists, NULL is returned */
146     template<class T>
get_data(std::string name=typeid (T).name ())147     nonstd::observer_ptr<T> get_data(
148         std::string name = typeid(T).name())
149     {
150         return nonstd::make_observer(dynamic_cast<T*>(_fetch_data(name)));
151     }
152 
153     /* Assigns the given data to the given name */
154     template<class T>
store_data(std::unique_ptr<T> stored_data,std::string name=typeid (T).name ())155     void store_data(std::unique_ptr<T> stored_data,
156         std::string name = typeid(T).name())
157     {
158         _store_data(std::move(stored_data), name);
159     }
160 
161     /* Returns true if there is saved data under the given name */
162     template<class T>
has_data()163     bool has_data()
164     {
165         return has_data(typeid(T).name());
166     }
167 
168     /** @return true if there is saved data with the given name */
169     bool has_data(std::string name);
170 
171     /** Remove the saved data under the given name */
172     void erase_data(std::string name);
173 
174     /** Remove the saved data for the type T */
175     template<class T>
erase_data()176     void erase_data()
177     {
178         erase_data(typeid(T).name());
179     }
180 
181     /* Erase the saved data from the store and return the pointer */
182     template<class T>
release_data(std::string name=typeid (T).name ())183     std::unique_ptr<T> release_data(
184         std::string name = typeid(T).name())
185     {
186         if (!has_data(name))
187         {
188             return {nullptr};
189         }
190 
191         auto stored = _fetch_erase(name);
192 
193         return std::unique_ptr<T>(dynamic_cast<T*>(stored));
194     }
195 
196     virtual ~object_base_t();
197 
198   protected:
199     object_base_t();
200 
201     /** Clear all stored data. */
202     void _clear_data();
203 
204   private:
205     /** Just get the data under the given name, or nullptr, if it does not exist */
206     custom_data_t *_fetch_data(std::string name);
207     /** Get the data under the given name, and release the pointer, deleting
208      * the entry in the map */
209     custom_data_t *_fetch_erase(std::string name);
210 
211     /** Store the given data under the given name */
212     void _store_data(std::unique_ptr<custom_data_t> data, std::string name);
213 
214     class obase_impl;
215     std::unique_ptr<obase_impl> obase_priv;
216 };
217 }
218 
219 #endif /* end of include guard: OBJECT_HPP */
220