{"action":"created","issue":{"url":"https://api.github.com/repos/gtkd-developers/GtkD/issues/167","repository_url":"https://api.github.com/repos/gtkd-developers/GtkD","labels_url":"https://api.github.com/repos/gtkd-developers/GtkD/issues/167/labels{/name}","comments_url":"https://api.github.com/repos/gtkd-developers/GtkD/issues/167/comments","events_url":"https://api.github.com/repos/gtkd-developers/GtkD/issues/167/events","html_url":"https://github.com/gtkd-developers/GtkD/issues/167","id":197476182,"number":167,"title":"Enable event delegates to be removed","user":{"login":"gnunn1","id":9358238,"avatar_url":"https://avatars.githubusercontent.com/u/9358238?v=3","gravatar_id":"","url":"https://api.github.com/users/gnunn1","html_url":"https://github.com/gnunn1","followers_url":"https://api.github.com/users/gnunn1/followers","following_url":"https://api.github.com/users/gnunn1/following{/other_user}","gists_url":"https://api.github.com/users/gnunn1/gists{/gist_id}","starred_url":"https://api.github.com/users/gnunn1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gnunn1/subscriptions","organizations_url":"https://api.github.com/users/gnunn1/orgs","repos_url":"https://api.github.com/users/gnunn1/repos","events_url":"https://api.github.com/users/gnunn1/events{/privacy}","received_events_url":"https://api.github.com/users/gnunn1/received_events","type":"User","site_admin":false},"labels":[{"id":14477334,"url":"https://api.github.com/repos/gtkd-developers/GtkD/labels/Enhancement","name":"Enhancement","color":"85b6eb","default":false}],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":12,"created_at":"2016-12-24T20:17:30Z","updated_at":"2016-12-30T15:34:46Z","closed_at":null,"body":"I'm working on adding the ability to remove events in GtkD. I'm starting with prototyping it with the OnButton clicked event. I have it working and below is the the code I'm using. It's actually pretty simple, it just saves the handlerid that Signals.connectData returns in the connectedSignals associative array instead of just saving the int 1 like it was previously. When the delegate is removed, it removes it from the delegate array and if the delegate array has a count of 0 removes the signal from GTK has well.\r\n\r\nI'm happy to take this to the next step to submit a PR, namely clean up my code and find the place it needs to go in the code generation. However, one thing I noticed with this code is that GtkD only ever registers a single handler with GTK and multiplexes it if there is more then one delegate. The one issue with this is the user can't register a handler using different ConnectFlags, it's a rare situation but I had one case in Terminix where I was looking at doing this fro a draw handler.\r\n\r\nIs it worth tweaking the code to allow each delegate to map 1:1 to a GTK signal handler to allow this or were there problems with that approach and hence why it was avoided?\r\n\r\n```\r\n\tvoid delegate(Button)[] onClickedListeners;\r\n\t/**\r\n\t * Emitted when the button has been activated (pressed and released).\r\n\t */\r\n\tvoid addOnClicked(void delegate(Button) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)\r\n\t{\r\n\t\tif ( \"clicked\" !in connectedSignals )\r\n\t\t{\r\n\t\t\tulong handlerid = Signals.connectData(\r\n\t\t\t\tthis,\r\n\t\t\t\t\"clicked\",\r\n\t\t\t\tcast(GCallback)&callBackClicked,\r\n\t\t\t\tcast(void*)this,\r\n\t\t\t\tnull,\r\n\t\t\t\tconnectFlags);\r\n\t\t\tconnectedSignals[\"clicked\"] = handlerid;\r\n\t\t}\r\n\t\tonClickedListeners ~= dlg;\r\n\t}\r\n\r\n\tvoid removeOnClicked(void delegate(Button) dlg) {\r\n\t\timport std.array;\r\n\t\timport std.algorithm;\r\n\t\timport std.stdio;\r\n\r\n\t\tauto index = onClickedListeners.countUntil(dlg);\r\n\t\tif (index >= 0) {\r\n\t\t\twriteln(\"Removing handler\");\r\n\t\t\tonClickedListeners[index] = null;\r\n\t\t\tonClickedListeners = std.algorithm.remove(onClickedListeners, index);\r\n\t\t\tif (onClickedListeners.length == 0) {\r\n\t\t\t\twriteln(\"Removing signal\");\r\n\t\t\t\tulong handlerid = connectedSignals[\"clicked\"];\r\n\t\t\t\tSignals.handlerDisconnect(this, handlerid);\r\n\t\t\t\tconnectedSignals.remove(\"clicked\");\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\textern(C) static void callBackClicked(GtkButton* buttonStruct, Button _button)\r\n\t{\r\n\t\tforeach ( void delegate(Button) dlg; _button.onClickedListeners )\r\n\t\t{\r\n\t\t\tdlg(_button);\r\n\t\t}\r\n\t}\r\n```"},"comment":{"url":"https://api.github.com/repos/gtkd-developers/GtkD/issues/comments/269784849","html_url":"https://github.com/gtkd-developers/GtkD/issues/167#issuecomment-269784849","issue_url":"https://api.github.com/repos/gtkd-developers/GtkD/issues/167","id":269784849,"user":{"login":"gnunn1","id":9358238,"avatar_url":"https://avatars.githubusercontent.com/u/9358238?v=3","gravatar_id":"","url":"https://api.github.com/users/gnunn1","html_url":"https://github.com/gnunn1","followers_url":"https://api.github.com/users/gnunn1/followers","following_url":"https://api.github.com/users/gnunn1/following{/other_user}","gists_url":"https://api.github.com/users/gnunn1/gists{/gist_id}","starred_url":"https://api.github.com/users/gnunn1/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/gnunn1/subscriptions","organizations_url":"https://api.github.com/users/gnunn1/orgs","repos_url":"https://api.github.com/users/gnunn1/repos","events_url":"https://api.github.com/users/gnunn1/events{/privacy}","received_events_url":"https://api.github.com/users/gnunn1/received_events","type":"User","site_admin":false},"created_at":"2016-12-30T15:34:46Z","updated_at":"2016-12-30T15:34:46Z","body":"Looking at it again I realized the addOnXXX could be cleaned up a bit since there is no need to check that handlerId > 0, new version:\r\n\r\n```\r\n/**\r\n * Emitted when the button has been activated (pressed and released).\r\n */\r\nulong addOnClicked(void delegate(Button) dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)\r\n{\r\n\tonClickedListeners ~= new OnClickedDelegateWrapper(dlg, 0, connectFlags);\r\n\tonClickedListeners[onClickedListeners.length - 1].handlerId = Signals.connectData(\r\n\t\tthis,\r\n\t\t\"clicked\",\r\n\t\tcast(GCallback)&callBackClicked,\r\n\t\tcast(void*)onClickedListeners[onClickedListeners.length - 1],\r\n\t\tcast(GClosureNotify)&callBackClickedDestroy,\r\n\t\tconnectFlags);\r\n\treturn onClickedListeners[onClickedListeners.length - 1].handlerId;\r\n}\r\n```"}}
{"actor":{"display_login":"gnunn1"}}