# Recursive loop of callbacks in signal connect method of Gtk4 widgets

**URL:** https://discourse.julialang.org/t/recursive-loop-of-callbacks-in-signal-connect-method-of-gtk4-widgets/107274
**Category:** Visualization
**Tags:** question, vscode, gtk, gui, crash
**Created:** [December 7, 2023, 2:16pm UTC](https://discourse.julialang.org/t/recursive-loop-of-callbacks-in-signal-connect-method-of-gtk4-widgets/107274 "2023-12-07T14:16:14Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![apurvdarji](https://avatars.discourse-cdn.com/v4/letter/a/e99b99/32.png) [@apurvdarji](https://discourse.julialang.org/u/apurvdarji)
#### Post date: [December 7, 2023, 2:16pm UTC](https://discourse.julialang.org/t/recursive-loop-of-callbacks-in-signal-connect-method-of-gtk4-widgets/107274/1 "2023-12-07T14:16:14Z")

</div>

I am trying to do bi-directional binding of two textboxes which are GtkEntry widgets from Gtk4.jl. The two textboxes should have the same text. I am using signal connect handlers on change events to achieve that. But it crashes the Julia REPL.  
Following is my code:

```julia
using Gtk4

win = GtkWindow("mirrored text boxes")
hbox = GtkBox(:h)
push!(win, hbox)

textbox1 = GtkEntry()
textbox2 = GtkEntry()
push!(hbox, textbox1)
push!(hbox, textbox2)

## try_1
id1 = signal_connect(textbox1, :changed) do widget
    set_gtk_property!(textbox2, :text, get_gtk_property(textbox1, :text))
end
id2 = signal_connect(textbox2, :changed) do widget
    #set_gtk_property!(textbox1, :text, get_gtk_property(textbox2, :text))
end

```

If I uncomment the middle line in `id2` signal, and run the code, it crashes the Julia terminal.  
I guess that it starts a recursive loop of callbacks. But even if I keep that line commented in `id2`, it still crashes the REPL. I do not understand WHY. I was able to capture the screenshot just before the crash, it reads:

```julia
GLib-GObject:ERROR:./gobject/gsignal.c:884;emission_pop: code should not be reached
Bail out!
GLib-GObject:ERROR:/gobject/gsignal.c:884:emission_pop: code should not be reached

[392321 signal (6): Abort trap: 6 in expression starting at none:0

```

I have also tried the following to stop the recursive loop of the callbacks. But it does not work and crashes the REPL.

```julia
## try_2
signal_connect(textbox1, :changed) do widget
    if get_gtk_property(textbox1, :text) != get_gtk_property(textbox2, :text)
        set_gtk_property!(textbox2, :text, get_gtk_property(textbox1, :text))
    end
end
signal_connect(textbox2, :changed) do widget
    if get_gtk_property(textbox2, :text) != get_gtk_property(textbox1, :text)
        set_gtk_property!(textbox1, :text, get_gtk_property(textbox2, :text))
    end
end

```

Finally, I was able to avoid the callbacks loop by using `signal_handler_block` and `signal_handler_unblock`.

```julia
## try_3
id1 = signal_connect(textbox1, :changed) do widget
        signal_handler_block(textbox2, id2)
        set_gtk_property!(textbox2, :text, get_gtk_property(textbox1, :text))
        signal_handler_unblock(textbox2, id2)
end

id2 = signal_connect(textbox2, :changed) do widget
        signal_handler_block(textbox1, id1)
        set_gtk_property!(textbox1, :text, get_gtk_property(textbox2, :text))
        signal_handler_unblock(textbox1, id1)
end

```

But I am still wondering why the firing of the `id2` signal without any action in `## try_1` block crashed the REPL.

Please let me know if something is not clear and you need more information. Thank you in advance! I am using Julia v"1.9.3" in VS Code on a Mac device.

---

<div class="post-metadata">

### Author: ![tknopp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tknopp/32/3569_2.png) [@tknopp](https://discourse.julialang.org/u/tknopp)
#### Post date: [December 7, 2023, 2:53pm UTC](https://discourse.julialang.org/t/recursive-loop-of-callbacks-in-signal-connect-method-of-gtk4-widgets/107274/2 "2023-12-07T14:53:25Z")

</div>

With a callback one cannot change the UI. Thus one needs to run the code at a later stage, which can be done by the `@idle_add` macro. So change to:

```julia
id1 = signal_connect(textbox1, :changed) do widget
    @idle_add set_gtk_property!(textbox2, :text, get_gtk_property(textbox1, :text))
end
id2 = signal_connect(textbox2, :changed) do widget
    @idle_add set_gtk_property!(textbox1, :text, get_gtk_property(textbox2, :text))
end

```

But this will not fix the recursion issue. What I usually do in that situation is to define some global

```julia
const changingUIParameter = Ref(false)

```

which I then check like this:

```julia
id1 = signal_connect(textbox1, :changed) do widget
    if !changingUIParameter[]
      changingUIParameter[] = true
      @idle_add begin
          set_gtk_property!(textbox2, :text, get_gtk_property(textbox1, :text))
          changingUIParameter[] = false
      end
    end
end
id2 = signal_connect(textbox2, :changed) do widget
    if !changingUIParameter[]
      changingUIParameter[] = true
      @idle_add begin
          set_gtk_property!(textbox1, :text, get_gtk_property(textbox2, :text))
          changingUIParameter[] = false
      end
    end
end

```
