1 (defpackage :doc-skeleton
2 (:use :cl :gtk :gdk :gobject :iter :c2mop :glib)
3 (:export :widget-skeleton
4 :widgets-chapter-skeleton
11 :enum-chapter-skeleton
12 :flags-chapter-skeleton
15 #:struct-chapter-skeleton
16 #:interface-chapter-skeleton
23 (in-package :doc-skeleton)
25 (defun widgets-chapter-skeleton (output widgets &key (use-refs t) (section "section"))
27 ((or (pathnamep output)
29 (with-open-file (stream output :direction :output :if-exists :supersede)
30 (widgets-chapter-skeleton stream widgets :use-refs use-refs :section section)))
31 ((null output) (with-output-to-string (stream)
32 (widgets-chapter-skeleton stream widgets :use-refs use-refs :section section)))
33 ((or (eq t output) (streamp output))
34 (format output "@menu~%")
35 (iter (for w in widgets)
36 (format output "* ~A::~%" (string-downcase (symbol-name w))))
37 (format output "@end menu~%~%")
38 (iter (for w in widgets)
39 (write-string (widget-skeleton w :section section :use-refs use-refs) output)
40 (format output "~%~%")))))
42 (defparameter *gtk-widgets* '(about-dialog accel-label alignment arrow
43 aspect-frame assistant bin box button button-box calendar cell-view
44 check-button check-menu-item color-button color-selection
45 color-selection-dialog combo-box combo-box-entry container curve
46 dialog drawing-area entry event-box expander file-chooser-button
47 file-chooser-dialog file-chooser-widget fixed font-button
48 font-selection font-selection-dialog frame gamma-curve gtk-window
49 h-box h-button-box h-paned h-ruler h-s-v h-scale h-scrollbar
50 h-separator handle-box icon-view image image-menu-item input-dialog
51 invisible item label layout link-button menu menu-bar menu-item
52 menu-shell menu-tool-button message-dialog misc notebook
53 old-editable paned plug progress progress-bar radio-button
54 radio-menu-item radio-tool-button range recent-chooser-dialog
55 recent-chooser-menu recent-chooser-widget ruler scale scale-button
56 scrollbar scrolled-window separator separator-menu-item
57 separator-tool-item socket spin-button statusbar table
58 tearoff-menu-item text text-view toggle-button toggle-tool-button
59 tool-button tool-item toolbar tree tree-item tree-view v-box
60 v-button-box v-paned v-ruler v-scale v-scrollbar v-separator
61 viewport volume-button widget))
63 (defun all-gtk-widgets ()
64 (all-widgets (find-package :gtk)))
66 (defun all-widgets (package)
67 (sort (iter (for symbol in-package (find-package package) :external-only t)
68 (for class = (find-class symbol nil))
69 (when (and class (subclassp class (find-class 'gtk:widget)))
73 (defun all-classes (package)
74 (sort (iter (for symbol in-package (find-package package) :external-only t)
75 (for class = (find-class symbol nil))
77 (not (subclassp class (find-class 'condition)))
78 (not (subclassp class (find-class 'gtk:widget)))
79 (or (not (typep class 'gobject::gobject-class))
80 (not (gobject::gobject-class-interface-p class)))
81 (not (typep class 'structure-class)))
85 ;; (widget-skeleton widget &key (sectioning-command "section"))
86 ;; returns the texinfo string for widget (a symbol or class)
90 ;; @$SECTIONING-COMMAND $WIDGET
94 ;; Superclass: $(direct-superclass WIDGET)
96 ;; Interfaces: $(direct-interface widget)
101 ;; @item @anchor{slot.$widget.$slot}$slot. Type: $(slot-type slot). Accessor: $(slot-accessor slot). $(when (constructor-only slot) "Contructor-only slot.")
107 ;; $(for each signal)
108 ;; @item @anchor{signal.$widget.$signal}"$signal". Signature: Type1 Arg1, .., Typen Argn => return-type. Options: $(signal-options)
112 (defvar *use-refs* t)
114 (defun widget-skeleton (widget &key (section "section") (use-refs t))
115 (unless (typep widget 'class) (setf widget (find-class widget)))
116 (with-output-to-string (stream)
117 (let ((*print-case* :downcase)
118 (*package* (symbol-package (class-name widget)))
120 (*use-refs* use-refs))
121 (format stream "@node ~A~%" (class-name widget))
122 (format stream "@~A ~A~%" section (class-name widget))
123 (format stream "@Class ~A~%" (class-name widget))
124 (format stream "Superclass:")
125 (iter (for super in (class-direct-superclasses widget))
126 (unless (and (typep super 'gobject-class) (gobject::gobject-class-interface-p super))
127 (format stream " ~A" (format-ref (class-name super)))))
128 (when (class-direct-subclasses widget)
129 (format stream "~%~%")
130 (format stream "Subclasses:")
131 (iter (for sub in (class-direct-subclasses widget))
132 (format stream " ~A" (format-ref (class-name sub)))))
133 (format stream "~%~%")
134 (widget-slots stream widget)
135 (format stream "~%~%")
136 (widget-signals stream widget)
137 (format stream "~%~%")
138 (widget-child-properties stream widget))))
140 (defun widget-slots (stream widget)
141 (format stream "Slots:~%")
142 (format stream "@itemize~%")
143 (iter (for slot in (class-direct-slots widget))
144 (when (typep slot 'gobject::gobject-direct-slot-definition)
145 (format stream "@item @anchor{slot.~A.~A}~A. Type: ~A. Accessor: ~A."
146 (class-name widget) (slot-definition-name slot)
147 (slot-definition-name slot)
149 (slot-accessor slot))
150 (case (classify-slot-readability widget slot)
151 (:write-only (format stream " Write-only."))
152 (:read-only (format stream " Read-only.")))
153 (format stream "~%")))
154 (format stream "@end itemize~%"))
156 (defun widget-signals (stream widget)
157 (when (typep widget 'gobject::gobject-class)
158 (let ((g-type (gobject::gobject-class-direct-g-type-name widget)))
160 (format stream "Signals:~%")
161 (format stream "@itemize~%")
162 ;; @item @anchor{signal.$widget.$signal}"$signal". Signature: Type1 Arg1, .., Typen Argn => return-type. Options: $(signal-options)
163 (iter (for signal in (type-signals g-type))
164 (format stream "@item @anchor{signal.~A.~A}\"~A\". Signature: ~A. Options: ~A."
166 (signal-info-name signal)
167 (signal-info-name signal)
168 (signal-signature signal)
169 (signal-options signal))
170 (format stream "~%"))
171 (format stream "@end itemize~%")))))
173 (defun widget-child-properties (stream widget)
174 (when (typep stream 'gobject::gobject-class)
175 (let ((g-type (gobject::gobject-class-g-type-name widget)))
176 (when (g-type-is-a g-type "GtkContainer")
177 (unless (string= g-type (gobject::gobject-class-g-type-name (first (class-direct-superclasses widget))))
178 (let ((props (gtk::container-class-child-properties g-type)))
180 (format stream "Child properties:~%")
181 (format stream "@itemize~%")
182 ;; @item @anchor{signal.$widget.$signal}"$signal". Signature: Type1 Arg1, .., Typen Argn => return-type. Options: $(signal-options)
183 (iter (for prop in props)
184 (for accessor = (format nil "~A-child-~A"
185 (string-downcase (symbol-name (class-name widget)))
186 (g-class-property-definition-name prop)))
187 (format stream "@item @anchor{childprop.~A.~A}~A. Type: ~A. Accessor: ~A."
188 (string-downcase (symbol-name (class-name widget)))
189 (g-class-property-definition-name prop)
190 (g-class-property-definition-name prop)
191 (type-string (g-class-property-definition-type prop))
193 (format stream "~%"))
194 (format stream "@end itemize~%"))))))))
196 (defun signal-signature (s)
197 (with-output-to-string (stream)
198 (format stream "(instance ~A)" (type-string (signal-info-owner-type s)))
199 (iter (for type in (signal-info-param-types s))
201 (format stream ", (arg-~A ~A)" counter (type-string type)))
202 (format stream " @result{} ~A" (type-string (signal-info-return-type s)))))
204 (defun signal-options (s)
205 (format nil "~{~A~^, ~}"(signal-info-flags s)))
207 (defun slot-type (slot)
208 (let ((type (gobject::gobject-direct-slot-definition-g-property-type slot)))
211 (defun type-string (type)
213 (string (type-string-s type))
214 (t (type-string-f type))))
216 (defun ensure-list (x) (if (listp x) x (list x)))
218 (defun type-string-f (type)
219 (let ((l (ensure-list type)))
221 ((:string glib:g-string) "@code{string}")
222 ((:int :uint :long :ulong :char :uchar :int64 :uint64) "@code{integer}")
223 ((:boolean :bool) "@code{boolean}")
224 (g-object (if (second l)
225 (format-ref (second l))
227 (g-boxed-foreign (format-ref (second l)))
229 ((glist gslist) (format nil "list of ~A" (type-string-f (second l))))
230 (t (if (symbolp type)
234 (defun type-string-s (type)
236 ((g-type= type +g-type-string+) "@code{string}")
237 ((g-type= type +g-type-boolean+) "@code{boolean}")
238 ((g-type= type +g-type-float+) "@code{single-float}")
239 ((g-type= type +g-type-double+) "@code{double-float}")
240 ((or (g-type= type +g-type-int+)
241 (g-type= type +g-type-uint+)
242 (g-type= type +g-type-char+)
243 (g-type= type +g-type-uchar+)
244 (g-type= type +g-type-long+)
245 (g-type= type +g-type-ulong+)
246 (g-type= type +g-type-int64+)
247 (g-type= type +g-type-uint64+)
248 (g-type= type +g-type-uint64+)) "@code{integer}")
249 ((g-type= type +g-type-float+) "@code{single-float}")
250 ((g-type-is-a type +g-type-enum+) (enum-string type))
251 ((g-type-is-a type +g-type-flags+) (flags-string type))
252 ((g-type-is-a type +g-type-object+) (object-string type))
253 ((g-type-is-a type +g-type-boxed+) (boxed-string type))
256 (defun format-ref (s)
257 (if (and *use-refs* (if (symbolp s)
258 (not (eq (symbol-package s) (find-package :cl)))
260 (format nil "@ref{~A}" s)
261 (format nil "@code{~A}" s)))
263 (defun flags-string (type)
264 (let ((flags (gobject::registered-flags-type (g-type-string type))))
267 (format nil "@code{~A}" (g-type-string type)))))
269 (defun enum-string (type)
270 (let ((enum (gobject::registered-enum-type (g-type-string type))))
273 (format nil "@code{~A}" (g-type-string type)))))
275 (defun object-string (type)
276 (let ((class (gobject::registered-object-type-by-name (g-type-string type))))
279 (format nil "@code{~A}" (g-type-string type)))))
281 (defun boxed-string (type)
282 (let ((boxed (ignore-errors (gobject::get-g-boxed-foreign-info-for-gtype (g-type-string type)))))
284 (format-ref (gobject::g-boxed-info-name boxed))
285 (format nil "@code{~A}" (g-type-string type)))))
287 (defmethod classify-slot-readability (class (slot gobject::gobject-property-direct-slot-definition))
288 (let* ((g-type (gobject::gobject-class-g-type-name class))
289 (property-name (gobject::gobject-property-direct-slot-definition-g-property-name slot))
290 (prop (if (g-type-is-a g-type +g-type-interface+)
291 (find property-name (interface-properties g-type)
293 :key #'g-class-property-definition-name)
294 (class-property-info g-type property-name)))
295 (readable (g-class-property-definition-readable prop))
296 (writable (g-class-property-definition-writable prop)))
298 ((and readable writable) :normal)
299 ((not readable) :write-only)
300 ((not writable) :read-only)
303 (defmethod classify-slot-readability (class (slot gobject::gobject-fn-direct-slot-definition))
304 (let ((readable (gobject::gobject-fn-direct-slot-definition-g-getter-name slot))
305 (writable (gobject::gobject-fn-direct-slot-definition-g-setter-name slot)))
307 ((and readable writable) :normal)
308 ((not readable) :write-only)
309 ((not writable) :read-only)
312 (defun slot-accessor (slot)
313 (let* ((readers (slot-definition-readers slot))
314 (writers (mapcar #'second (slot-definition-writers slot)))
315 (combined (union readers writers))
316 (accessor (first combined)))
318 (format nil "@anchor{fn.~A}@code{~A}" accessor accessor)
319 (format nil "None"))))
322 ;; (enum-skeleton enum &key (section "section"))
327 ;; $(enum-values enum)
330 (defun enum-skeleton (enum &key (section "section"))
331 (with-output-to-string (stream)
332 (format stream "@node ~A~%" (string-downcase enum))
333 (format stream "@~A ~A~%" section (string-downcase enum))
334 (format stream "@Enum ~A~%" (string-downcase enum))
335 (format stream "Values: ~%")
336 (format stream "@itemize~%")
337 (iter (for item in (cffi:foreign-enum-keyword-list enum))
338 (format stream "@item :~A~%" (string-downcase (symbol-name item))))
339 (format stream "@end itemize~%")))
341 (defun flags-skeleton (flags &key (section "section"))
342 (with-output-to-string (stream)
343 (format stream "@node ~A~%" (string-downcase flags))
344 (format stream "@~A ~A~%" section (string-downcase flags))
345 (format stream "@Flags ~A~%" (string-downcase flags))
346 (format stream "Values: ~%")
347 (format stream "@itemize~%")
348 (iter (for item in (cffi:foreign-bitfield-symbol-list flags))
349 (format stream "@item :~A~%" (string-downcase (symbol-name item))))
350 (format stream "@end itemize~%")))
352 (defun all-enums (package)
353 (sort (iter (for symbol in-package package :external-only t)
354 (when (ignore-errors (cffi:foreign-enum-keyword-list symbol))
358 (defun all-flags (package)
359 (sort (iter (for symbol in-package package :external-only t)
360 (when (ignore-errors (cffi:foreign-bitfield-symbol-list symbol))
364 (defun enum-chapter-skeleton (output enums &key (section "section"))
366 ((or (pathnamep output) (stringp output))
367 (with-open-file (stream output :direction :output :if-exists :supersede)
368 (enum-chapter-skeleton stream enums :section section)))
369 ((null output) (with-output-to-string (stream)
370 (enum-chapter-skeleton stream enums :section section)))
371 ((or (eq t output) (streamp output))
372 (format output "@menu~%")
373 (iter (for e in enums)
374 (format output "* ~A::~%" (string-downcase (symbol-name e))))
375 (format output "@end menu~%~%")
376 (iter (for e in enums)
377 (write-string (enum-skeleton e :section section) output)
378 (format output "~%~%")))))
380 (defun flags-chapter-skeleton (output flagss &key (section "section"))
382 ((or (pathnamep output) (stringp output))
383 (with-open-file (stream output :direction :output :if-exists :supersede)
384 (flags-chapter-skeleton stream flagss :section section)))
385 ((null output) (with-output-to-string (stream)
386 (flags-chapter-skeleton stream flagss :section section)))
387 ((or (eq t output) (streamp output))
388 (format output "@menu~%")
389 (iter (for e in flagss)
390 (format output "* ~A::~%" (string-downcase (symbol-name e))))
391 (format output "@end menu~%~%")
392 (iter (for e in flagss)
393 (write-string (flags-skeleton e :section section) output)
394 (format output "~%~%")))))
397 ;; (struct-skeleton struct &key (section "section") (use-refs t))
408 (defun struct-skeleton (struct &key (section "section") (use-refs t))
409 (unless (typep struct 'class) (setf struct (find-class struct)))
410 (with-output-to-string (stream)
411 (let ((*print-case* :downcase)
412 (*package* (symbol-package (class-name struct)))
414 (*use-refs* use-refs))
415 (format stream "@node ~A~%" (class-name struct))
416 (format stream "@~A ~A~%" section (class-name struct))
417 (format stream "@Struct ~A~%" (class-name struct))
418 (format stream "Superclass:")
419 (iter (for super in (class-direct-superclasses struct))
420 (format stream " ~A" (format-ref (class-name super))))
421 (when (class-direct-subclasses struct)
422 (format stream "~%~%")
423 (format stream "Subclasses:")
424 (iter (for sub in (class-direct-subclasses struct))
425 (format stream " ~A" (format-ref (class-name sub)))))
426 (format stream "~%~%")
427 (struct-slots stream struct))))
429 (defun struct-slots (stream struct)
430 (format stream "Slots:~%")
431 (format stream "@itemize~%")
432 (iter (for slot in (class-direct-slots struct))
433 (format stream "@item @anchor{slot.~A.~A}~A. Accessor: ~A."
434 (class-name struct) (string-downcase (slot-definition-name slot))
435 (string-downcase (slot-definition-name slot))
436 (format nil "~A-~A" (class-name struct) (slot-definition-name slot)))
437 (format stream "~%"))
438 (format stream "@end itemize~%"))
440 (defun all-structs (package)
441 (sort (iter (for symbol in-package package :external-only t)
442 (for class = (find-class symbol nil))
443 (when (and class (typep class (find-class 'structure-class)))
447 (defun struct-chapter-skeleton (output structs &key (section "section") (use-refs t))
449 ((or (stringp output) (pathnamep output))
450 (with-open-file (stream output :direction :output :if-exists :supersede)
451 (struct-chapter-skeleton stream structs :section section :use-refs use-refs)))
452 ((null output) (with-output-to-string (stream)
453 (struct-chapter-skeleton stream structs :section section :use-refs use-refs)))
454 ((or (eq t output) (streamp output))
455 (format output "@menu~%")
456 (iter (for e in structs)
457 (format output "* ~A::~%" (string-downcase (symbol-name e))))
458 (format output "@end menu~%~%")
459 (iter (for e in structs)
460 (write-string (struct-skeleton e :section section :use-refs use-refs) output)
461 (format output "~%~%")))))
463 (defun interface-chapter-skeleton (output interfaces &key (use-refs t) (section "section"))
465 ((or (stringp output) (pathnamep output))
466 (with-open-file (stream output :direction :output :if-exists :supersede)
467 (interface-chapter-skeleton stream interfaces :use-refs use-refs :section section)))
468 ((null output) (with-output-to-string (stream)
469 (interface-chapter-skeleton stream interfaces :use-refs use-refs :section section)))
470 ((or (eq t output) (streamp output))
471 (format output "@menu~%")
472 (iter (for w in interfaces)
473 (format output "* ~A::~%" (string-downcase (symbol-name w))))
474 (format output "@end menu~%~%")
475 (iter (for w in interfaces)
476 (write-string (interface-skeleton w :section section :use-refs use-refs) output)
477 (format output "~%~%")))))
479 (defun all-interfaces (package)
480 (sort (iter (for symbol in-package package :external-only t)
481 (for class = (find-class symbol nil))
483 (typep class 'gobject:gobject-class)
484 (gobject::gobject-class-interface-p class))
488 ;; (interface-skeleton interface &key (sectioning-command "section"))
489 ;; returns the texinfo string for interface (a symbol or class)
493 ;; @$SECTIONING-COMMAND $INTERFACE
497 ;; Interfaces: $(direct-interface interface)
502 ;; @item @anchor{slot.$interface.$slot}$slot. Type: $(slot-type slot). Accessor: $(slot-accessor slot). $(when (constructor-only slot) "Contructor-only slot.")
508 ;; $(for each signal)
509 ;; @item @anchor{signal.$interface.$signal}"$signal". Signature: Type1 Arg1, .., Typen Argn => return-type. Options: $(signal-options)
513 (defun interface-skeleton (interface &key (section "section") (use-refs t))
514 (unless (typep interface 'class) (setf interface (find-class interface)))
515 (with-output-to-string (stream)
516 (let ((*print-case* :downcase)
517 (*package* (symbol-package (class-name interface)))
519 (*use-refs* use-refs))
520 (format stream "@node ~A~%" (class-name interface))
521 (format stream "@~A ~A~%" section (class-name interface))
522 (format stream "@Class ~A~%" (class-name interface))
523 (format stream "~%~%")
524 (widget-slots stream interface)
525 (format stream "~%~%")
526 (widget-signals stream interface))))
528 (defun all-gtk-skeletons (dir)
529 (widgets-chapter-skeleton (merge-pathnames "gdk.objects.texi" dir) (all-classes (find-package :gdk)))
530 (widgets-chapter-skeleton (merge-pathnames "gtk.objects.texi" dir) (all-classes (find-package :gtk)))
531 (struct-chapter-skeleton (merge-pathnames "gtk.structs.texi" dir) (all-structs (find-package :gtk)))
532 (struct-chapter-skeleton (merge-pathnames "gdk.structs.texi" dir) (all-structs (find-package :gdk)))
533 (widgets-chapter-skeleton (merge-pathnames "gtk.widgets.texi" dir) (all-widgets (find-package :gtk)))
534 (interface-chapter-skeleton (merge-pathnames "gtk.interfaces.texi" dir) (all-interfaces (find-package :gtk)))
535 (enum-chapter-skeleton (merge-pathnames "gtk.enums.texi" dir) (all-enums :gtk))
536 (enum-chapter-skeleton (merge-pathnames "gdk.enums.texi" dir) (all-enums :gdk))
537 (flags-chapter-skeleton (merge-pathnames "gtk.flags.texi" dir) (all-flags :gtk))
538 (flags-chapter-skeleton (merge-pathnames "gdk.flags.texi" dir) (all-flags :gdk)))