--- /dev/null
+(* $Id$ *)
+
+open Gtk
+
+type id
+type ('a,'b) t =
+ { name: string;
+ marshaller: ('b -> GtkArgv.t -> GtkArgv.data list -> unit) }
+
+let enter_callback = ref (fun () -> ())
+and exit_callback = ref (fun () -> ())
+
+let stop_emit_ref = ref false
+let stop_emit () = stop_emit_ref := true
+
+type saved_state = State of bool
+let push_callback () =
+ !enter_callback ();
+ let old = !stop_emit_ref in
+ stop_emit_ref := false;
+ State old
+
+let pop_callback (State old) =
+ let res = !stop_emit_ref in
+ stop_emit_ref := old;
+ !exit_callback ();
+ res
+
+external connect :
+ 'a obj -> name:string -> callback:(GtkArgv.t -> unit) -> after:bool -> id
+ = "ml_gtk_signal_connect"
+external emit_stop_by_name : 'a obj -> name:string -> unit
+ = "ml_gtk_signal_emit_stop_by_name"
+let connect ~(sgn : ('a, _) t) ~callback ?(after=false) (obj : 'a obj) =
+ let callback argv =
+ let old = push_callback () in
+ let exn =
+ try sgn.marshaller callback argv (GtkArgv.get_args argv); None
+ with exn -> Some exn
+ in
+ if pop_callback old then emit_stop_by_name obj ~name:sgn.name;
+ Gaux.may ~f:raise exn
+ in
+ connect obj ~name:sgn.name ~callback ~after
+external disconnect : 'a obj -> id -> unit
+ = "ml_gtk_signal_disconnect"
+external handler_block : 'a obj -> id -> unit
+ = "ml_gtk_signal_handler_block"
+external handler_unblock : 'a obj -> id -> unit
+ = "ml_gtk_signal_handler_unblock"
+
+let marshal_unit f _ _ = f ()
+let marshal_int f _ = function
+ | GtkArgv.INT n :: _ -> f n
+ | _ -> invalid_arg "GtkSignal.marshal_int"
+
+let emit (obj : 'a obj) ~(sgn : ('a, 'b) t)
+ ~(emitter : 'a obj -> name:string -> 'b) =
+ emitter obj ~name:sgn.name
+external emit_none : 'a obj -> name:string -> unit -> unit
+ = "ml_gtk_signal_emit_none"
+let emit_unit obj ~sgn = emit obj ~emitter:emit_none ~sgn ()
+external emit_int : 'a obj -> name:string -> int -> unit
+ = "ml_gtk_signal_emit_int"
+let emit_int = emit ~emitter:emit_int