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