+(defmethod signal-connect ((gobject gobject) signal function &key after object)
+"Connects a callback function to a signal for a particular object. If :OBJECT
+ is T, the object connected to is passed as the first argument to the callback
+ function, or if :OBJECT is any other non NIL value, it is passed as the first
+ argument instead. If :AFTER is non NIL, the handler will be called after the
+ default handler of the signal."
+ (let ((callback-id
+ (make-callback-closure
+ (cond
+ ((or (eq object t) (eq object gobject)) function)
+ ((not object)
+ #'(lambda (&rest args) (apply function (cdr args))))
+ (t
+ #'(lambda (&rest args) (apply function object (rest args))))))))
+ (signal-connect-closure gobject signal callback-id :after after)))
+
+
+;;; Message logging
+
+;; TODO: define and signal conditions based on log-level
+;(defun log-handler (domain log-level message)
+(def-callback log-handler (c-call:void (domain c-call:c-string)
+ (log-level c-call:int)
+ (message c-call:c-string))
+ (error "~A: ~A" domain message))
+
+(setf (extern-alien "log_handler" system-area-pointer) (callback log-handler))
+
+
+;;;; Convenient macros
+
+(defmacro def-callback-marshal (name (return-type &rest args))
+ (let ((names (loop
+ for arg in args
+ collect (if (atom arg) (gensym) (first arg))))
+ (types (loop
+ for arg in args
+ collect (if (atom arg) arg (second arg)))))
+ `(defcallback ,name (,return-type ,@(mapcar #'list names types)
+ (callback-id unsigned-int))
+ (invoke-callback callback-id ',return-type ,@names))))
+
+(defmacro with-callback-function ((id function) &body body)
+ `(let ((,id (register-callback-function ,function)))
+ (unwind-protect
+ (progn ,@body)
+ (destroy-user-data ,id))))