chiark / gitweb /
Hopefully allow (require :glib) again.
[clg] / gdk / gdk.lisp
index 3d1ffe346c36eb3eaa85dc2357cb556b7c561bdc..f3ec462673ac95dd6c6c5e61801f39098e4c7bb6 100644 (file)
@@ -20,7 +20,7 @@
 ;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 ;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
-;; $Id: gdk.lisp,v 1.30 2006-06-07 13:17:24 espen Exp $
+;; $Id: gdk.lisp,v 1.50 2008-04-21 16:21:07 espen Exp $
 
 
 (in-package "GDK")
@@ -36,13 +36,39 @@ (defbinding (gdk-init "gdk_parse_args") () nil
 
 ;;; Display
 
-(defbinding %display-open () display
+#-debug-ref-counting
+(defmethod print-object ((display display) stream)
+  (if (and (proxy-valid-p display) (slot-boundp display 'name))
+      (print-unreadable-object (display stream :type t :identity nil)
+        (format stream "~S at 0x~X" 
+        (display-name display) (pointer-address (foreign-location display))))
+    (call-next-method)))
+
+(defbinding %display-open () (or null display)
   (display-name (or null string)))
 
-(defun display-open (&optional display-name)
-  (let ((display (%display-open display-name)))
+(defvar *display-aliases* ())
+
+(defun display-add-alias (display alias)
+  (unless (rassoc display *display-aliases*)
+    (signal-connect display 'closed
+     #'(lambda (is-error-p)
+        (declare (ignore is-error-p))
+        (setq *display-aliases* 
+         (delete-if #'(lambda (mapping)
+                        (eq (cdr mapping) display))
+          *display-aliases*))))
+    (push (cons alias display) *display-aliases*)))
+
+
+(defun display-open (&optional name)
+  (let ((display (or
+                 (%display-open name)
+                 (error "Opening display failed: ~A" name))))
     (unless (display-get-default)
       (display-set-default display))
+    (when (and (stringp name) (not (string= name (display-name display))))
+      (display-add-alias display name))
     display))
 
 (defbinding %display-get-n-screens () int
@@ -71,14 +97,16 @@ (defbinding display-flush (&optional (display (display-get-default))) nil
   (display display))
 
 (defbinding display-close (&optional (display (display-get-default))) nil
-  (display display))
+  ((ensure-display display t) display))
+
+(defbinding flush () nil)
 
 (defbinding display-get-event
-    (&optional (display (display-get-default))) event
+    (&optional (display (display-get-default))) (or null event)
   (display display))
 
 (defbinding display-peek-event
-    (&optional (display (display-get-default))) event
+    (&optional (display (display-get-default))) (or null event)
   (display display))
 
 (defbinding display-put-event
@@ -90,33 +118,199 @@ (defbinding (display-connection-number "clg_gdk_connection_number")
     (&optional (display (display-get-default))) int
   (display display))
 
+(defun find-display (name &optional (error-p t))
+  (or
+   (find name (list-displays) :key #'display-name :test #'string=)
+   (cdr (assoc name *display-aliases* :test #'string=))
+   (when error-p
+     (error "No such display: ~A" name))))
+
+;; This will not detect connections to the same server that use
+;; different hostnames
+(defun %find-similar-display (display)
+   (find (display-name display) (delete display (list-displays))
+    :key #'display-name :test #'string=))
+
+(defun ensure-display (display &optional existing-only-p)
+  (etypecase display
+    (null (display-get-default))
+    (display display)
+    (string (or 
+            (find-display display existing-only-p)
+            (let* ((new (display-open display))
+                   (existing (%find-similar-display new)))
+              (if existing
+                  (progn
+                    (display-add-alias existing display)
+                    (display-close new)
+                    existing)
+                new))))))
 
 
 ;;; Display manager
 
-(defbinding display-get-default () display)
-
-(defbinding (display-manager "gdk_display_manager_get") () display-manager)
+(defbinding display-get-default () (or null display))
 
 (defbinding (display-set-default "gdk_display_manager_set_default_display")
     (display) nil
   ((display-manager) display-manager)
   (display display))
 
+(defbinding (list-displays "gdk_display_manager_list_displays") ()
+    (gslist (static display))
+  ((display-manager) display-manager))
+
+;; The only purpose of exporting this is to make it possible for
+;; applications to connect to the display-opened signal
+(defbinding (display-manager "gdk_display_manager_get") () display-manager)
+
+(defbinding display-get-core-pointer 
+    (&optional (display (display-get-default))) device
+  (display display))
+
+(defmacro with-default-display ((display) &body body)
+  (let ((saved-display (make-symbol "SAVED-DISPLAY"))
+       (current-display (make-symbol "CURRENT-DISPLAY")))
+    `(let* ((,current-display ,display)
+           (,saved-display (when ,current-display
+                             (prog1
+                                 (display-get-default)
+                               (display-set-default (ensure-display ,current-display))))))
+       (unwind-protect 
+          (progn ,@body)
+        (when ,saved-display
+          (display-set-default ,saved-display))))))
+
+
+;;; Primitive graphics structures (points, rectangles and regions)
+
+(defbinding %rectangle-intersect () boolean
+  (src1 rectangle)
+  (src2 rectangle)
+  (dest rectangle))
+
+(defun rectangle-intersect (src1 src2 &optional (dest (make-instance 'rectangle)))
+  "Calculates the intersection of two rectangles. It is allowed for DEST to be the same as either SRC1 or SRC2. DEST is returned if the to rectangles intersect, otherwise NIL" 
+  (when (%rectangle-intersect src1 src2 dest)
+    dest))
+
+(defbinding rectangle-union (src1 src2 &optional (dest (make-instance 'rectangle))) nil
+  "Calculates the union of two rectangles. The union of rectangles SRC1 and SRC2 is the smallest rectangle which includes both SRC1 and SRC2 within it. It is allowed for DEST to be the same as either SRC1 or SRC2." 
+  (src1 rectangle)
+  (src2 rectangle)
+  (dest rectangle :in/return))
+
+(defun ensure-rectangle (rectangle)
+  (etypecase rectangle 
+    (rectangle rectangle)
+    (vector (make-instance 'rectangle 
+            :x (aref rectangle 0) :y (aref rectangle 1)
+            :width (aref rectangle 2) :height (aref rectangle 3)))))
+
+
+(defbinding %region-new () pointer)
+
+(defbinding %region-polygon () pointer
+  (points (vector (inlined point)))
+  (n-points int)
+  (fill-rule fill-rule))
+
+(defbinding %region-rectangle () pointer
+  (rectangle rectangle))
+
+(defbinding %region-copy () pointer
+  (location pointer))
+
+(defbinding %region-destroy () nil
+  (location pointer))
+
+(defmethod allocate-foreign ((region region) &key rectangle polygon fill-rule)
+  (cond
+   ((and rectangle polygon) 
+    (error "Only one of the keyword arguments :RECTANGLE and :POLYGON can be specified"))
+   (rectangle (%region-rectangle (ensure-rectangle rectangle)))
+   (polygon (%region-polygon polygon (length polygon) fill-rule))
+   ((%region-new))))
+
+(defun ensure-region (region)
+  (etypecase region 
+    (region region)
+    ((or rectangle vector) 
+     (make-instance 'region :rectangle (ensure-rectangle region)))
+    (list
+     (make-instance 'region :polygon region))))
+
+(defbinding region-get-clipbox (region &optional (rectangle (make-instance 'rectangle))) nil
+  (region region)
+  (rectangle rectangle :in/return))
+
+(defbinding %region-get-rectangles () nil
+  (region region)
+  (rectangles pointer :out)
+  (n-rectangles int :out))
+
+(defun region-get-rectangles (region)
+  "Obtains the area covered by the region as a list of rectangles."
+  (multiple-value-bind (location length) (%region-get-rectangles region)
+    (prog1
+       (map-c-vector 'list #'identity location '(inlined rectangle) length :get)
+      (deallocate-memory location))))
+
+(defbinding region-empty-p () boolean
+  (region region))
+
+(defbinding region-equal-p () boolean
+  (region1 region)
+  (region2 region))
+
+(defbinding region-point-in-p () boolean
+  (region region)
+  (x int)
+  (y int))
+
+(defbinding region-rect-in (region rectangle) overlap-type
+  (region region)
+  ((ensure-rectangle rectangle) rectangle))
+
+(defbinding region-offset () nil
+  (region region)
+  (dx int)
+  (dy int))
+
+(defbinding region-shrink () nil
+  (region region)
+  (dx int)
+  (dy int))
+
+(defbinding region-intersect (source1 source2) nil
+  ((ensure-region source1) region :in/return)
+  ((ensure-region source2) region))
+
+(defbinding region-union (source1 source2) nil
+  ((ensure-region source1) region :in/return)
+  ((ensure-region source2) region))
+
+(defbinding region-subtract (source1 source2) nil
+  ((ensure-region source1) region :in/return)
+  ((ensure-region source2) region))
+
+(defbinding region-xor (source1 source2) nil
+  ((ensure-region source1) region :in/return)
+  ((ensure-region source2) region))
 
 
 ;;; Events
 
 (defbinding (events-pending-p "gdk_events_pending") () boolean)
 
-(defbinding event-get () event)
+(defbinding event-get () (or null event))
 
-(defbinding event-peek () event)
+(defbinding event-peek () (or null event))
 
 (defbinding event-get-graphics-expose () event
   (window window))
 
-(defbinding event-put () event
+(defbinding event-put () nil
   (event event))
 
 ;(defbinding event-handler-set () ...)
@@ -129,11 +323,18 @@ (defbinding get-show-events () boolean)
 
 ;;; Miscellaneous functions
 
-(defbinding screen-width () int)
-(defbinding screen-height () int)
+(defbinding screen-width () int
+  (screen screen))
+
+(defbinding screen-height () int
+  (screen screen))
+
+(defbinding screen-width-mm () int
+  (screen screen))
+
+(defbinding screen-height-mm () int
+  (screen screen))
 
-(defbinding screen-width-mm () int)
-(defbinding screen-height-mm () int)
 
 (defbinding pointer-grab 
     (window &key owner-events events confine-to cursor time) grab-status
@@ -214,8 +415,9 @@ (defbinding list-visuals () (glist visual))
 (defbinding window-destroy () nil
   (window window))
 
-
-(defbinding window-at-pointer () window
+(defbinding (window-at-pointer "gdk_display_get_window_at_pointer") 
+    (&optional (display (display-get-default))) (or null window)
+  display
   (x int :out)
   (y int :out))
 
@@ -291,6 +493,13 @@ (defbinding window-scroll () nil
   (dx int)
   (dy int))
 
+#?(pkg-exists-p "gtk+-2.0" :atleast-version "2.8.0")
+(defbinding window-move-region (window region dx dy) nil
+  (window window)
+  ((ensure-region region) region)
+  (dx int)
+  (dy int))
+
 (defbinding window-reparent () nil
   (window window)
   (new-parent window)
@@ -341,49 +550,223 @@ (defbinding window-begin-move-drag () nil
   (root-y int)
   (timestamp unsigned-int))
 
-;;
+;; Probably not needed
+;; (defbinding window-constrain-size () nil ..
+
+(defbinding window-begin-paint-region (window region) nil
+  (window window)
+  ((ensure-region region) region))
+
+(defbinding window-end-paint () nil
+  (window window))
 
+(defmacro with-window-paint ((window region) &body body)
+  `(progn
+     (window-begin-paint-region ,window ,region)
+     (unwind-protect 
+        (progn ,@body)
+       (window-end-paint ,window))))
+
+;; TODO: create wrapper function and use gdk_window_invalidate_maybe_recurse 
+;; if last arg is a function
+(defbinding window-invalidate-region (window region invalidate-children-p) nil
+  (window window)
+  ((ensure-region region) region)
+  (invalidate-children-p boolean))
+
+(defbinding window-get-update-area () region
+  (window window))
+
+(defbinding window-freeze-updates () nil
+  (window window))
+
+(defbinding window-thaw-updates () nil
+  (window window))
+
+(defbinding window-process-all-updates () nil)
+
+(defbinding window-process-updates () nil
+  (window window)
+  (update-children-p boolean))
+
+(defbinding window-set-debug-updates () nil
+  (enable-p boolean))
+
+(defbinding window-enable-synchronized-configure () nil
+  (window window))
+  
+(defbinding window-configure-finished () nil
+  (window window))
+
+;; Deprecated, use gobject user data mechanism
 (defbinding window-set-user-data () nil
   (window window)
   (user-data pointer))
 
 (defbinding window-set-override-redirect () nil
   (window window)
-  (override-redirect boolean))
+  (override-redirect-p boolean))
 
-; (defbinding window-add-filter () nil
+(defbinding window-set-accept-focus () nil
+  (window window)
+  (accept-focus-p boolean))
+
+(defbinding window-set-focus-on-map () nil
+  (window window)
+  (focus-on-map-p boolean))
 
+;; Added if needed
+; (defbinding window-add-filter () nil
 ; (defbinding window-remove-filter () nil
 
+;; New code should use window-shape-combine
 (defbinding window-shape-combine-mask () nil
   (window window)
   (shape-mask bitmap)
   (offset-x int)
   (offset-y int))
 
+(defbinding %window-shape-combine-region () nil
+  (window window)
+  (region (or null region))
+  (offset-x int)
+  (offset-y int))
+
+(defun window-shape-combine (window shape offset-x offset-y)
+  (etypecase shape
+    (null (%window-shape-combine-region window nil 0 0))
+    (region (%window-shape-combine-region window shape offset-x offset-y))
+    (bitmap (window-shape-combine-mask window shape offset-x offset-y))))
+
 (defbinding window-set-child-shapes () nil
   (window window))
 
 (defbinding window-merge-child-shapes () nil
   (window window))
 
+#?(pkg-exists-p "gtk+-2.0" :atleast-version "2.10.0")
+(progn
+  (defbinding %window-input-shape-combine-mask () nil
+    (window window)
+    (shape-mask bitmap)
+    (x int)
+    (y int))
+
+  (defbinding %window-input-shape-combine-region () nil
+    (window window)
+    (region (or null region))
+    (x int)
+    (y int))
+  
+  (defun window-input-shape-combine (window shape x y)
+    (etypecase shape
+      (null (%window-input-shape-combine-region window nil 0 0))
+      (region (%window-input-shape-combine-region window shape x y))
+      (bitmap (%window-input-shape-combine-mask window shape x y))))
+
+  (defbinding window-set-child-input-shapes () nil
+    (window window))
+  
+  (defbinding window-merge-child-input-shapes () nil
+    (window window)))
 
 (defbinding window-set-static-gravities () boolean
   (window window)
-  (use-static boolean))
+  (use-static-p boolean))
 
-; (defbinding add-client-message-filter ...
+(defbinding window-set-title () nil
+  (window window)
+  (title string))
+
+(defbinding window-set-background () nil
+  (window window)
+  (color color))
+
+(defbinding window-set-back-pixmap (window pixmap &optional parent-relative-p) nil
+  (window window)
+  (pixmap (or null pixmap))
+  (parent-relative-p boolean))
 
 (defbinding window-set-cursor () nil
   (window window)
   (cursor (or null cursor)))
 
-(defbinding window-get-pointer () window
+(defbinding window-get-geometry () nil
+  (window window)
+  (x int :out)
+  (y int :out)
+  (width int :out)
+  (height int :out)
+  (depth int :out))
+
+;(defbinding window-set-geometry-hints () nil
+
+(defbinding window-set-icon-list () nil
+  (window window)
+  (icons (glist pixbufs)))
+
+(defbinding window-set-skip-taskbar-hint () nil
+  (window window)
+  (skip-taskbar-p boolean))
+
+(defbinding window-set-skip-pager-hint () nil
+  (window window)
+  (skip-pager-p boolean))
+
+#?(pkg-exists-p "gtk+-2.0" :atleast-version "2.8.0")
+(defbinding window-set-urgency-hint () nil
+  (window window)
+  (urgent-p boolean))
+
+(defbinding window-get-position () nil
+  (window window)
+  (x int :out)
+  (y int :out))
+
+(defbinding window-get-root-origin () nil
+  (window window)
+  (x int :out)
+  (y int :out))
+
+(defbinding window-get-frame-extents (window &optional (extents (make-instance 'rect))) nil
+  (window window)
+  (extents rectangle :in/return))
+
+(defbinding window-get-origin () nil ; this may not work as
+  (window window)                    ; an int is actually returned
+  (x int :out)
+  (y int :out))
+
+(defbinding window-get-pointer () (or null window)
   (window window)
   (x int :out)
   (y int :out)
   (mask modifier-type :out))
 
+;(defbinding window-set-icon () nil
+
+(defbinding window-set-icon-name () nil
+  (window window)
+  (icon-name string))
+
+(defbinding window-set-transient-for () nil
+  (window window)
+  (parent window))
+
+(defbinding window-set-role () nil
+  (window window)
+  (role string))
+
+(defbinding %window-get-decorations () boolean
+  (window window)
+  (decorations wm-decoration :out))
+
+(defun %window-decorations-getter (window)
+  (nth-value 1 (%window-get-decorations window)))
+
+(defun %window-decorations-boundp (window)
+  (%window-get-decorations window))
+
 (defbinding %window-get-toplevels () (glist window))
 
 (defun window-get-toplevels (&optional screen)
@@ -470,7 +853,7 @@ (defbinding %pixmap-new () pointer
   (depth int))
 
 (defmethod allocate-foreign ((pximap pixmap) &key width height depth window)
-  (%pixmap-new window width height depth))
+  (%pixmap-new window (or width (drawable-width window)) (or height (drawable-height window)) (or depth -1)))
 
 (defun pixmap-new (width height depth &key window)
   (warn "PIXMAP-NEW is deprecated, use (make-instance 'pixmap ...) instead")
@@ -618,22 +1001,20 @@ (defbinding draw-arc () nil
 
 (defbinding %draw-layout () nil
   (drawable drawable) (gc gc) 
-  (font pango:font)
   (x int) (y int)
   (layout pango:layout))
 
 (defbinding %draw-layout-with-colors () nil
   (drawable drawable) (gc gc) 
-  (font pango:font)
   (x int) (y int)
   (layout pango:layout)
   (foreground (or null color))
   (background (or null color)))
 
-(defun draw-layout (drawable gc font x y layout &optional foreground background)
+(defun draw-layout (drawable gc x y layout &optional foreground background)
   (if (or foreground background)
-      (%draw-layout-with-colors drawable gc font x y layout foreground background)
-    (%draw-layout drawable gc font x y layout)))
+      (%draw-layout-with-colors drawable gc x y layout foreground background)
+    (%draw-layout drawable gc x y layout)))
 
 (defbinding draw-drawable 
     (drawable gc src src-x src-y dest-x dest-y &optional width height) nil
@@ -668,7 +1049,7 @@ (defbinding drawable-copy-to-image
 
 ;;; Key values
 
-(defbinding keyval-name () string
+(defbinding keyval-name () (static string)
   (keyval unsigned-int))
 
 (defbinding %keyval-from-name () unsigned-int
@@ -692,6 +1073,7 @@ (defbinding (keyval-is-upper-p "gdk_keyval_is_upper") () boolean
 (defbinding (keyval-is-lower-p "gdk_keyval_is_lower") () boolean
   (keyval unsigned-int))
 
+
 ;;; Cairo interaction
 
 #?(pkg-exists-p "gtk+-2.0" :atleast-version "2.8.0")
@@ -709,41 +1091,57 @@   (defbinding cairo-set-source-color () nil
     (cr cairo:context)
     (color color))
 
-  (defbinding cairo-set-source-pixbuf () nil
+  (defbinding cairo-set-source-pixbuf (cr pixbuf &optional (x 0.0) (y 0.0)) nil
     (cr cairo:context)
     (pixbuf pixbuf)
     (x double-float)
     (y double-float))
  
+  (defbinding cairo-set-source-pixmap (cr pixmap &optional (x 0.0) (y 0.0)) nil
+    (cr cairo:context)
+    (pixmap pixmap)
+    (x double-float)
+    (y double-float))
   (defbinding cairo-rectangle () nil
     (cr cairo:context)
     (rectangle rectangle))
  
-;;   (defbinding cairo-region () nil
-;;     (cr cairo:context)
-;;     (region region))
+  (defbinding cairo-region (cr region) nil
+    (cr cairo:context)
+    ((ensure-region region) region))
+
+  (defbinding (cairo-surface-get-window "clg_gdk_cairo_surface_get_window") () window
+    (surface cairo:surface))
 )
 
 
 
 ;;; Multi-threading support
 
-#+sbcl
+#+sb-thread
 (progn
-  (defvar *global-lock* (sb-thread:make-mutex :name "global GDK lock"))
-  (let ((recursive-level 0))
-    (defun threads-enter ()
-      (if (eq (sb-thread:mutex-value *global-lock*) sb-thread:*current-thread*)
-         (incf recursive-level)
-       (sb-thread:get-mutex *global-lock*)))
-
-    (defun threads-leave (&optional flush-p)
+  (defvar *global-lock* nil)
+  (defvar *recursion-count* 0)
+
+  (defun %global-lock-p ()
+    (eq (sb-thread:mutex-value *global-lock*) sb-thread:*current-thread*))
+
+  (defun threads-enter ()
+    (when *global-lock*
+      (if (%global-lock-p)
+         (incf *recursion-count*)
+        (sb-thread:get-mutex *global-lock*))))
+    
+  (defun threads-leave (&optional flush-p)
+    (when *global-lock*
+      (assert (%global-lock-p))
       (cond
-       ((zerop recursive-level)          
+       ((zerop *recursion-count*)
        (when flush-p
-         (display-flush))
+         (flush))
        (sb-thread:release-mutex *global-lock*))
-       (t (decf recursive-level)))))
+       (t (decf *recursion-count*)))))
 
   (define-callback %enter-fn nil ()
     (threads-enter))
@@ -751,13 +1149,43 @@   (define-callback %enter-fn nil ()
   (define-callback %leave-fn nil ()
     (threads-leave))
   
-  (defbinding threads-set-lock-functions (&optional) nil
+  (defbinding %threads-set-lock-functions (nil) nil
     (%enter-fn callback)
     (%leave-fn callback))
 
+  (defun threads-init ()
+    (setq *global-lock* (sb-thread:make-mutex :name "global GDK lock"))
+    (%threads-set-lock-functions))
+
   (defmacro with-global-lock (&body body)
     `(progn
        (threads-enter)
        (unwind-protect
-          ,@body
-        (threads-leave t)))))
+          (progn ,@body)
+        (threads-leave t))))
+
+  (defun timeout-add-with-lock (interval function &optional (priority +priority-default+))
+    (timeout-add interval
+     #'(lambda () 
+        (with-global-lock (funcall function)))
+     priority))
+
+  (defun idle-add-with-lock (function &optional (priority +priority-default-idle+))
+    (idle-add 
+     #'(lambda () 
+        (with-global-lock (funcall function)))
+     priority)))
+
+
+#-sb-thread
+(progn
+  (defmacro with-global-lock (&body body)
+    `(progn ,@body))
+
+  (defun timeout-add-with-lock (interval function &optional (priority +priority-default+))
+    (timeout-add interval function priority))
+
+  (defun idle-add-with-lock (function &optional (priority +priority-default-idle+))
+    (idle-add function priority)))
+
+