1 #ifndef _GLIBMM_SIGNALPROXY_H 2 #define _GLIBMM_SIGNALPROXY_H 3 4 /* signalproxy.h 5 * 6 * Copyright (C) 2015 The gtkmm Development Team 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 20 */ 21 22 extern "C" { 23 typedef void (*GCallback)(void); 24 typedef struct _GObject GObject; 25 } 26 27 #include <sigc++/sigc++.h> 28 #include <glibmm/signalproxy_connectionnode.h> 29 #include <glibmm/ustring.h> 30 #include <utility> // std::move() 31 32 namespace Glib 33 { 34 35 // Forward declarations 36 class GLIBMM_API ObjectBase; 37 38 #ifndef DOXYGEN_SHOULD_SKIP_THIS 39 40 struct SignalProxyInfo 41 { 42 const char* signal_name; 43 GCallback callback; 44 GCallback notify_callback; 45 }; 46 47 #endif // DOXYGEN_SHOULD_SKIP_THIS 48 49 // This base class is used by SignalProxyNormal, SignalProxyDetailed and SignalProxyProperty. 50 class GLIBMM_API SignalProxyBase 51 { 52 public: 53 SignalProxyBase(Glib::ObjectBase* obj); 54 55 #ifndef DOXYGEN_SHOULD_SKIP_THIS data_to_slot(void * data)56 static inline sigc::slot_base* data_to_slot(void* data) 57 { 58 const auto pConnectionNode = static_cast<SignalProxyConnectionNode*>(data); 59 60 // Return null pointer if the connection is blocked. 61 return (!pConnectionNode->slot_.blocked()) ? &pConnectionNode->slot_ : nullptr; 62 } 63 #endif /* DOXYGEN_SHOULD_SKIP_THIS */ 64 65 protected: 66 ObjectBase* obj_; 67 68 private: 69 SignalProxyBase& operator=(const SignalProxyBase&); // not implemented 70 }; 71 72 // Shared portion of a Signal without detail 73 /** The SignalProxy provides an API similar to sigc::signal that can be used to 74 * connect sigc::slots to glib signals. 75 * 76 * This holds the name of the glib signal and the object 77 * which might emit it. Actually, proxies are controlled by 78 * the template derivatives, which serve as gatekeepers for the 79 * types allowed on a particular signal. 80 * 81 * For signals with a detailed name (signal_name::detail_name) see SignalProxyDetailed. 82 */ 83 class GLIBMM_API SignalProxyNormal : public SignalProxyBase 84 { 85 public: 86 ~SignalProxyNormal() noexcept; 87 88 /// Stops the current signal emission (not in libsigc++) 89 void emission_stop(); 90 91 #ifndef DOXYGEN_SHOULD_SKIP_THIS 92 // This callback for SignalProxy<void> 93 // is defined here to avoid code duplication. 94 static void slot0_void_callback(GObject*, void* data); 95 #endif 96 97 protected: 98 /** Creates a proxy for a signal that can be emitted by @a obj. 99 * @param obj The object that can emit the signal. 100 * @param info Information about the signal, including its name, and the C callbacks that should 101 * be called by glib. 102 */ 103 SignalProxyNormal(Glib::ObjectBase* obj, const SignalProxyInfo* info); 104 105 /** Connects a generic signal handler to a signal. 106 * This is called by connect() in derived SignalProxy classes. 107 * 108 * @param slot The signal handler, usually created with sigc::mem_fun() or sigc::ptr_fun(). 109 * @param after Whether this signal handler should be called before or after the default signal 110 * handler. 111 */ 112 sigc::slot_base& connect_(const sigc::slot_base& slot, bool after); 113 114 /** Connects a signal handler without a return value to a signal. 115 * This is called by connect_notify() in derived SignalProxy classes. 116 * 117 * @param slot The signal handler, which should have a @c void return type, 118 * usually created with sigc::mem_fun() or sigc::ptr_fun(). 119 * @param after Whether this signal handler should be called before or after the default signal 120 * handler. 121 */ 122 sigc::slot_base& connect_notify_(const sigc::slot_base& slot, bool after); 123 124 /** Connects a signal handler to a signal. 125 * @see connect_(const sigc::slot_base& slot, bool after) and 126 * connect_notify_(const sigc::slot_base& slot, bool after). 127 * 128 * @newin{2,48} 129 */ 130 sigc::slot_base& connect_impl_(bool notify, sigc::slot_base&& slot, bool after); 131 132 private: 133 const SignalProxyInfo* info_; 134 135 // TODO: We could maybe replace both connect_() and connect_notify_() with this in future, because 136 // they don't do anything extra. 137 /** This is called by connect_() and connect_notify_(). 138 */ 139 sigc::slot_base& connect_impl_(GCallback callback, const sigc::slot_base& slot, bool after); 140 141 // no copy assignment 142 SignalProxyNormal& operator=(const SignalProxyNormal&); 143 }; 144 145 /**** Glib::SignalProxy ***************************************************/ 146 147 /** Proxy for signals with any number of arguments. 148 * Use the connect() or connect_notify() method, with sigc::mem_fun() or sigc::ptr_fun() 149 * to connect signal handlers to signals. 150 */ 151 template <class R, class... T> 152 class SignalProxy : public SignalProxyNormal 153 { 154 public: 155 using SlotType = sigc::slot<R, T...>; 156 using VoidSlotType = sigc::slot<void, T...>; 157 SignalProxy(ObjectBase * obj,const SignalProxyInfo * info)158 SignalProxy(ObjectBase* obj, const SignalProxyInfo* info) : SignalProxyNormal(obj, info) {} 159 160 /** Connects a signal handler to a signal. 161 * 162 * For instance, connect( sigc::mem_fun(*this, &TheClass::on_something) ); 163 * 164 * @param slot The signal handler, usually created with sigc::mem_fun() or sigc::ptr_fun(). 165 * @param after Whether this signal handler should be called before or after the default signal 166 * handler. 167 */ 168 sigc::connection connect(const SlotType& slot, bool after = true) 169 { 170 return sigc::connection(connect_(slot, after)); 171 } 172 173 /** Connects a signal handler to a signal. 174 * @see connect(const SlotType& slot, bool after). 175 * 176 * @newin{2,48} 177 */ 178 sigc::connection connect(SlotType&& slot, bool after = true) 179 { 180 return sigc::connection(connect_impl_(false, std::move(slot), after)); 181 } 182 183 /** Connects a signal handler without a return value to a signal. 184 * By default, the signal handler will be called before the default signal handler. 185 * 186 * For instance, connect_notify( sigc::mem_fun(*this, &TheClass::on_something) ); 187 * 188 * If the signal requires signal handlers with a @c void return type, 189 * the only difference between connect() and connect_notify() is the default 190 * value of @a after. 191 * 192 * If the signal requires signal handlers with a return value of type T, 193 * connect_notify() binds <tt>return T()</tt> to the connected signal handler. 194 * For instance, if the return type is @c bool, the following two calls are equivalent. 195 * @code 196 * connect_notify( sigc::mem_fun(*this, &TheClass::on_something) ); 197 * connect( sigc::bind_return<bool>(sigc::mem_fun(*this, &TheClass::on_something), false), false 198 * ); 199 * @endcode 200 * 201 * @param slot The signal handler, which should have a @c void return type, 202 * usually created with sigc::mem_fun() or sigc::ptr_fun(). 203 * @param after Whether this signal handler should be called before or after the default signal 204 * handler. 205 */ 206 sigc::connection connect_notify(const VoidSlotType& slot, bool after = false) 207 { 208 return sigc::connection(connect_notify_(slot, after)); 209 } 210 211 /** Connects a signal handler without a return value to a signal. 212 * @see connect_notify(const VoidSlotType& slot, bool after). 213 * 214 * @newin{2,48} 215 */ 216 sigc::connection connect_notify(VoidSlotType&& slot, bool after = false) 217 { 218 return sigc::connection(connect_impl_(true, std::move(slot), after)); 219 } 220 }; 221 222 /* Templates below has been added to avoid API break, and should not be 223 * used in a newly created code. SignalProxy class should be used instead 224 * of SignalProxy# class. 225 */ 226 template <typename R> 227 using SignalProxy0 = SignalProxy<R>; 228 template <typename R, typename T1> 229 using SignalProxy1 = SignalProxy<R, T1>; 230 template <typename R, typename T1, typename T2> 231 using SignalProxy2 = SignalProxy<R, T1, T2>; 232 template <typename R, typename T1, typename T2, typename T3> 233 using SignalProxy3 = SignalProxy<R, T1, T2, T3>; 234 template <typename R, typename T1, typename T2, typename T3, typename T4> 235 using SignalProxy4 = SignalProxy<R, T1, T2, T3, T4>; 236 template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5> 237 using SignalProxy5 = SignalProxy<R, T1, T2, T3, T4, T5>; 238 template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> 239 using SignalProxy6 = SignalProxy<R, T1, T2, T3, T4, T5, T6>; 240 241 // TODO: When we can break ABI, consider renaming 242 // SignalProxyDetailed => SignalProxyDetailedBase 243 // SignalProxyDetailedAnyType => SignalProxyDetailed 244 245 // Shared portion of a Signal with detail 246 /** The SignalProxy provides an API similar to sigc::signal that can be used to 247 * connect sigc::slots to glib signals. 248 * 249 * This holds the name of the glib signal, including the detail name if any, 250 * and the object which might emit it. Actually, proxies are controlled by 251 * the template derivatives, which serve as gatekeepers for the 252 * types allowed on a particular signal. 253 */ 254 class GLIBMM_API SignalProxyDetailed : public SignalProxyBase 255 { 256 public: 257 ~SignalProxyDetailed() noexcept; 258 259 /// Stops the current signal emission (not in libsigc++) 260 void emission_stop(); 261 262 protected: 263 /** Creates a proxy for a signal that can be emitted by @a obj. 264 * @param obj The object that can emit the signal. 265 * @param info Information about the signal, including its name 266 * and the C callbacks that should be called by glib. 267 * @param detail_name The detail name, if any. 268 */ 269 SignalProxyDetailed( 270 Glib::ObjectBase* obj, const SignalProxyInfo* info, const Glib::ustring& detail_name); 271 272 /** Connects a signal handler to a signal. 273 * This is called by connect() and connect_notify() in derived SignalProxyDetailedAnyType classes. 274 * 275 * @param notify Whether this method is called by connect_notify() or by connect(). 276 * @param slot The signal handler, usually created with sigc::mem_fun() or sigc::ptr_fun(). 277 * @param after Whether this signal handler should be called before or after the default signal 278 * handler. 279 */ 280 sigc::slot_base& connect_impl_(bool notify, const sigc::slot_base& slot, bool after); 281 282 /** Connects a signal handler to a signal. 283 * @see connect_impl_(bool notify, const sigc::slot_base& slot, bool after). 284 * 285 * @newin{2,48} 286 */ 287 sigc::slot_base& connect_impl_(bool notify, sigc::slot_base&& slot, bool after); 288 289 private: 290 const SignalProxyInfo* info_; // Pointer to statically allocated structure. 291 const Glib::ustring detailed_name_; // signal_name[::detail_name] 292 293 // no copy assignment 294 SignalProxyDetailed& operator=(const SignalProxyDetailed&); 295 }; 296 297 /** Proxy for signals with any number of arguments and possibly a detailed name. 298 * Use the connect() or connect_notify() method, with sigc::mem_fun() or sigc::ptr_fun() 299 * to connect signal handlers to signals. 300 */ 301 template <class R, class... T> 302 class SignalProxyDetailedAnyType : public SignalProxyDetailed 303 { 304 public: 305 using SlotType = sigc::slot<R, T...>; 306 using VoidSlotType = sigc::slot<void, T...>; 307 SignalProxyDetailedAnyType(ObjectBase * obj,const SignalProxyInfo * info,const Glib::ustring & detail_name)308 SignalProxyDetailedAnyType( 309 ObjectBase* obj, const SignalProxyInfo* info, const Glib::ustring& detail_name) 310 : SignalProxyDetailed(obj, info, detail_name) 311 { 312 } 313 314 /** Connects a signal handler to a signal. 315 * 316 * For instance, connect( sigc::mem_fun(*this, &TheClass::on_something) ); 317 * 318 * @param slot The signal handler, usually created with sigc::mem_fun() or sigc::ptr_fun(). 319 * @param after Whether this signal handler should be called before or after the default signal 320 * handler. 321 */ 322 sigc::connection connect(const SlotType& slot, bool after = true) 323 { 324 return sigc::connection(connect_impl_(false, slot, after)); 325 } 326 327 /** Connects a signal handler to a signal. 328 * @see connect(const SlotType& slot, bool after). 329 * 330 * @newin{2,48} 331 */ 332 sigc::connection connect(SlotType&& slot, bool after = true) 333 { 334 return sigc::connection(connect_impl_(false, std::move(slot), after)); 335 } 336 337 /** Connects a signal handler without a return value to a signal. 338 * By default, the signal handler will be called before the default signal handler. 339 * 340 * For instance, connect_notify( sigc::mem_fun(*this, &TheClass::on_something) ); 341 * 342 * If the signal requires signal handlers with a @c void return type, 343 * the only difference between connect() and connect_notify() is the default 344 * value of @a after. 345 * 346 * If the signal requires signal handlers with a return value of type T, 347 * connect_notify() binds <tt>return T()</tt> to the connected signal handler. 348 * For instance, if the return type is @c bool, the following two calls are equivalent. 349 * @code 350 * connect_notify( sigc::mem_fun(*this, &TheClass::on_something) ); 351 * connect( sigc::bind_return<bool>(sigc::mem_fun(*this, &TheClass::on_something), false), false 352 * ); 353 * @endcode 354 * 355 * @param slot The signal handler, which should have a @c void return type, 356 * usually created with sigc::mem_fun() or sigc::ptr_fun(). 357 * @param after Whether this signal handler should be called before or after the default signal 358 * handler. 359 */ 360 sigc::connection connect_notify(const VoidSlotType& slot, bool after = false) 361 { 362 return sigc::connection(connect_impl_(true, slot, after)); 363 } 364 365 /** Connects a signal handler without a return value to a signal. 366 * @see connect_notify(const VoidSlotType& slot, bool after). 367 * 368 * @newin{2,48} 369 */ 370 sigc::connection connect_notify(VoidSlotType&& slot, bool after = false) 371 { 372 return sigc::connection(connect_impl_(true, std::move(slot), after)); 373 } 374 }; 375 376 /* Templates below has been added to avoid API break, and should not be 377 * used in a newly created code. SignalProxyDetailedAnyType class should be 378 * used instead of SignalProxyDetailed# class. 379 */ 380 template <typename R> 381 using SignalProxyDetailed0 = SignalProxyDetailedAnyType<R>; 382 template <typename R, typename T1> 383 using SignalProxyDetailed1 = SignalProxyDetailedAnyType<R, T1>; 384 template <typename R, typename T1, typename T2> 385 using SignalProxyDetailed2 = SignalProxyDetailedAnyType<R, T1, T2>; 386 template <typename R, typename T1, typename T2, typename T3> 387 using SignalProxyDetailed3 = SignalProxyDetailedAnyType<R, T1, T2, T3>; 388 template <typename R, typename T1, typename T2, typename T3, typename T4> 389 using SignalProxyDetailed4 = SignalProxyDetailedAnyType<R, T1, T2, T3, T4>; 390 template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5> 391 using SignalProxyDetailed5 = SignalProxyDetailedAnyType<R, T1, T2, T3, T4, T5>; 392 template <typename R, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6> 393 using SignalProxyDetailed6 = SignalProxyDetailedAnyType<R, T1, T2, T3, T4, T5, T6>; 394 395 } // namespace Glib 396 397 #endif /* _GLIBMM_SIGNALPROXY_H */ 398