1 /* signalproxy_connectionnode.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 <glibmm/signalproxy_connectionnode.h>
20 #include <glibmm/object.h>
21 #include <utility> // std::move()
22
23 namespace Glib
24 {
25
SignalProxyConnectionNode(const sigc::slot_base & slot,GObject * gobject)26 SignalProxyConnectionNode::SignalProxyConnectionNode(const sigc::slot_base& slot, GObject* gobject)
27 : connection_id_(0), slot_(slot), object_(gobject)
28 {
29 // The cleanup callback will be called when the connection is disconnected.
30 slot_.set_parent(this, &SignalProxyConnectionNode::notify /* cleanup callback */);
31 }
32
SignalProxyConnectionNode(sigc::slot_base && slot,GObject * gobject)33 SignalProxyConnectionNode::SignalProxyConnectionNode(sigc::slot_base&& slot, GObject* gobject)
34 : connection_id_(0), slot_(std::move(slot)), object_(gobject)
35 {
36 // The cleanup callback will be called when the connection is disconnected.
37 slot_.set_parent(this, &SignalProxyConnectionNode::notify /* cleanup callback */);
38 }
39
40 // notify is a message coming up from the slot to be passed back to Gtk+
41 // disconnect is a message coming up from the Gtk+ to be passed down to SigC++
42 // static
43 void*
notify(void * data)44 SignalProxyConnectionNode::notify(void* data)
45 {
46 // notification from libsigc++.
47 SignalProxyConnectionNode* conn = static_cast<SignalProxyConnectionNode*>(data);
48
49 // If there is no object, this call was triggered from destroy_notify_handler(),
50 // because we set conn->object to 0 there:
51 if (conn && conn->object_)
52 {
53 GObject* o = conn->object_;
54 conn->object_ = nullptr;
55
56 // We check first, because during destruction, GTK+ sometimes seems to
57 // disconnect them for us, before we expect it to. See bug #87912
58 if (g_signal_handler_is_connected(o, conn->connection_id_))
59 {
60 // Disconnecting triggers execution of destroy_notify_handler(), eiter immediately or later:
61 // When the signal handler is currently running. (for instance, if the callback disconnects
62 // its own connection)
63 // In that case, destroy_notify_handler() will be called after this whole function has
64 // returned.
65 // Anyway. destroy_notify_handler() will always be called, so we leave that to do the
66 // deletion.
67
68 // Forget the connection:
69 gulong connection_id = conn->connection_id_;
70 conn->connection_id_ = 0;
71
72 g_signal_handler_disconnect(o, connection_id);
73 }
74 }
75
76 return nullptr; // apparently unused in libsigc++
77 }
78
79 // static
80 void
destroy_notify_handler(gpointer data,GClosure *)81 SignalProxyConnectionNode::destroy_notify_handler(gpointer data, GClosure*)
82 {
83 // glib calls this when it has finished with a glib signal connection,
84 // either when the emitting object dies, or when the connection has been disconnected.
85
86 // notification from gtk+.
87 SignalProxyConnectionNode* conn = static_cast<SignalProxyConnectionNode*>(data);
88
89 if (conn)
90 {
91 // the object has already lost track of this object.
92 conn->object_ = nullptr;
93
94 // If there are connection objects referring to slot_ they are notified during
95 // destruction of slot_.
96 delete conn;
97 }
98 }
99
100 } /* namespace Glib */
101