1 /* signalproxy.cc
2  *
3  * Copyright (C) 2002 The gtkmm Development Team
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <glib-object.h>
20 #include <glibmm/exceptionhandler.h>
21 #include <glibmm/object.h>
22 #include <glibmm/signalproxy.h>
23 
24 namespace Glib
25 {
26 
27 // SignalProxyBase implementation:
28 
SignalProxyBase(Glib::ObjectBase * obj)29 SignalProxyBase::SignalProxyBase(Glib::ObjectBase* obj) : obj_(obj)
30 {
31 }
32 
33 // SignalProxyNormal implementation:
34 
SignalProxyNormal(Glib::ObjectBase * obj,const SignalProxyInfo * info)35 SignalProxyNormal::SignalProxyNormal(Glib::ObjectBase* obj, const SignalProxyInfo* info)
36 : SignalProxyBase(obj), info_(info)
37 {
38 }
39 
~SignalProxyNormal()40 SignalProxyNormal::~SignalProxyNormal() noexcept
41 {
42 }
43 
44 sigc::slot_base&
connect_(const sigc::slot_base & slot,bool after)45 SignalProxyNormal::connect_(const sigc::slot_base& slot, bool after)
46 {
47   return connect_impl_(info_->callback, slot, after);
48 }
49 
50 sigc::slot_base&
connect_notify_(const sigc::slot_base & slot,bool after)51 SignalProxyNormal::connect_notify_(const sigc::slot_base& slot, bool after)
52 {
53   return connect_impl_(info_->notify_callback, slot, after);
54 }
55 
56 sigc::slot_base&
connect_impl_(GCallback callback,const sigc::slot_base & slot,bool after)57 SignalProxyNormal::connect_impl_(GCallback callback, const sigc::slot_base& slot, bool after)
58 {
59   // create a proxy to hold our connection info
60   auto pConnectionNode = new SignalProxyConnectionNode(slot, obj_->gobj());
61 
62   // connect it to glib
63   // pConnectionNode will be passed in the data argument to the callback.
64   pConnectionNode->connection_id_ = g_signal_connect_data(obj_->gobj(), info_->signal_name,
65     callback, pConnectionNode, &SignalProxyConnectionNode::destroy_notify_handler,
66     static_cast<GConnectFlags>((after) ? G_CONNECT_AFTER : 0));
67 
68   return pConnectionNode->slot_;
69 }
70 
71 sigc::slot_base&
connect_impl_(bool notify,sigc::slot_base && slot,bool after)72 SignalProxyNormal::connect_impl_(bool notify, sigc::slot_base&& slot, bool after)
73 {
74   // create a proxy to hold our connection info
75   auto pConnectionNode = new SignalProxyConnectionNode(std::move(slot), obj_->gobj());
76 
77   // connect it to glib
78   // pConnectionNode will be passed in the data argument to the callback.
79   pConnectionNode->connection_id_ = g_signal_connect_data(obj_->gobj(), info_->signal_name,
80     notify ? info_->notify_callback : info_->callback, pConnectionNode,
81     &SignalProxyConnectionNode::destroy_notify_handler,
82     static_cast<GConnectFlags>(after ? G_CONNECT_AFTER : 0));
83 
84   return pConnectionNode->slot_;
85 }
86 
87 void
emission_stop()88 SignalProxyNormal::emission_stop()
89 {
90   g_signal_stop_emission_by_name(obj_->gobj(), info_->signal_name);
91 }
92 
93 // static
94 void
slot0_void_callback(GObject * self,void * data)95 SignalProxyNormal::slot0_void_callback(GObject* self, void* data)
96 {
97   // Do not try to call a signal on a disassociated wrapper.
98   if (Glib::ObjectBase::_get_current_wrapper(self))
99   {
100     try
101     {
102       if (sigc::slot_base* const slot = data_to_slot(data))
103         (*static_cast<sigc::slot<void>*>(slot))();
104     }
105     catch (...)
106     {
107       Glib::exception_handlers_invoke();
108     }
109   }
110 }
111 
112 // SignalProxyDetailed implementation:
113 
SignalProxyDetailed(Glib::ObjectBase * obj,const SignalProxyInfo * info,const Glib::ustring & detail_name)114 SignalProxyDetailed::SignalProxyDetailed(
115   Glib::ObjectBase* obj, const SignalProxyInfo* info, const Glib::ustring& detail_name)
116 : SignalProxyBase(obj),
117   info_(info),
118   detailed_name_(Glib::ustring(info->signal_name) +
119                  (detail_name.empty() ? Glib::ustring() : ("::" + detail_name)))
120 {
121 }
122 
~SignalProxyDetailed()123 SignalProxyDetailed::~SignalProxyDetailed() noexcept
124 {
125 }
126 
127 sigc::slot_base&
connect_impl_(bool notify,const sigc::slot_base & slot,bool after)128 SignalProxyDetailed::connect_impl_(bool notify, const sigc::slot_base& slot, bool after)
129 {
130   // create a proxy to hold our connection info
131   auto pConnectionNode = new SignalProxyConnectionNode(slot, obj_->gobj());
132 
133   // connect it to glib
134   // pConnectionNode will be passed in the data argument to the callback.
135   pConnectionNode->connection_id_ = g_signal_connect_data(obj_->gobj(), detailed_name_.c_str(),
136     notify ? info_->notify_callback : info_->callback, pConnectionNode,
137     &SignalProxyConnectionNode::destroy_notify_handler,
138     static_cast<GConnectFlags>(after ? G_CONNECT_AFTER : 0));
139 
140   return pConnectionNode->slot_;
141 }
142 
143 sigc::slot_base&
connect_impl_(bool notify,sigc::slot_base && slot,bool after)144 SignalProxyDetailed::connect_impl_(bool notify, sigc::slot_base&& slot, bool after)
145 {
146   // create a proxy to hold our connection info
147   auto pConnectionNode = new SignalProxyConnectionNode(std::move(slot), obj_->gobj());
148 
149   // connect it to glib
150   // pConnectionNode will be passed in the data argument to the callback.
151   pConnectionNode->connection_id_ = g_signal_connect_data(obj_->gobj(), detailed_name_.c_str(),
152     notify ? info_->notify_callback : info_->callback, pConnectionNode,
153     &SignalProxyConnectionNode::destroy_notify_handler,
154     static_cast<GConnectFlags>(after ? G_CONNECT_AFTER : 0));
155 
156   return pConnectionNode->slot_;
157 }
158 
159 void
emission_stop()160 SignalProxyDetailed::emission_stop()
161 {
162   g_signal_stop_emission_by_name(obj_->gobj(), detailed_name_.c_str());
163 }
164 
165 } // namespace Glib
166