Module: Lich::Common::GtkSignalHandlerRetention
- Defined in:
- documented/common/gtk.rb
Overview
Retain both the receiver wrapper and its callback Procs on the Ruby side. ruby-gnome stores signal handlers in C-side closures that Ruby's GC cannot see, which can leave long-lived GTK callbacks eligible for collection.
Instance Method Summary collapse
-
#signal_connect(signal, *args) {|Object| ... } ⇒ Integer, Object
Connects a signal handler block to a GTK receiver while retaining the callback.
Instance Method Details
#signal_connect(signal, *args) {|Object| ... } ⇒ Integer, Object
Callbacks are retained in Lich::Common.gtk_signal_handlers until the receiver is destroyed or the handler is manually disconnected
Connects a signal handler block to a GTK receiver while retaining the callback.
ruby-gnome stores signal handlers in C-side closures that Ruby's GC cannot see, which can leave long-lived GTK callbacks eligible for collection. This method wraps the native #signal_connect to retain both the receiver wrapper and the callback Proc on the Ruby side, ensuring they survive until the receiver is destroyed.
The first call to signal_connect on a receiver also installs a 'destroy' signal handler that automatically cleans up retained references when the widget is destroyed.
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 |
# File 'documented/common/gtk.rb', line 251 def signal_connect(signal, *args, &block) return super(signal, *args, &block) unless block receiver = self entry = Lich::Common.with_gtk_registry_lock do retained_entry = Lich::Common.gtk_signal_handlers[receiver] ||= { receiver: self, handlers: [], cleanup_installed: false } retained_entry[:handlers] << block retained_entry end cleanup = proc do Lich::Common.release_gtk_signal_handlers(receiver) false end install_cleanup = Lich::Common.with_gtk_registry_lock do next false if entry[:cleanup_installed] entry[:cleanup_installed] = true entry[:handlers] << cleanup true end if install_cleanup begin super('destroy', &cleanup) rescue StandardError Lich::Common.with_gtk_registry_lock do entry[:handlers].delete(cleanup) entry[:cleanup_installed] = false end end end begin super(signal, *args, &block) rescue StandardError Lich::Common.with_gtk_registry_lock do entry[:handlers].delete(cleanup) entry[:handlers].delete(block) entry[:cleanup_installed] = false unless entry[:handlers].include?(cleanup) Lich::Common.gtk_signal_handlers.delete(receiver) if entry[:handlers].empty? end raise end end |