Skip to content

Missing dissconnect #139

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
gavr123456789 opened this issue Jun 17, 2021 · 9 comments
Closed

Missing dissconnect #139

gavr123456789 opened this issue Jun 17, 2021 · 9 comments

Comments

@gavr123456789
Copy link

gavr123456789 commented Jun 17, 2021

Here my app example when all good:

Peek.2021-06-17.17-59.mp4

Im using ListView with factory from this good known tutorial: https://github.com/ToshioCP/Gtk4-tutorial/blob/main/gfm/sec25.md

proc unbind_cb(factory: gtk4.SignalListItemFactory, listitem: gtk4.ListItem) =  
# There's nothing to do here.   
# If you does something like setting a signal in bind_cb,  
# then disconnecting the signal is necessary in unbind_cb.   echo "unbind"

But now I have connect in my bind_cb so i need disconnect func, and im missing it.
Here what happening:

Peek.2021-06-18.00-40.mp4

How you can see nothing bad happend with open/close empty folder test, but there are crash with others.
Absolutelly nothing in console throw(no error messages)
Im not 100% sure, but I think its because there no disconnect in my unbind_cb and when the factory starts reusing the same widgets without disconnecting the previous signals there is a problem

@gavr123456789
Copy link
Author

Here how i dissconnected signals in my previous GTK 3 vala app 11, 12, 16, 17 lines: https://github.com/gavr123456789/FileBrowser/blob/master/src/Views/RowWidget.vala#L16
Here my current nim version GTK 4: https://github.com/gavr123456789/Katana/blob/master/createListView.nim

@gavr123456789
Copy link
Author

May be this some how related to #118

@StefanSalewski
Copy link
Owner

May be this some how related to #118

No, should be not related. I think what demotohiro reported is a tiny well know leak for a connect() macro call. That leak is a few bytes in the macro -- unfortunately I am not good in macro writing and there is no support from core devs. And I have always the fear that I may break it, so whenever I modify macros I would have to do extended testing. That is more a task for long dark winter.

@StefanSalewski
Copy link
Owner

What exactly do you need? Is it g-signal-handler-disconnect

https://developer.gnome.org/gobject/stable/gobject-Signals.html#g-signal-handler-disconnect

That may be hard, I just try to remember when I started with gintro in 2015, I think that time I had the impression that providing a g-signal-handler-disconnect() would be very difficult. Maybe we would have to consult an expert like Arne Doehring or Disruptec for that :-(

A link to a tiny working C code example which uses that disconect would help.

@gavr123456789
Copy link
Author

I was never interested in how Vala does this on the C side of the code, the first Googling gave out that there are several types of discount in C.
disconnect-by-func
disconnect-matched
https://stackoverflow.com/questions/8037345/how-to-disconnect-a-signal-of-gtk
I will try to create minimac example in Vala, and send to you C code that generated from it.

@gavr123456789
Copy link
Author

Looks like Vala using disconnect-matched, here line 16 in C code:
Vala Line 16: direction_btn.toggled.disconnect(direction_toggled_handler);
Vala direction_toggled_handler: void direction_toggled_handler (ToggleButton src){...}
Vala direction_btn.toggled is a signal "toggled" of ToggleButton, Vala has strong typed signals.
C:

	RowWidget * self;
	GtkToggleButton* _tmp0_;
	guint _tmp1_;
	GtkToggleButton* _tmp2_;
	guint _tmp3_;

	self = G_TYPE_CHECK_INSTANCE_CAST (obj, TYPE_ROW_WIDGET, RowWidget);
#line 16 "../src/Views/RowWidget.vala"
	_tmp0_ = self->priv->direction_btn;
#line 16 "../src/Views/RowWidget.vala"
	g_signal_parse_name ("toggled", gtk_toggle_button_get_type (), &_tmp1_, NULL, FALSE);
#line 16 "../src/Views/RowWidget.vala"
	g_signal_handlers_disconnect_matched (_tmp0_, G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, _tmp1_, 0, NULL, (GCallback) _row_widget_direction_toggled_handler_gtk_toggle_button_toggled, self);

So looks like first what we doing is getting signal handler in to &tmp1, by signal name + GType with g_signal_parse_name, than with this signal id we disconnecting signal by call g_signal_handlers_disconnect_matched, _row_widget_direction_toggled_handler_gtk_toggle_button_toggled here is call back that was connected:
Vala:

direction_btn.toggled.connect(direction_toggled_handler);

C:

self = (RowWidget*) g_object_new (object_type, NULL);
...
_tmp9_ = self->priv->direction_btn;
g_signal_connect_object (_tmp9_, "toggled", (GCallback) _row_widget_direction_toggled_handler_gtk_toggle_button_toggled, self, 0);

@gavr123456789
Copy link
Author

Just done simplest example: 2 buttons, second btn is counter that increase its label, first disconnecting signal of second.

#!/usr/bin/env -S vala --pkg gtk4

int counter = 0;

void button2_clicked_cb (Gtk.Button button){
  counter++;
  button.label = @"$counter";
}

int main (string[] argv) {
  var app = new Gtk.Application ("com.example.GtkApplication", GLib.ApplicationFlags.FLAGS_NONE);

  app.activate.connect (() => {
      var window = new Gtk.ApplicationWindow (app);

      var button = new Gtk.Button.with_label ("disconnect btn 2");
      var button2 = new Gtk.Button.with_label ("connected");
      button2.clicked.connect (button2_clicked_cb);
      
      button.clicked.connect (() => {
          print("disconnect");
          button2.clicked.disconnect (button2_clicked_cb);
      });


      var box = new Gtk.Box(Gtk.Orientation.HORIZONTAL, 0);
      box.append(button);
      box.append(button2);
      window.set_child (box);
      window.present ();
  });

  return app.run (argv);
}

To run make it executable and run file.
To get C code valac -C filename --pkg gtk4

@StefanSalewski
Copy link
Owner

Well, actually the function signalHandlerDisconnect() is available, so we can rewrite your last vala example as

# nim c --gc:arc t.nim
import gintro/[gtk4, gobject, gio]

var counter: int
var id: uint64

proc button2ClickedCb(button: Button) =
  inc(counter)
  button.label = $counter
  
proc buttonClickedCb(button: Button; arg: Button) =
  echo("disconnect")
  arg.signalHandlerDisconnect(id)

proc activate(app: gtk4.Application) =
  let window = newApplicationWindow(app)
  let button = newButton("disconnect btn 2")
  let button2 = newButton("connected")
  id = button2.connect("clicked", button2ClickedCb)
  button.connect("clicked", buttonClickedCb, button2)  
  let box = newBox(Orientation.horizontal, 0)
  box.append(button)
  box.append(button2)
  window.setChild(box)
  window.present()

proc main =
  let app = newApplication("org.gtk.example", {})
  app.connect("activate", activate)
  let status = app.run
  quit(status)

main()

Maybe not that nice due to the global id variable, but you can subclass a Button as described in the gintro README and add a field id, or you can create a ref object with field button and id and pass that as arg.

I am not sure if this will solve your initial issue. The link to your nim program was not working.

If this is not enough, maybe you can create your own g_signal_handlers_disconnect_matched() in pure Nim, which then calls signalHandlerDisconnect(). Note that disconnecting more than one time may give an error, you may catch that somehow.

@gavr123456789
Copy link
Author

@StefanSalewski Thank you very much! Now everything works and does not crash.

Peek.2021-06-19.05-34.mp4

The link to your nim program was not working.

https://github.com/gavr123456789/Katana/blob/master/list_view.nim#L33
https://github.com/gavr123456789/Katana/blob/master/row_widget.nim#L11

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants