;; Common Lisp bindings for GTK+ 2.x ;; Copyright 2008 Espen S. Johnsen ;; ;; Permission is hereby granted, free of charge, to any person obtaining ;; a copy of this software and associated documentation files (the ;; "Software"), to deal in the Software without restriction, including ;; without limitation the rights to use, copy, modify, merge, publish, ;; distribute, sublicense, and/or sell copies of the Software, and to ;; permit persons to whom the Software is furnished to do so, subject to ;; the following conditions: ;; ;; The above copyright notice and this permission notice shall be ;; included in all copies or substantial portions of the Software. ;; ;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ;; $Id: streams.lisp,v 1.1 2008-12-10 02:58:13 espen Exp $ (in-package "GIO") (use-prefix "g") ;;; Input streams (defbinding input-stream-read (stream buffer &key length cancellable) gssize (stream input-stream) (buffer pointer) (length gsize) (cancellable (or null cancellable)) (nil gerror-signal :out)) (defbinding input-stream-read-all (stream buffer &key length cancellable) boolean (stream input-stream) (buffer pointer) (length gsize) (bytes-read gsize :out) (cancellable (or null cancellable)) (nil gerror-signal :out)) (defbinding input-stream-skip (stream length &key cancellable) gssize (stream input-stream) (length gsize) (cancellable (or null cancellable)) (nil gerror-signal :out)) (defbinding input-stream-close (stream &key cancellable) boolean (stream input-stream) (cancellable (or null cancellable)) (nil gerror-signal :out)) ;;; Output streams (defbinding output-stream-write (stream buffer &key length cancellable) gssize (stream output-stream) (buffer (or (unboxed-vector (unsigned-byte 8)) pointer)) ((or length (length buffer)) gsize) (cancellable (or null cancellable)) (nil gerror-signal :out)) (defbinding output-stream-write-all (stream buffer &key length cancellable) boolean (stream output-stream) (buffer (or (unboxed-vector (unsigned-byte 8)) pointer)) ((or length (length buffer)) gsize) (bytes-written gsize :out) (cancellable (or null cancellable)) (nil gerror-signal :out)) (defbinding output-stream-flush (stream &key cancellable) boolean (stream output-stream) (cancellable (or null cancellable)) (nil gerror-signal :out)) (defbinding output-stream-close (stream &key cancellable) boolean (stream output-stream) (cancellable (or null cancellable)) (nil gerror-signal :out)) ;;; Unix streams (defbinding %unix-input-stream-new () pointer (fd int) (close-fd-p boolean)) (defmethod allocate-foreign ((stream unix-input-stream) &key fd close-fd) (%unix-input-stream-new fd close-fd)) (defbinding %unix-output-stream-new () pointer (fd int) (close-fd-p boolean)) (defmethod allocate-foreign ((stream unix-output-stream) &key fd close-fd) (%unix-output-stream-new fd close-fd)) ;;; Callback streams (clg extension) (define-callback callback-stream-read-func gssize ((buffer pointer) (count gsize) (cancellable (or null cancellable)) (gerror pointer) (stream-id pointer-data)) (declare (ignore cancellable)) (handler-case (let* ((sequence (make-array count :element-type '(unsigned-byte 8))) (stream (find-user-data stream-id)) (bytes-read (read-sequence sequence stream))) (unless (null-pointer-p buffer) (make-c-vector '(unsigned-byte 8) bytes-read :content sequence :location buffer)) bytes-read) (serious-condition (condition) (gerror-set-in-callback gerror (file-error-domain) (enum-int :failed 'file-error-enum) (princ-to-string condition)) -1))) (define-callback callback-stream-write-func gssize ((buffer pointer) (count gsize) (cancellable (or null cancellable)) (gerror pointer) (stream-id pointer-data)) (declare (ignore cancellable)) (handler-case (let ((stream (find-user-data stream-id))) (write-sequence (map-c-vector 'vector 'identity buffer '(unsigned-byte 8) count) stream)) (serious-condition (condition) (gerror-set-in-callback gerror (file-error-domain) (enum-int :failed 'file-error-enum) (princ-to-string condition)) -1))) (define-callback callback-stream-flush-func boolean ((cancellable (or null cancellable)) (gerror pointer) (stream-id pointer-data)) (declare (ignore cancellable)) (handler-case (force-output (find-user-data stream-id)) (serious-condition (condition) (gerror-set-in-callback gerror (file-error-domain) (enum-int :failed 'file-error-enum) (princ-to-string condition)) -1))) (define-callback callback-stream-close-func boolean ((cancellable (or null cancellable)) gerror (stream-id pointer-data)) (declare (ignore cancellable gerror)) (destroy-user-data stream-id)) (defbinding %callback-input-stream-new (stream-id) pointer (callback-stream-read-func callback) (callback-stream-close-func callback) (stream-id pointer-data)) (defbinding %callback-output-stream-new (stream-id) pointer (callback-stream-read-func callback) (callback-stream-flush-func callback) (callback-stream-close-func callback) (stream-id pointer-data)) (defmethod allocate-foreign ((stream callback-input-stream) &key base-stream) (%callback-input-stream-new (register-user-data base-stream))) (defmethod allocate-foreign ((stream callback-output-stream) &key base-stream) (%callback-input-stream-new (register-user-data base-stream))) ;;; Lisp integration (deftype input-stream-designator () '(or stream input-stream integer)) (deftype output-stream-designator () '(or stream input-stream integer)) (define-type-method alien-type ((type input-stream-designator)) (declare (ignore type)) (alien-type 'input-stream)) (define-type-method alien-arg-wrapper ((type input-stream-designator) var stream style form &optional copy-in-p) (declare (ignore type)) (let ((%stream (make-symbol "STREAM"))) `(let ((,%stream (etypecase ,stream (input-stream ,stream) (integer (make-instance 'unix-input-stream :fd ,stream)) (stream (make-instance 'callback-input-stream :base-stream ,stream))))) (unwind-protect ,(alien-arg-wrapper 'input-stream var %stream style form copy-in-p) (unless (typep ,stream 'input-stream) (input-stream-close ,%stream)))))) (define-type-method alien-type ((type output-stream-designator)) (declare (ignore type)) (alien-type 'output-stream)) (define-type-method alien-arg-wrapper ((type output-stream-designator) var stream style form &optional copy-in-p) (declare (ignore type)) (let ((%stream (make-symbol "STREAM"))) `(let ((,%stream (etypecase ,stream (output-stream ,stream) (integer (make-instance 'unix-output-stream :fd ,stream)) (stream (make-instance 'callback-output-stream :base-stream ,stream))))) (unwind-protect ,(alien-arg-wrapper 'input-stream var %stream style form copy-in-p) (unless (typep ,stream 'output-stream) (output-stream-close ,%stream)))))) ;; TODO: make GIO streams appear as Lisp streams