DEFINITION MODULE GtkClosures ; (* m2-GTK4 - per-connection signal closures. GObject signals carry a single gpointer of user data. This module allocates a small context for each connection, stores the handler and the user payload in it, and installs a trampoline as the C callback. When the connection is removed - explicitly with g_signal_handler_disconnect(), or implicitly when the GObject is finalized - the optional destroy procedure runs and the context is freed. Every connection therefore owns its own state and cleans up after itself. Handlers receive exactly the payload passed to Connect*; recover the typed state with SYSTEM.CAST: PROCEDURE OnClick (button, user: ADDRESS); VAR state: State; BEGIN state := CAST(State, user); ... END OnClick; ... Connect2(button, "clicked", OnClick, CAST(ADDRESS, state)); ISO dialect required -------------------- This module (and therefore the whole build) uses -fiso: CAST comes from ISO's SYSTEM, and NEW/DISPOSE need ALLOCATE/DEALLOCATE from the ISO Storage module. *) FROM SYSTEM IMPORT ADDRESS; EXPORT UNQUALIFIED Handler2, Handler3, DestroyProc, Connect2, Connect3, Connect2Owned, Connect3Owned; TYPE (* void handler(instance, user_data) e.g. GtkButton "clicked". *) Handler2 = PROCEDURE (ADDRESS, ADDRESS); (* void handler(instance, parameter, user_data) e.g. GAction "activate"/"change-state", GObject "notify". *) Handler3 = PROCEDURE (ADDRESS, ADDRESS, ADDRESS); (* void destroy(user_data) - release the payload when the connection goes away; pass NIL when the payload is not owned. *) DestroyProc = PROCEDURE (ADDRESS); (* Connect a 2-argument handler; the payload is not owned. *) PROCEDURE Connect2 (instance: ADDRESS; signal: ARRAY OF CHAR; handler: Handler2; user: ADDRESS) : [ LONGCARD ]; (* Connect a 3-argument handler; the payload is not owned. *) PROCEDURE Connect3 (instance: ADDRESS; signal: ARRAY OF CHAR; handler: Handler3; user: ADDRESS) : [ LONGCARD ]; (* As Connect2, but destroy(user) runs when the connection is removed. *) PROCEDURE Connect2Owned (instance: ADDRESS; signal: ARRAY OF CHAR; handler: Handler2; user: ADDRESS; destroy: DestroyProc) : [ LONGCARD ]; (* As Connect3, but destroy(user) runs when the connection is removed. *) PROCEDURE Connect3Owned (instance: ADDRESS; signal: ARRAY OF CHAR; handler: Handler3; user: ADDRESS; destroy: DestroyProc) : [ LONGCARD ]; END GtkClosures.