11 #:*glib-interface-age*
21 #:+g-priority-default+
22 #:+g-priority-high-idle+
23 #:+g-priority-default-idle+
31 #:with-catching-to-g-error
33 #:g-error-condition-domain
34 #:g-error-condition-code
35 #:g-error-condition-message
37 #:push-library-version-features
38 #:foreign-library-minimum-version-mismatch
39 #:require-library-version)
41 "Cl-gtk2-glib is wrapper for @a[http://library.gnome.org/devel/glib/]{GLib}."))
45 (eval-when (:compile-toplevel :load-toplevel :execute)
46 (defvar *initializers-table* (make-hash-table :test 'equalp))
47 (defvar *initializers* nil)
48 (defun register-initializer (key fn)
49 (unless (gethash key *initializers-table*)
50 (setf (gethash key *initializers-table*) t
51 *initializers* (nconc *initializers* (list fn)))))
52 (defvar *finalizers-table* (make-hash-table :test 'equalp))
53 (defvar *finalizers* nil)
54 (defun register-finalizer (key fn)
55 (unless (gethash key *finalizers-table*)
56 (setf (gethash key *finalizers-table*) t
57 *finalizers* (nconc *finalizers* (list fn))))))
59 (defun run-initializers ()
60 (iter (for fn in *initializers*)
63 (defun run-finalizers ()
64 (iter (for fn in *finalizers*)
68 (pushnew 'run-initializers sb-ext:*init-hooks*)
70 (pushnew 'run-initializers ccl:*restore-lisp-functions*)
73 (pushnew 'run-finalizers sb-ext:*save-hooks*)
75 (pushnew 'run-finalizers ccl:*save-exit-functions*)
77 (defmacro at-init ((&rest keys) &body body)
79 @arg[keys]{list of expression}
81 Runs the code normally but also schedules the code to be run at image load time.
82 It is used to reinitialize the libraries when the dumped image is loaded. (Works only on SBCL for now).
84 At-init form may be called multiple times. The same code from should not be run multiple times at initialization time (in best case, this will only slow down initialization, in worst case, the code may crash). To ensure this, every @code{at-init} expression is added to hash-table with the @code{body} and @code{keys} as a composite key. This ensures that the same code is only executed once (once on the same set of parameters).
88 \(defmethod initialize-instance :after ((class gobject-class) &key &allow-other-keys)
89 (register-object-type (gobject-class-g-type-name class) (class-name class))
90 (at-init (class) (initialize-gobject-class-g-type class)))
93 In this example, for every @code{class}, @code{(initialize-gobject-class-g-type class)} will be called only once.
95 `(progn (register-initializer (list ,@keys ',body) (lambda () ,@body))
98 (defmacro at-finalize ((&rest keys) &body body)
99 `(register-finalizer (list ,@keys ',body) (lambda () ,@body)))
102 (eval-when (:compile-toplevel :load-toplevel :execute)
103 (define-foreign-library glib
104 ((:and :unix (:not :darwin)) (:or "libglib-2.0.so.0" "libglib-2.0.so"))
105 (:darwin (:or "libglib-2.0.0.dylib" "libglib-2.0.dylib"))
106 (:windows "libglib-2.0-0.dll")
107 (t (:default "libglib-2.0"))))
108 (eval-when (:compile-toplevel :load-toplevel :execute)
109 (define-foreign-library gthread
110 ((:and :unix (:not :darwin)) (:or "libgthread-2.0.so.0" "libgthread-2.0.so"))
111 (:darwin (:or "libgthread-2.0.0.dylib" "libgthread-2.0.dylib"))
112 (:windows "libgthread-2.0-0.dll")
113 (t "libgthread-2.0")))
115 (use-foreign-library glib)
116 (use-foreign-library gthread))
118 (defmacro push-library-version-features (library-name major-version-var minor-version-var &body versions)
119 `(eval-when (:load-toplevel :execute)
120 ,@(iter (for (major minor) on versions by #'cddr)
122 `(when (or (and (= ,major-version-var ,major) (>= ,minor-version-var ,minor))
123 (> ,major-version-var ,major))
124 (pushnew ,(intern (format nil "~A-~A.~A" (string library-name) major minor) (find-package :keyword)) *features*))))))
126 (define-condition foreign-library-minimum-version-mismatch (error)
127 ((library :initarg :library :reader .library)
128 (minimum-version :initarg :minimum-version :reader .minimum-version)
129 (actual-version :initarg :actual-version :reader .actual-version))
130 (:report (lambda (c s)
131 (format s "Library ~A has too old version: it is ~A but required to be at least ~A"
134 (.minimum-version c)))))
136 (defun require-library-version (library min-major-version min-minor-version major-version minor-version)
137 (unless (or (> major-version min-major-version)
138 (and (= major-version min-major-version)
139 (>= minor-version min-minor-version)))
141 (error 'foreign-library-minimum-version-mismatch
143 :minimum-version (format nil "~A.~A" min-major-version min-minor-version)
144 :actual-version (format nil "~A.~A" major-version minor-version))
145 (ignore () :report "Ignore version requirement" nil))))
152 ;; Fundamentals - Basic types
156 ;; TODO: not sure about these: for amd64 they are ok
157 (eval-when (:compile-toplevel :load-toplevel :execute)
159 ((cffi-features:cffi-feature-p :x86-64) (defctype gsize :uint64))
160 ((cffi-features:cffi-feature-p :x86) (defctype gsize :ulong))
161 ((cffi-features:cffi-feature-p :ppc32) (defctype gsize :uint32))
162 ((cffi-features:cffi-feature-p :ppc64) (defctype gsize :uint64))
163 (t (error "Can not define 'gsize', unknown CPU architecture (known are x86 and x86-64)"))))
165 (defctype gssize :long)
167 (defctype goffset :uint64)
171 ;; Fundamentals - Version information
174 (defcvar (*glib-major-version* "glib_major_version" :read-only t :library glib) :uint)
175 (defcvar (*glib-minor-version* "glib_minor_version" :read-only t :library glib) :uint)
176 (defcvar (*glib-micro-version* "glib_micro_version" :read-only t :library glib) :uint)
177 (defcvar (*glib-binary-age* "glib_binary_age" :read-only t :library glib) :uint)
178 (defcvar (*glib-interface-age* "glib_interface_age" :read-only t :library glib) :uint)
180 (push-library-version-features glib *glib-major-version* *glib-micro-version*
193 (require-library-version "Glib" 2 20 *glib-major-version* *glib-minor-version*)
197 ;; Limits of Basic Types, Standard Macros, Type Conversion Macros, Byte Order Macros,
198 ;; Numerical Definitions, Miscellaneous Macros, Atomic operations
201 ;; Core Application Support - The Main Event Loop
203 (defcstruct g-main-loop)
204 (defctype g-main-loop (:struct g-main-loop))
205 (defcstruct g-main-context)
206 (defctype g-main-context (:struct g-main-context))
207 (defcstruct g-source)
208 (defctype g-source (:struct g-source))
209 (defcstruct g-source-funcs
214 (closure-callback :pointer)
215 (closure-marshal :pointer))
216 (defctype g-source-funcs (:struct g-source-funcs))
217 (defcstruct g-source-callback-funcs
221 (defctype g-source-callback-funcs (:struct g-source-callback-funcs))
223 (defctype g-cond (:struct g-cond))
225 (defctype g-mutex (:struct g-mutex))
227 (defcstruct g-poll-fd
228 (fd :int) ;; TODO: #if defined (G_OS_WIN32) && GLIB_SIZEOF_VOID_P == 8
231 (defctype g-poll-fd (:struct g-poll-fd))
233 (defcstruct g-time-val
235 (microseconds :long))
236 (defctype g-time-val (:struct g-time-val))
238 (defcstruct g-thread)
239 (defctype g-thread (:struct g-thread))
241 (defcfun (g-main-loop-new "g_main_loop_new" :library glib) (:pointer g-main-loop)
242 (context (:pointer g-main-context))
243 (is-running :boolean))
245 (defcfun (g-main-loop-ref "g_main_loop_ref" :library glib) (:pointer g-main-loop)
246 (loop (:pointer g-main-loop)))
248 (defcfun (g-main-loop-unref "g_main_loop_unref" :library glib) (:pointer g-main-loop)
249 (loop (:pointer g-main-loop)))
251 (defcfun (g-main-loop-run "g_main_loop_run" :library glib) :void
252 (loop (:pointer g-main-loop)))
254 (defcfun (g-main-loop-quit "g_main_loop_quit" :library glib) :void
255 (loop (:pointer g-main-loop)))
257 (defcfun (g-main-loop-is-running "g_main_loop_is_running" :library glib) :boolean
258 (loop (:pointer g-main-loop)))
260 (defcfun (g-main-loop-get-context "g_main_loop_get_context" :library glib) (:pointer g-main-context)
261 (loop (:pointer g-main-loop)))
263 (defconstant +g-priority-high+ -100 "Use this for high priority event sources. It is not used within GLib or GTK+.")
264 (defconstant +g-priority-default+ 0 "Use this for default priority event sources. In GLib this priority is used when adding timeout functions with g_timeout_add(). In GDK this priority is used for events from the X server.")
265 (defconstant +g-priority-high-idle+ 100 "Use this for high priority idle functions. GTK+ uses @variable{+g-priority-high-idle+} + 10 for resizing operations, and @variable{+g-priority-high-idle+} + 20 for redrawing operations. (This is done to ensure that any pending resizes are processed before any pending redraws, so that widgets are not redrawn twice unnecessarily.)")
266 (defconstant +g-priority-default-idle+ 200 "Use this for default priority idle functions. In GLib this priority is used when adding idle functions with g_idle_add().")
267 (defconstant +g-priority-low+ 300 "Use this for very low priority background tasks. It is not used within GLib or GTK+.")
269 (defcfun (g-main-context-new "g_main_context_new" :library glib) (:pointer g-main-context))
271 (defcfun (g-main-context-ref "g_main_context_ref" :library glib) (:pointer g-main-context)
272 (context (:pointer g-main-context)))
274 (defcfun (g-main-context-unref "g_main_context_unref" :library glib) (:pointer g-main-context)
275 (context (:pointer g-main-context)))
277 (defcfun (g-main-context-default "g_main_context_default" :library glib) (:pointer g-main-context))
279 (defcfun (g-main-context-iteration "g_main_context_iteration" :library glib) :boolean
280 (context (:pointer g-main-context))
281 (may-block :boolean))
283 (defcfun (g-main-context-pending "g_main_context_pending" :library glib) :boolean
284 (context (:pointer g-main-context)))
286 (defcfun (g-main-context-find-source-by-id "g_main_context_find_source_by_id" :library glib) (:pointer g-source)
287 (context (:pointer g-main-context))
290 (defcfun (g-main-context-find-source-by-user-data "g_main_context_find_source_by_user_data" :library glib) (:pointer g-source)
291 (context (:pointer g-main-context))
292 (user-data :pointer))
294 (defcfun (g-main-context-find-source-by-funcs-user-data "g_main_context_find_source_by_funcs_user_data" :library glib) (:pointer g-source)
295 (context (:pointer g-main-context))
296 (funcs (:pointer g-source-funcs))
297 (user-data :pointer))
299 (defcfun (g-main-context-wakeup "g_main_context_wakeup" :library glib) :void
300 (context (:pointer g-main-context)))
302 (defcfun (g-main-context-acquire "g_main_context_acquire" :library glib) :boolean
303 (context (:pointer g-main-context)))
305 (defcfun (g-main-context-release "g_main_context_release" :library glib) :void
306 (context (:pointer g-main-context)))
308 (defcfun (g-main-context-is-owner "g_main_context_is_owner" :library glib) :boolean
309 (context (:pointer g-main-context)))
311 (defcfun (g-main-context-wait "g_main_context_wait" :library glib) :boolean
312 (context (:pointer g-main-context))
313 (cond (:pointer g-cond))
314 (mutex (:pointer g-mutex)))
316 (defcfun (g_main_context_prepare "g_main_context_prepare" :library glib) :boolean
317 (context (:pointer g-main-context))
318 (priority-ret (:pointer :int)))
320 (defcfun (g_main_context_query "g_main_context_query" :library glib) :int
321 (context (:pointer g-main-context))
323 (timeout-ret (:pointer :int))
324 (fds-ret (:pointer g-poll-fd))
327 (defcfun (g-main-context-check "g_main_context_check" :library glib) :int
328 (context (:pointer g-main-context))
330 (fds (:pointer g-poll-fd))
333 (defcfun (g-main-context-dispatch "g_main_context_dispatch" :library glib) :void
334 (context (:pointer g-main-context)))
336 (defcfun (g-main-context-set-poll-func "g_main_context_set_poll_func" :library glib) :void
337 (context (:pointer g-main-context))
340 (defcfun (g-main-context-get-poll-func "g_main_context_get_poll_func" :library glib) :pointer
341 (context (:pointer g-main-context)))
343 (defcfun (g-main-context-add-poll "g_main_context_add_poll" :library glib) :void
344 (context (:pointer g-main-context))
345 (fd (:pointer g-poll-fd))
348 (defcfun (g-main-context-remove-poll "g_main_context_remove_poll" :library glib) :void
349 (context (:pointer g-main-context))
350 (fd (:pointer g-poll-fd)))
352 (defcfun (g-main-depth "g_main_depth" :library glib) :int)
354 (defcfun (g-main-current-source "g_main_current_source" :library glib) (:pointer g-source))
356 (defcfun (g-timeout-source-new "g_timeout_source_new" :library glib) (:pointer g-source)
357 (interval-milliseconds :int))
359 (defcfun (g-timeout-source-new-seconds "g_timeout_source_new_seconds" :library glib) (:pointer g-source)
360 (interval-seconds :int))
362 (defcfun (g-timeout-add "g_timeout_add" :library glib) :uint
363 (interval-milliseconds :uint)
367 (defcfun (g-timeout-add-full "g_timeout_add_full" :library glib) :uint
369 (interval-milliseconds :uint)
372 (destroy-notify :pointer))
374 (defcfun (g-timeout-add-seconds "g_timeout_add_seconds" :library glib) :uint
375 (interval-seconds :uint)
379 (defcfun (g-timeout-add-seconds-full "g_timeout_add_seconds_full" :library glib) :uint
381 (interval-seconds :uint)
384 (destroy-notify :pointer))
386 (defcfun (g-idle-source-new "g_idle_source_new" :library glib) (:pointer g-source))
388 (defcfun (g-idle-add "g_idle_add" :library glib) :uint
392 (defcfun (g-idle-add-full "g_idle_add_full" :library glib) :uint
393 "A low-level function for adding callbacks to be called from main loop. Wrapper around g_idle_add_full.
394 Adds a function to be called whenever there are no higher priority events pending. If the function returns FALSE it is automatically removed from the list of event sources and will not be called again.
395 @arg[priority]{an integer specifying the priority. See @variable{+g-priority-default+}, @variable{+g-priority-default-idle+}, @variable{+g-priority-high+}, @variable{+g-priority-high-idle+}, @variable{+g-priority-low+}.}
396 @arg[function]{pointer to callback that will be called. Callback should accept a single pointer argument and return a boolean FALSE if it should be removed}
397 @arg[data]{pointer that will be passed to callback function}
398 @arg[notify]{function that will be called when callback is no more needed. It will receive the @code{data} argument}"
404 (defcfun (g-idle-remove-by-data "g_idle_remove_by_data" :library glib) :boolean
407 ;(defctype g-pid :int) ;;TODO: might work on amd64 linux, but on others
409 ;; Omitted GPid, g_child_add_watch, g_child_add_watch_full
411 (defcfun (g-source-new "g_source_new" :library glib) (:pointer g-source)
412 (source-funcs (:pointer g-source-funcs))
415 (defcfun (g-source-ref "g_source_ref" :library glib) (:pointer g-source)
416 (source (:pointer g-source)))
418 (defcfun (g-source-unref "g_source_unref" :library glib) :void
419 (source (:pointer g-source)))
421 (defcfun (g-source-set-funcs "g_source_set_funcs" :library glib) :void
422 (source (:pointer g-source))
423 (funcs (:pointer g-source-funcs)))
425 (defcfun (g-source-attach "g_source_attach" :library glib) :uint
426 (source (:pointer g-source))
427 (context (:pointer g-main-context)))
429 (defcfun (g-source-destroy "g_source_destroy" :library glib) :void
430 (source (:pointer g-source)))
432 (defcfun (g-source-is-destroyed "g_source_is_destroyed" :library glib) :boolean
433 (source (:pointer g-source)))
435 (defcfun (g-source-set-priority "g_source_set_priority" :library glib) :void
436 (source (:pointer g-source))
439 (defcfun (g-source-get-priority "g_source_get_priority" :library glib) :int
440 (source (:pointer g-source)))
442 (defcfun (g-source-set-can-recurse "g_source_set_can_recurse" :library glib) :void
443 (source (:pointer g-source))
444 (can-recurse :boolean))
446 (defcfun (g-source-get-can-recurse "g_source_get_can_recurse" :library glib) :boolean
447 (source (:pointer g-source)))
449 (defcfun (g-source-get-id "g_source_get_id" :library glib) :uint
450 (source (:pointer g-source)))
452 (defcfun (g-source-get-context "g_source_get_context" :library glib) (:pointer g-main-context)
453 (source (:pointer g-source)))
455 (defcfun (g-source-set-callback "g_source_set_callback" :library glib) :void
456 (source (:pointer g-source))
461 (defcfun (g-source-add-poll "g_source_add_poll" :library glib) :void
462 (source (:pointer g-source))
463 (fd (:pointer g-poll-fd)))
465 (defcfun (g-source-remove-poll "g_source_remove_poll" :library glib) :void
466 (source (:pointer g-source))
467 (fd (:pointer g-poll-fd)))
469 (defcfun (g-source-get-current-time "g_source_get_current_time" :library glib) :void
470 (source (:pointer g-source))
471 (timeval-ret (:pointer g-time-val)))
473 (defcfun (g-source-remove "g_source_remove" :library glib) :boolean
476 (defcfun (g-source-remove-by-funcs-user-data "g_source_remove_by_funcs_user_data" :library glib) :boolean
477 (funcs (:pointer g-source-funcs))
480 (defcfun (g-source-remove-by-user-data "g_source_remove_by_user_data" :library glib) :boolean
484 ;; Core Application Support - Threads
487 (defcenum g-thread-error
488 :g-thread-error-again)
490 ;omitted: struct GThreadFunctions
492 (defcfun (g-thread-init "g_thread_init") :void
495 (defcfun g-thread-get-initialized :boolean)
498 (unless (g-thread-get-initialized)
499 (g-thread-init (null-pointer))))
501 (defcenum g-thread-priority
502 :g-thread-priority-low
503 :g-thread-priority-normal
504 :g-thread-priority-hight
505 :g-thread-priority-urgent)
507 ;omitted: g_thread_create, g_thread_create_full, g_thread_yield, g_thread_exit, g_thread_foreach
509 (defcfun (g-thread-self "g_thread_self" :library glib) (:pointer g-thread))
511 (defcfun (g-thread-join "g_thread_join" :library glib) :pointer
512 (thread (:pointer g-thread)))
514 (defcfun (g-thread-priority "g_thread_set_priority" :library glib) :void
515 (thread (:pointer g-thread))
516 (priority g-thread-priority))
518 ;;;; TODO: Commented g_mutex_*, g_cond* because they are not functions, but called through dispatch table
520 ;; (defcfun (g-mutex-new "g_mutex_new" :library glib) (:pointer g-mutex))
522 ;; (defcfun (g-mutex-lock "g_mutex_lock" :library glib) :void
523 ;; (mutex (:pointer g-mutex)))
525 ;; (defcfun (g-mutex-try-lock "g_mutex_trylock" :library glib) :boolean
526 ;; (mutex (:pointer g-mutex)))
528 ;; (defcfun (g-mutex-free "g_mutex_free" :library glib) :void
529 ;; (mutex (:pointer g-mutex)))
531 ;omitted: GStaticMutex, GStaticRWLock stuff
533 ;; (defcfun (g-cond-new "g_cond_new" :library glib) (:pointer g-cond))
535 ;; (defcfun (g-cond-signal "g_cond_signal" :library glib) :void
536 ;; (cond (:pointer g-cond)))
538 ;; (defcfun (g-cond-broadcast "g_cond_broadcast" :library glib) :void
539 ;; (cond (:pointer g-cond)))
541 ;; (defcfun (g-cond-wait "g_cond_wait" :library glib) :void
542 ;; (cond (:pointer g-cond))
543 ;; (mutex (:pointer g-mutex)))
545 ;; (defcfun (g-cond-timed-wait "g_cond_timed_wait" :library glib) :boolean
546 ;; (cond (:pointer g-cond))
547 ;; (mutex (:pointer g-mutex))
548 ;; (abs-time (:pointer g-time-val)))
550 ;; (defcfun (g-cond-free "g_cond_free" :library glib) :void
551 ;; (cond (:pointer g-cond)))
553 ;omitted: GPrivate, GOnce stuff
555 ;omitted: Thread pools, Asynchronous queues, Dynamic Loading of Modules,
556 ; Memory Allocation, IO Channels, Error Reporting, Message Output and Debugging Functions, Message Logging
558 (defcfun g-free :void
559 "@arg[ptr]{pointer previously obtained with @fun{g-malloc} or with g_malloc C function}
560 Frees the pointer by calling g_free on it."
563 (defcfun (g-malloc "g_malloc0") :pointer
564 "@arg[n-bytes]{an integer}
565 @return{pointer to beginning of allocated memory}
566 Allocates the specified number of bytes in memory. Calls g_malloc.
570 (defcfun g-strdup :pointer
571 "@arg[str]{a @class{string}}
572 @return{foreign pointer to new string}
573 Allocates a new string that is equal to @code{str}. Use @fun{g-free} to free it."
574 (str (:string :free-to-foreign t)))
576 ;omitted all GLib Utilites
578 (defbitfield g-spawn-flags
579 :leave-descriptors-open :do-not-reap-child :search-path :stdout-to-dev-null :stderr-to-dev-null
580 :child-inherits-stdin :file-and-argv-zero)
582 ;TODO: omitted Date and Time Functions