Correctly sort out string-specified getters in virtual-slots.lisp
[clg] / gdk / pixbuf.lisp
index f0598ef..910e1cd 100644 (file)
 ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
-;; $Id: pixbuf.lisp,v 1.5 2006-06-07 13:18:20 espen Exp $
+;; $Id: pixbuf.lisp,v 1.9 2008-12-10 03:01:34 espen Exp $
 
 
 (in-package "GDK")
 
 
 
 (in-package "GDK")
 
-(defbinding pixbuf-get-option () (copy-of string)
-  (pixbuf pixbuf)
-  (key string))
+(defbinding %pixbuf-new () pointer
+  colorspace 
+  (has-alpha boolean)
+  (bits-per-sample int)
+  (width int)
+  (height int))
 
 
-(defbinding %pixbuf-new-from-file () (referenced pixbuf)
+(defbinding %pixbuf-new-from-data () pointer
+  (data pointer)
+  colorspace       
+  (has-alpha boolean)
+  (bits-per-sample int)
+  (width int)
+  (height int)
+  (rowstride int)
+  (nil null)
+  (nil null))
+
+(defbinding %pixbuf-new-from-xpm-data () pointer
+  (data (vector string)))
+
+(defbinding %pixbuf-new-from-file () pointer
   (filename pathname)
   (filename pathname)
-  (nil gerror :out))
+  (nil (or null gerror) :out))
 
 
-(defbinding %pixbuf-new-from-file-at-size () (referenced pixbuf)
+(defbinding %pixbuf-new-from-file-at-size () pointer
   (filename pathname)
   (width int)
   (height int)
   (filename pathname)
   (width int)
   (height int)
-  (nil gerror :out))
+  (nil (or null gerror) :out))
 
 #?(pkg-exists-p "gtk+-2.0" :atleast-version "2.6.0")
 
 #?(pkg-exists-p "gtk+-2.0" :atleast-version "2.6.0")
-(defbinding %pixbuf-new-from-file-at-scale () (referenced pixbuf)
+(defbinding %pixbuf-new-from-file-at-scale () pointer
   (filename pathname)
   (width int)
   (height int)
   (preserve-aspect-ratio boolean)
   (filename pathname)
   (width int)
   (height int)
   (preserve-aspect-ratio boolean)
-  (nil gerror :out))
+  (nil (or null gerror) :out))
 
 
-(defun pixbuf-load (filename &key width height size (preserve-aspect-ratio t))
-  #?-(pkg-exists-p "gtk+-2.0" :atleast-version "2.6.0")
-  (unless preserve-aspect-ratio 
-    (warn ":preserve-aspect-ratio not supported with this version of Gtk"))
-
-  (multiple-value-bind (pixbuf gerror)
+(defun %pixbuf-load (filename width height preserve-aspect-p)
+  (multiple-value-bind (location gerror)
       (cond
       (cond
-       (size 
-       #?-(pkg-exists-p "gtk+-2.0" :atleast-version "2.6.0")
-       (%pixbuf-new-from-file-at-size filename size size)
-       #?(pkg-exists-p "gtk+-2.0" :atleast-version "2.6.0")
-       (%pixbuf-new-from-file-at-scale filename size size preserve-aspect-ratio))
-       ((and width height)
-       #?-(pkg-exists-p "gtk+-2.0" :atleast-version "2.6.0")
-       (%pixbuf-new-from-file-at-size filename width height)
-       #?(pkg-exists-p "gtk+-2.0" :atleast-version "2.6.0")
-       (%pixbuf-new-from-file-at-scale filename width height preserve-aspect-ratio))
-       ((or width height)
-       (error "Both :width and :height must be specified"))
-       (t (%pixbuf-new-from-file filename)))
+       ((and width height)
+        (%pixbuf-new-from-file-at-size filename width height))
+       ((or width height)
+        #?-(pkg-exists-p "gtk+-2.0" :atleast-version "2.6.0")
+        (error "Both :width and :height must be specified")
+        #?(pkg-exists-p "gtk+-2.0" :atleast-version "2.6.0")
+        (%pixbuf-new-from-file-at-scale filename 
+         (or width -1) (or height -1) preserve-aspect-p))
+       (t (%pixbuf-new-from-file filename)))
     (if gerror
        (signal-gerror gerror)
     (if gerror
        (signal-gerror gerror)
-      pixbuf)))
+      location)))
+
+#?(pkg-exists-p "gtk+-2.0" :atleast-version "2.14.0")
+(progn
+  (defbinding %pixbuf-new-from-stream () pointer
+    gio:input-stream-designator
+    (nil (or null gio:cancellable))
+    (nil (or null gerror) :out))
+
+  (defbinding %pixbuf-new-from-stream-at-scale () pointer
+    gio:input-stream-designator
+    (width int)
+    (height int)
+    (preserve-aspect-ratio boolean)
+    (nil (or null gio:cancellable))
+    (nil (or null gerror) :out))
+
+  (defun %load-from-stream (stream width height preserve-aspect-p)
+    (multiple-value-bind (location gerror)
+       (cond
+         ((or width height)
+          (%pixbuf-new-from-stream-at-scale stream
+           (or width -1) (or height -1) preserve-aspect-p))
+         (t (%pixbuf-new-from-stream stream)))
+      (if gerror
+         (signal-gerror gerror)
+       location))))
+
+(defmethod allocate-foreign ((pixbuf pixbuf) &key source (bits-per-sample 8)
+                            (colorspace :rgb) (has-alpha t) width height 
+                            (preserve-aspect-ratio t) destroy stride)
+  (cond
+   ((not source) 
+    (%pixbuf-new colorspace has-alpha bits-per-sample width height))
+   ((typep source 'pointer)
+    ;; TODO: destory
+    (%pixbuf-new-from-data source colorspace has-alpha bits-per-sample width height (or stride (* width (if has-alpha 4 3)))))
+   ((and (vectorp source) (stringp (aref source 0)))
+    (%pixbuf-new-from-xpm-data source))
+   ((typep source 'vector)
+
+    )
+   ((or (pathnamep source) (stringp source))
+    #?-(pkg-exists-p "gtk+-2.0" :atleast-version "2.6.0")
+    (unless preserve-aspect-ratio 
+      (warn ":preserve-aspect-ratio not supported with this version of Gtk"))
+    (%pixbuf-load source width height preserve-aspect-ratio))
+   #?(pkg-exists-p "gtk+-2.0" :atleast-version "2.14.0")
+   ((typep source 'gio:input-stream-designator)
+    (%load-from-stream source width height preserve-aspect-ratio))
+   ((call-next-method))))
+
+
+(defbinding (pixbuf-subpixbuf "gdk_pixbuf_new_subpixbuf") () 
+    (or null (referenced pixbuf))
+  pixbuf (src-x int) (src-y int) (width int) (height int))
+
+(defbinding pixbuf-copy () (or null (referenced pixbuf))
+  pixbuf)
+
+
+(defbinding pixbuf-get-option () (copy-of string)
+  (pixbuf pixbuf)
+  (key string))
+
+(defun pixbuf-load (filename &key width height size (preserve-aspect-ratio t))
+  (make-instance 'pixbuf :source filename 
+   :width (or size width) :height (or size height)
+   :preserve-aspect-ratio preserve-aspect-ratio))
 
 
 ;; (defbinding pixbuf-get-file-info () (copy-of pixbuf-format)
 
 
 ;; (defbinding pixbuf-get-file-info () (copy-of pixbuf-format)
   (filename pathname)
   (type string)
   (keys strings)
   (filename pathname)
   (type string)
   (keys strings)
-  (values string)
-  (nil gerror :out))
+  (values strings)
+  (nil (or null gerror) :out))
 
 
-(defun pixbuf-save (pixbuf filename type &rest options)
+(defun %pixbuf-save-options (options)
   (let ((keys (make-array 0 :adjustable t :fill-pointer t))
        (values (make-array 0 :adjustable t :fill-pointer t)))
     (loop 
   (let ((keys (make-array 0 :adjustable t :fill-pointer t))
        (values (make-array 0 :adjustable t :fill-pointer t)))
     (loop 
-     as (key value . rest) = options then rest
+     for (key value) on options by #'cddr
      do (vector-push-extend (string-downcase key) keys)
         (vector-push-extend 
         (etypecase value 
      do (vector-push-extend (string-downcase key) keys)
         (vector-push-extend 
         (etypecase value 
           (symbol (string-downcase value))
           (number (format nil "~A" value)))
         values))
           (symbol (string-downcase value))
           (number (format nil "~A" value)))
         values))
-    (multiple-value-bind (ok-p gerror)
-       (%pixbuf-savev pixbuf filename type keys values)
-      (unless ok-p
-       (signal-gerror gerror)))))
+    (values keys values)))
 
 
-(defbinding pixbuf-new-from-xpm-data () (referenced pixbuf)
-  (data (vector string)))
+(defgeneric pixbuf-save (pixbuf dest type &rest options))
+
+(defmethod pixbuf-save (pixbuf (filename string) type &rest options)
+  (multiple-value-bind (ok-p gerror)
+      (multiple-value-call #'%pixbuf-savev 
+       pixbuf filename (string-downcase type) 
+       (%pixbuf-save-options options))
+    (unless ok-p
+      (signal-gerror gerror))))
+
+(defmethod pixbuf-save (pixbuf (pathname pathname) type &rest options)
+  (apply #'pixbuf-save pixbuf (namestring (translate-logical-pathname pathname))
+   type options))
+
+(define-callback stream-write-func boolean 
+    ((data pointer) (length gsize) (gerror pointer) (stream-id pointer-data))
+  (block stream-write
+    (handler-case
+       (let ((stream (find-user-data stream-id)))
+         (write-sequence
+          (map-c-vector 'vector 'identity data '(unsigned-byte 8) length)
+          stream))
+      (serious-condition (condition)
+       (gerror-set-in-callback gerror (file-error-domain) 
+        (enum-int :failed 'file-error-enum) (princ-to-string condition))
+       (return-from stream-write nil)))
+    t))
+
+(defbinding %pixbuf-save-to-callbackv (pixbuf stream type keys values) boolean
+  (pixbuf pixbuf)
+  (stream-write-func callback)
+  (stream pointer-data)
+  (type string)
+  (keys strings)
+  (values strings)
+  (nil (or null gerror) :out))
+
+(defmethod pixbuf-save (pixbuf (stream stream) type &rest options)
+  (let ((stream-id (register-user-data stream)))
+    (unwind-protect
+        (multiple-value-bind (ok-p gerror)
+            (multiple-value-call #'%pixbuf-save-to-callbackv
+              pixbuf stream-id (string-downcase type) 
+              (%pixbuf-save-options options))
+          (unless ok-p
+            (signal-gerror gerror)))
+      (destroy-user-data stream-id))))
+
+
+;; (defbinding pixbuf-new-from-xpm-data () (referenced pixbuf)
+;;   (data (vector string)))
 
 (defbinding %pixbuf-new-subpixbuf () pixbuf ;; or (referenced pixbuf)?
   (pixbuf pixbuf)
 
 (defbinding %pixbuf-new-subpixbuf () pixbuf ;; or (referenced pixbuf)?
   (pixbuf pixbuf)
       (%pixbuf-copy pixbuf)
     (%pixbuf-new-subpixbuf pixbuf x y width height)))
 
       (%pixbuf-copy pixbuf)
     (%pixbuf-new-subpixbuf pixbuf x y width height)))
 
-(defbinding %pixbuf-get-from-drawable () (referenced pixbuf)
+(defbinding %pixbuf-get-from-drawable () (or null (referenced pixbuf))
   (dest (or null pixbuf))
   (drawable drawable)
   (colormap (or null colormap))
   (dest (or null pixbuf))
   (drawable drawable)
   (colormap (or null colormap))
    (error "Couldn't get pixbuf from drawable")))
 
 
    (error "Couldn't get pixbuf from drawable")))
 
 
+;;; Pixbuf Loader
+
+(defbinding %pixbuf-loader-new-with-type () pointer
+  (type string)
+  (nil gerror-signal :out))
+
+(defbinding %pixbuf-loader-new-with-mime-type () pointer
+  (mime-type string)
+  (nil gerror-signal :out))
+
+(defmethod allocate-foreign ((loader pixbuf-loader) &key type mime-type)
+  (cond
+   ((and type mime-type) 
+    (error "Only one of the keyword arguments :TYPE and :MIME-TYPE can be specified"))
+   (type (%pixbuf-loader-new-with-type type))
+   (mime-type (%pixbuf-loader-new-with-mime-type mime-type))
+   ((call-next-method))))
+
+(defbinding pixbuf-loader-write (loader buffer &optional (length (length buffer))) boolean
+  (loader pixbuf-loader)
+  (buffer (unboxed-vector (unsigned-byte 8)))
+  (length integer)  
+  (nil gerror-signal :out))
+
+(defbinding pixbuf-loader-close () boolean
+  (loader pixbuf-loader)
+  (nil gerror-signal :out))
+
+(defbinding pixbuf-loader-get-pixbuf () (or null pixbuf)
+  (loader pixbuf-loader))
+
+(defbinding pixbuf-loader-get-animation () (or null pixbuf-animation)
+  (loader pixbuf-loader))
+
+(defbinding pixbuf-loader-set-size () nil
+  (loader pixbuf-loader)
+  (width integer)
+  (height integer))
+
+
 ;;; Utilities
 
 (defbinding pixbuf-add-alpha 
 ;;; Utilities
 
 (defbinding pixbuf-add-alpha 
   (red (unsigned 8))
   (green (unsigned 8))
   (blue (unsigned 8)))
   (red (unsigned 8))
   (green (unsigned 8))
   (blue (unsigned 8)))
+
+;; The purpose of this function is to be able to share pixel data
+;; between GdkPixbufs and Cairo image surfaces.
+#+nil
+(defun pixbuf-swap-rgb (pixbuf)
+  (assert (= (pixbuf-bits-per-sample pixbuf) 8))
+  (assert (= (pixbuf-n-channels pixbuf) 4))
+  (assert (pixbuf-has-alpha-p pixbuf))
+  (let ((pixels (pixbuf-pixels pixbuf))
+       (stride (pixbuf-rowstride pixbuf))
+       (n-channels (pixbuf-n-channels pixbuf)))
+    (loop for y from 0 below (pixbuf-height pixbuf) do
+     (let ((row-offset (* y stride)))
+       (loop for x from 0 below (pixbuf-width pixbuf) do
+        (let* ((offset (+ row-offset (* n-channels x)))
+              (p0 (ref-uint-8 pixels offset))
+              (p2 (ref-uint-8 pixels (+ offset 2))))
+         (setf (ref-uint-8 pixels offset) p2)
+         (setf (ref-uint-8 pixels (+ offset 2)) p0)))))))
+
+(defbinding (pixbuf-swap-rgb "clg_gdk_pixbuf_swap_rgb") () nil
+  pixbuf)