1 /* 2 * This file is part of d-dazzle. 3 * 4 * d-dazzle is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU Lesser General Public License 6 * as published by the Free Software Foundation; either version 3 7 * of the License, or (at your option) any later version, with 8 * some exceptions, please read the COPYING file. 9 * 10 * d-dazzle 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 13 * GNU Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public License 16 * along with d-dazzle; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA 18 */ 19 module dazzle.SignalGroup; 20 21 private import dazzle.c.functions; 22 public import dazzle.c.types; 23 private import glib.ConstructionException; 24 private import glib.Str; 25 private import gobject.ObjectG; 26 private import gobject.Signals; 27 private import std.algorithm; 28 29 30 /** 31 * #DzlSignalGroup manages to simplify the process of connecting 32 * many signals to a #GObject as a group. As such there is no API 33 * to disconnect a signal from the group. 34 * 35 * In particular, this allows you to: 36 * 37 * - Change the target instance, which automatically causes disconnection 38 * of the signals from the old instance and connecting to the new instance. 39 * - Block and unblock signals as a group 40 * - Ensuring that blocked state transfers across target instances. 41 * 42 * One place you might want to use such a structure is with #GtkTextView and 43 * #GtkTextBuffer. Often times, you'll need to connect to many signals on 44 * #GtkTextBuffer from a #GtkTextView subclass. This allows you to create a 45 * signal group during instance construction, simply bind the 46 * #GtkTextView:buffer property to #DzlSignalGroup:target and connect 47 * all the signals you need. When the #GtkTextView:buffer property changes 48 * all of the signals will be transitioned correctly. 49 */ 50 public class SignalGroup : ObjectG 51 { 52 /** the main Gtk struct */ 53 protected DzlSignalGroup* dzlSignalGroup; 54 55 /** Get the main Gtk struct */ 56 public DzlSignalGroup* getSignalGroupStruct(bool transferOwnership = false) 57 { 58 if (transferOwnership) 59 ownedRef = false; 60 return dzlSignalGroup; 61 } 62 63 /** the main Gtk struct as a void* */ 64 protected override void* getStruct() 65 { 66 return cast(void*)dzlSignalGroup; 67 } 68 69 /** 70 * Sets our main struct and passes it to the parent class. 71 */ 72 public this (DzlSignalGroup* dzlSignalGroup, bool ownedRef = false) 73 { 74 this.dzlSignalGroup = dzlSignalGroup; 75 super(cast(GObject*)dzlSignalGroup, ownedRef); 76 } 77 78 79 /** */ 80 public static GType getType() 81 { 82 return dzl_signal_group_get_type(); 83 } 84 85 /** 86 * Creates a new #DzlSignalGroup for target instances of @target_type. 87 * 88 * Params: 89 * targetType = the #GType of the target instance. 90 * 91 * Returns: a new #DzlSignalGroup 92 * 93 * Throws: ConstructionException GTK+ fails to create the object. 94 */ 95 public this(GType targetType) 96 { 97 auto p = dzl_signal_group_new(targetType); 98 99 if(p is null) 100 { 101 throw new ConstructionException("null returned by new"); 102 } 103 104 this(cast(DzlSignalGroup*) p, true); 105 } 106 107 /** 108 * Blocks all signal handlers managed by @self so they will not 109 * be called during any signal emissions. Must be unblocked exactly 110 * the same number of times it has been blocked to become active again. 111 * 112 * This blocked state will be kept across changes of the target instance. 113 * 114 * See: g_signal_handler_block(). 115 */ 116 public void block() 117 { 118 dzl_signal_group_block(dzlSignalGroup); 119 } 120 121 /** 122 * Connects @callback to the signal @detailed_signal 123 * on the target instance of @self. 124 * 125 * See: g_signal_connect(). 126 * 127 * Params: 128 * detailedSignal = a string of the form "signal-name::detail" 129 * cHandler = the #GCallback to connect 130 * data = the data to pass to @callback calls 131 */ 132 public void connect(string detailedSignal, GCallback cHandler, void* data) 133 { 134 dzl_signal_group_connect(dzlSignalGroup, Str.toStringz(detailedSignal), cHandler, data); 135 } 136 137 /** 138 * Connects @callback to the signal @detailed_signal 139 * on the target instance of @self. 140 * 141 * The @callback will be called after the default handler of the signal. 142 * 143 * See: g_signal_connect_after(). 144 * 145 * Params: 146 * detailedSignal = a string of the form "signal-name::detail" 147 * cHandler = the #GCallback to connect 148 * data = the data to pass to @callback calls 149 */ 150 public void connectAfter(string detailedSignal, GCallback cHandler, void* data) 151 { 152 dzl_signal_group_connect_after(dzlSignalGroup, Str.toStringz(detailedSignal), cHandler, data); 153 } 154 155 /** 156 * Connects @callback to the signal @detailed_signal 157 * on the target instance of @self. 158 * 159 * See: g_signal_connect_data(). 160 * 161 * Params: 162 * detailedSignal = a string of the form "signal-name::detail" 163 * cHandler = the #GCallback to connect 164 * data = the data to pass to @callback calls 165 * notify = function to be called when disposing of @self 166 * flags = the flags used to create the signal connection 167 */ 168 public void connectData(string detailedSignal, GCallback cHandler, void* data, GClosureNotify notify, GConnectFlags flags) 169 { 170 dzl_signal_group_connect_data(dzlSignalGroup, Str.toStringz(detailedSignal), cHandler, data, notify, flags); 171 } 172 173 /** 174 * Connects @callback to the signal @detailed_signal 175 * on the target object of @self. 176 * 177 * Ensures that the @object stays alive during the call to @callback 178 * by temporarily adding a reference count. When the @object is destroyed 179 * the signal handler will automatically be removed. 180 * 181 * See: g_signal_connect_object(). 182 * 183 * Params: 184 * detailedSignal = a string of the form "signal-name::detail" 185 * cHandler = the #GCallback to connect 186 * object = the #GObject to pass as data to @callback calls 187 */ 188 public void connectObject(string detailedSignal, GCallback cHandler, void* object, GConnectFlags flags) 189 { 190 dzl_signal_group_connect_object(dzlSignalGroup, Str.toStringz(detailedSignal), cHandler, object, flags); 191 } 192 193 /** 194 * Connects @callback to the signal @detailed_signal 195 * on the target instance of @self. 196 * 197 * The instance on which the signal is emitted and @data 198 * will be swapped when calling @callback. 199 * 200 * See: g_signal_connect_swapped(). 201 * 202 * Params: 203 * detailedSignal = a string of the form "signal-name::detail" 204 * cHandler = the #GCallback to connect 205 * data = the data to pass to @callback calls 206 */ 207 public void connectSwapped(string detailedSignal, GCallback cHandler, void* data) 208 { 209 dzl_signal_group_connect_swapped(dzlSignalGroup, Str.toStringz(detailedSignal), cHandler, data); 210 } 211 212 /** 213 * Gets the target instance used when connecting signals. 214 * 215 * Returns: The target instance. 216 */ 217 public ObjectG getTarget() 218 { 219 auto p = dzl_signal_group_get_target(dzlSignalGroup); 220 221 if(p is null) 222 { 223 return null; 224 } 225 226 return ObjectG.getDObject!(ObjectG)(cast(GObject*) p); 227 } 228 229 /** 230 * Sets the target instance used when connecting signals. Any signal 231 * that has been registered with dzl_signal_group_connect_object() or 232 * similar functions will be connected to this object. 233 * 234 * If the target instance was previously set, signals will be 235 * disconnected from that object prior to connecting to @target. 236 * 237 * Params: 238 * target = The target instance used 239 * when connecting signals. 240 */ 241 public void setTarget(ObjectG target) 242 { 243 dzl_signal_group_set_target(dzlSignalGroup, (target is null) ? null : target.getObjectGStruct()); 244 } 245 246 /** 247 * Unblocks all signal handlers managed by @self so they will be 248 * called again during any signal emissions unless it is blocked 249 * again. Must be unblocked exactly the same number of times it 250 * has been blocked to become active again. 251 * 252 * See: g_signal_handler_unblock(). 253 */ 254 public void unblock() 255 { 256 dzl_signal_group_unblock(dzlSignalGroup); 257 } 258 259 /** 260 * This signal is emitted when the target instance of @self 261 * is set to a new #GObject. 262 * 263 * This signal will only be emitted if the target of @self is non-%NULL. 264 * 265 * Params: 266 * instance_ = a #GObject 267 */ 268 gulong addOnBind(void delegate(ObjectG, SignalGroup) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 269 { 270 return Signals.connect(this, "bind", dlg, connectFlags ^ ConnectFlags.SWAPPED); 271 } 272 273 /** 274 * This signal is emitted when the target instance of @self 275 * is set to a new #GObject. 276 * 277 * This signal will only be emitted if the previous target 278 * of @self is non-%NULL. 279 */ 280 gulong addOnUnbind(void delegate(SignalGroup) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0) 281 { 282 return Signals.connect(this, "unbind", dlg, connectFlags ^ ConnectFlags.SWAPPED); 283 } 284 }