;;; xwem-osd.el --- On Screen Display implementation for XWEM.

;; Copyright (C) 2004 by Free Software Foundation, Inc.

;; Author: Zajcev Evgeny <zevlg@yandex.ru>
;; Created: Mon Jan 12 13:14:32 MSK 2004
;; Keywords: xwem
;; X-CVS: $Id: xwem-osd.el,v 1.2 2004/05/05 22:43:07 lg Exp $

;; This file is part of XWEM.

;; XWEM is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.

;; XWEM is distributed in the hope that it will be useful, but WITHOUT
;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
;; License for more details.

;; You should have received a copy of the GNU General Public License
;; along with XEmacs; see the file COPYING.  If not, write to the Free
;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
;; 02111-1307, USA.

;;; Synched up with: Not in FSF

;;; Commentary:

;; Support for on screen display in XWEM.  xwem-osd can display text,
;; processing bar, other stuff using shaped window.  The main feature
;; of this OSD implementation that it uses OSD instances to display
;; stuff, so it does not need to handle expose events.

;; OSD supports system tray.  It is very easy to write OSD dockapp.
;; Simple example in xwem-framei.el.  You just create osd as usuall,
;; but using `xwem-osd-create-dock', where you can specify width,
;; height and keymap to use, for example:
;; 
;;    (setq myosd (xwem-osd-create-dock (xwem-dpy) 24 24 (list 'keymap myosd-keymap)))
;;    (xwem-osd-text myosd "test")
;; 
;; This will create dockapp in system tray, display "test" in it, and
;; will execute commands in `myosd-keymap' if you click on OSD.  To
;; define commands in `myosd-keymap' do something like:
;; 
;;    (define-key myosd-keymap [button1]
;;      (lambda () (interactive) (xwem-message 'info "Myosd Hello world!")))
;;    (define-key myosd-keymap [button3] 'myosd-popup-menu)
;; 

;; New instance type added - dots.  To poly dataset in OSD you can use
;; `xwem-osd-dots-add' function.  TYPE is one of:
;; 
;;    'points      - Little circles.
;;    'lines       - Lines
;;    'linespoints - Lines with points at ends.
;;    'impulses    - Impulses from 0 to dot's Y.
;;    'dots        - Tiny dots.
;;    'steps       - Steps around points
;;    'fsteps      - Another 'steps variant
;;    'histeps     - Yet another 'steps variant (NI)
;;    'boxes       - Boxes arount points (NI)
;; 
;; For example if you have some dataset(CPU load f.i.) which
;; represented in as list of cons cells, which car is X and cdr is Y.
;; 
;;   ds
;;   ==>
;;   ((1 . 3) (3 . 6) (5 . 4) (7 . 10) (9 . 10) (11 . 3))
;;
;;   (xwem-osd-dots-add myosd ds 'impulses "red4")
;; 
;; This will draw nice graph.
;; 
;; For full drawing posibilities consider `xwem-diagram.el'.

;;; Code:

(eval-when-compile
  (require 'cl))

(require 'xlib-xshape)

(defconst xwem-osd-instance-types '(text line dots arc rect)
  "List of valid types of osd instance.")


(defstruct xwem-osd-instance
  type					; instance type, see `xwem-osd-instance-types'
  osd					; back reference to osd
  (depth 0)				; depth

  xwin xmask
  color)				; instance background color

(defmacro xwem-osd-instance-xdpy (osin)
  "Return display of OSIN osd instance."
  `(xwem-osd-xdpy (xwem-osd-instance-osd osin)))

(defstruct xwem-osd
  always-ontop                          ; non-nil if OSD must be always on top
  state					; 'destroyed, 'hided or 'shown
  x y width height

  xdpy
  xwin
  xmask

  gc					; GC used to draw
  mask-gc				; GC used to draw mask

  instances				; list of xwem-osd-instance structs sorted by depth

  plist)				; User defined plist

(defsubst xwem-osd-put-prop (osd prop val)
  "In OSD's properties list put property PROP with value VAL."
  (setf (xwem-osd-plist osd)
        (plist-put (xwem-osd-plist osd) prop val)))
(put 'xwem-osd-put-prop 'lisp-indent-function 2)

(defsubst xwem-osd-get-prop (osd prop)
  "Return OSD's property PROP."
  (plist-get (xwem-osd-plist osd) prop))

(defcustom xwem-osd-default-font "fixed"
  "Default font for text drawed in osd.")

(defcustom xwem-osd-default-color "black"
  "Default color used to draw.")

(defcustom xwem-osd-always-ontop t
  "*Non-nil mean that OSD's winow will be always on top.")


;;; Functions
(defun xwem-osd-event-handler (xdpy xwin xev)
  "On X display XDPY and window XWIN handle X Event XEV."
  (let* ((osd (xwem-osd-get-osd xwin))
         (keymap (xwem-osd-get-prop osd 'keymap)))

    (when (xwem-osd-p osd)
      (X-Event-CASE xev
        (:X-DestroyNotify
         (xwem-osd-destroy osd t))

        ((:X-KeyPress :X-ButtonPress :X-ButtonRelease)
         (when (keymapp keymap)
           (let ((xwem-override-global-map keymap))
             (xwem-kbd-handle-keybutton xev))))
        ))
    ))

(defun xwem-osd-root-event-handler (xdpy xwin xev)
  "Root window event handler for OSD."
  (X-Event-CASE xev
    (:X-ConfigureNotify
     (let ((osd (xwem-osd-get-osd (X-Event-xconfigure-above-sibling xev))))
       (when (and (xwem-osd-p osd) (xwem-osd-always-ontop osd))
	 ;; OSD's window is above sibling for some other window, so it
	 ;; is (osd's window) obscured and we need to pop it back.
         ;; 
         ;; NOTE: what if two OSD with always-ontop property obscures
         ;;       each other?
	 (xwem-osd-show osd)
	 )))
    ))

;;; Instances operations
(defun xwem-osd-instance-destroy (osin)
  "Destroy osd instance OSIN."
  (XDestroyWindow (xwem-osd-instance-xdpy osin) (xwem-osd-instance-xwin osin))
  (XFreePixmap (xwem-osd-instance-xdpy osin) (xwem-osd-instance-xmask osin))

  (X-invalidate-cl-struct osin)
  )

(defun xwem-osd-add-instance (osd depth &optional color)
  "In OSD add osd instance with background COLOR.
Return newly created osd instance."
  (unless color
    (setq color xwem-osd-default-color))

  (let ((xdpy (xwem-osd-xdpy osd))
	(osin (make-xwem-osd-instance :osd osd :depth depth
				      :color color)))
    (setf (xwem-osd-instance-xwin osin)
	  (XCreateWindow xdpy (xwem-osd-xwin osd)
			 0 0 (xwem-osd-width osd) (xwem-osd-height osd)
			 0 nil nil nil
			 (make-X-Attr :override-redirect t
				      :background-pixel (XAllocNamedColor xdpy (XDefaultColormap xdpy)
									  color))))
    (setf (xwem-osd-instance-xmask osin)
	  (XCreatePixmap xdpy (make-X-Pixmap :dpy xdpy :id (X-Dpy-get-id xdpy))
			 (xwem-osd-instance-xwin osin) 1
			 (xwem-osd-width osd) (xwem-osd-height osd)))
    (xwem-osd-instance-clear osin)

    (push osin (xwem-osd-instances osd))
    ;; TODO: - sort instances according to depth

    osin))

(defun xwem-osd-instance-clear (osin)
  "Clear mask area of OSD instance."
  (let ((osd (xwem-osd-instance-osd osin)))
    (xwem-osd-mask-fgbg osd)
    (XFillRectangle (xwem-osd-xdpy osd) (xwem-osd-instance-xmask osin) (xwem-osd-mask-gc osd)
		    0 0 (xwem-osd-width osd) (xwem-osd-height osd))
    (xwem-osd-mask-fgbg osd)))

(defun xwem-osd-instance-show (osin)
  "Show osd instance OSIN."
  (XMapWindow (xwem-osd-instance-xdpy osin) (xwem-osd-instance-xwin osin)))

(defun xwem-osd-instance-set-color (osin new-color)
  "Set new color."
  (let ((xdpy (xwem-osd-instance-xdpy osin)))
    (setf (xwem-osd-instance-color osin) new-color)
    (XSetWindowBackground xdpy (xwem-osd-instance-xwin osin)
			  (XAllocNamedColor xdpy (XDefaultColormap xdpy)
					    new-color))
    (XClearArea xdpy (xwem-osd-instance-xwin osin)
		0 0 (xwem-osd-width (xwem-osd-instance-osd osin))
		(xwem-osd-height (xwem-osd-instance-osd osin)) nil)))

;;; OSD functions
;;;###autoload
(defun xwem-osd-create (xdpy x y width height &optional x-parent properties)
  "On X display XDPY create new xwem osd context with +X+Y/WIDTHxHEIGHT geometry on X-PARENT."
  (let ((osd (make-xwem-osd :always-ontop xwem-osd-always-ontop :xdpy xdpy :x x :y y :width width :height height
                            :plist properties))
        (keymap (plist-get properties 'keymap)))
    (setf (xwem-osd-xwin osd)
	  (XCreateWindow xdpy (or x-parent (XDefaultRootWindow xdpy))
			 x y width height 0 nil nil nil
			 (make-X-Attr :override-redirect t
				      :background-pixel (XBlackPixel xdpy)
				      :event-mask (Xmask-or XM-StructureNotify
                                                            (if keymap (Xmask-or XM-KeyPress XM-ButtonPress XM-ButtonRelease) 0)))))
    ;; Create gc
    (setf (xwem-osd-gc osd)
	  (XCreateGC xdpy (xwem-osd-xwin osd)
		     (make-X-Gc :dpy xdpy :id (X-Dpy-get-id xdpy)
				:foreground (XAllocNamedColor xdpy (XDefaultColormap xdpy)
							      xwem-osd-default-color)
				:font (X-Font-get xdpy xwem-osd-default-font))))

    (X-Win-put-prop (xwem-osd-xwin osd) 'osd-ctx osd)
    (X-Win-EventHandler-add-new (xwem-osd-xwin osd) 'xwem-osd-event-handler)

    (when xwem-osd-always-ontop
      (X-Win-EventHandler-add-new (XDefaultRootWindow xdpy) 'xwem-osd-root-event-handler))

    (xwem-osd-create-mask osd)
    osd))

;;;###autoload
(defun xwem-osd-create-dock (xdpy width height &optional properties)
  "Create docked osd instance.
XDPY - Display.
X, Y, WIDTH, HEIGHT - OSD Geometry."
  (let* ((xwem-osd-always-ontop nil)    ; for sure
         (osd (xwem-osd-create xdpy 0 0 width height nil properties)))
    (xwem-osd-clear osd)
    (XTrayInit xdpy (xwem-osd-xwin osd))
    osd))

(defun xwem-osd-get-osd (xwin)
  "Get osd context associated with XWIN."
  (and (X-Win-p xwin) (X-Win-get-prop xwin 'osd-ctx)))

(defun xwem-osd-mask-fgbg (osd)
  "Exchange foreground and background colors in OSD's mask gc."
  (let* ((mgc (xwem-osd-mask-gc osd))
	 (fg (X-Gc-foreground mgc))
	 (bg (X-Gc-background mgc)))
    (setf (X-Gc-foreground mgc) bg)
    (setf (X-Gc-background mgc) fg)
    
    (XChangeGC (xwem-osd-xdpy osd) mgc)))

(defun xwem-osd-clear-mask (osd)
  "Clear mask area of OSD context."
  (xwem-osd-mask-fgbg osd)
  (XFillRectangle (xwem-osd-xdpy osd) (xwem-osd-xmask osd) (xwem-osd-mask-gc osd)
		  0 0 (xwem-osd-width osd) (xwem-osd-height osd))
  (xwem-osd-mask-fgbg osd))
  
(defun xwem-osd-create-mask (osd)
  "For xwem osd context OSD create mask pixmap."
  (let ((xdpy (xwem-osd-xdpy osd)))
    (setf (xwem-osd-xmask osd)
	  (XCreatePixmap xdpy (make-X-Pixmap :dpy xdpy :id (X-Dpy-get-id xdpy))
			 (xwem-osd-xwin osd) 1 (xwem-osd-width osd)
			 (xwem-osd-height osd)))

    (setf (xwem-osd-mask-gc osd)
	  (XCreateGC xdpy (xwem-osd-xmask osd)
		     (make-X-Gc :dpy xdpy :id (X-Dpy-get-id xdpy)
				:foreground 1.0
				:background 0.0
				:font (X-Font-get xdpy xwem-osd-default-font))))
    (xwem-osd-clear-mask osd)
    ))

(defun xwem-osd-set-height (osd new-height)
  "Set OSD's window height to NEW-HEIGHT."
  (setf (xwem-osd-height osd) new-height)
  (XResizeWindow (xwem-osd-xdpy osd)
		 (xwem-osd-xwin osd)
		 (xwem-osd-width osd)
		 (xwem-osd-height osd))

  (XFreePixmap (xwem-osd-xdpy osd) (xwem-osd-xmask osd))
  (xwem-osd-create-mask osd))

(defun xwem-osd-set-width (osd new-width)
  "Set OSD's window width to NEW-WIDTH."
  (setf (xwem-osd-width osd) new-width)
  (XResizeWindow (xwem-osd-xdpy osd)
		 (xwem-osd-xwin osd)
		 (xwem-osd-width osd)
		 (xwem-osd-height osd))

  (XFreePixmap (xwem-osd-xdpy osd) (xwem-osd-xmask osd))
  (xwem-osd-create-mask osd))

(defun xwem-osd-move (osd new-x new-y)
  "Change OSD's window position to NEW-X, NEW-Y."
  (XMoveWindow (xwem-osd-xdpy osd) (xwem-osd-xwin osd)
	       new-x new-y))

(defun xwem-osd-set-xwin-color (osd color-name)
  "Set background for OSD's window to COLOR-NAME."
  (let ((xdpy (xwem-osd-xdpy osd)))
    (XSetWindowBackground xdpy (xwem-osd-xwin osd)
			  (XAllocNamedColor xdpy (XDefaultColormap xdpy)
					    color-name))))

(defun xwem-osd-set-gc-color (osd color-name)
  "Set OSD's gc foreground color to COLOR-NAME."
  (let ((xdpy (xwem-osd-xdpy osd)))
    (setf (X-Gc-foreground (xwem-osd-gc osd))
	  (XAllocNamedColor xdpy (XDefaultColormap xdpy)
			    color-name))
    (XChangeGC xdpy (xwem-osd-gc osd))))

(defun xwem-osd-set-color (osd color-name)
  "Set both OSD's background and OSD's gc foreground color to COLOR-NAME."
  (let* ((xdpy (xwem-osd-xdpy osd))
	 (col (XAllocNamedColor xdpy (XDefaultColormap xdpy)
				color-name)))
    (XSetWindowBackground xdpy (xwem-osd-xwin osd) col)
    (xwem-osd-clear-xwin osd)
    (setf (X-Gc-foreground (xwem-osd-gc osd)) col)
    (XChangeGC xdpy (xwem-osd-gc osd))))

(defun xwem-osd-show (osd)
  "Show OSD's window."
  (X-XShapeMask (xwem-osd-xdpy osd) (xwem-osd-xwin osd) X-XShape-Bounding X-XShapeSet 0 0 (xwem-osd-xmask osd))
  (XMapWindow (xwem-osd-xdpy osd) (xwem-osd-xwin osd))
  (XRaiseWindow (xwem-osd-xdpy osd) (xwem-osd-xwin osd)))

(defun xwem-osd-hide (osd)
  "Hide OSD's window."
  (XUnmapWindow (xwem-osd-xdpy osd) (xwem-osd-xwin osd)))

(defun xwem-osd-destroy-instances (osd)
  "Destroy all instances in OSD."
  (mapcar (lambda (osin)
	    (xwem-osd-instance-destroy osin))
	  (xwem-osd-instances osd))
  (setf (xwem-osd-instances osd) nil))

(defun xwem-osd-destroy (osd &optional already-destroyed)
  "Destroy OSD context."
  (xwem-osd-destroy-instances osd)

  (X-Win-EventHandler-rem (xwem-osd-xwin osd) 'xwem-osd-event-handler)
  
  ;; NOTE: Can't delet 'xwem-osd-root-event-handler because some other
  ;;       OSD can be with always-ontop property.
;  (X-Win-EventHandler-rem (XDefaultRootWindow (xwem-osd-xdpy osd)) 'xwem-osd-root-event-handler)

  (unless already-destroyed
    (XDestroyWindow (xwem-osd-xdpy osd) (xwem-osd-xwin osd)))
  (XFreePixmap (xwem-osd-xdpy osd) (xwem-osd-xmask osd))
  (XFreeGC (xwem-osd-xdpy osd) (xwem-osd-mask-gc osd))
  (XFreeGC (xwem-osd-xdpy osd) (xwem-osd-gc osd))

  (X-invalidate-cl-struct osd))

(defun xwem-osd-set-font (osd font-name)
  "In OSD's context set font to be FONT-NAME."
  (let* ((xdpy (xwem-osd-xdpy osd))
	 (gc (xwem-osd-gc osd))
	 (mgc (xwem-osd-mask-gc osd))
	 (font (X-Font-get xdpy font-name)))
    (setf (X-Gc-font mgc) font)
    (XChangeGC xdpy mgc)

    (setf (X-Gc-font gc) font)
    (XChangeGC xdpy gc)))

(defun xwem-osd-char-width (osd)
  "Return width of OSD's window in characters."
  ;; XXX assumes that font is width fixed
  (/ (xwem-osd-width osd)
     (X-Text-width (xwem-osd-xdpy osd) (X-Gc-font (xwem-osd-mask-gc osd)) "_")))

(defun xwem-osd-clear-xwin (osd)
  "Clear contents of OSD's window."
  (XClearArea (xwem-osd-xdpy osd) (xwem-osd-xwin osd) 0 0
	      (xwem-osd-width osd) (xwem-osd-height osd) nil))

(defun xwem-osd-clear (osd)
  "Clear OSD window."
  (xwem-osd-destroy-instances osd)
  (xwem-osd-clear-mask osd)

  (X-XShapeMask (xwem-osd-xdpy osd) (xwem-osd-xwin osd)
		X-XShape-Bounding X-XShapeSet 0 0 (xwem-osd-xmask osd)))

(defun xwem-osd-text (osd string)
  "In OSD's context show string.
When MASK-ONLY is non-nil, do not performe any real drawing."
  (let* ((xdpy (xwem-osd-xdpy osd))
	 (yoff (- (X-Text-height xdpy (X-Gc-font (xwem-osd-mask-gc osd)) string)
		  (X-Text-descent xdpy (X-Gc-font (xwem-osd-mask-gc osd)) string))))

    ;; Update window shape
    (xwem-osd-clear-mask osd)
    (XDrawString xdpy (xwem-osd-xmask osd) (xwem-osd-mask-gc osd)
		 0 yoff string)
    (X-XShapeMask xdpy (xwem-osd-xwin osd)
		  X-XShape-Bounding X-XShapeSet 0 0 (xwem-osd-xmask osd))
    ))

(defun xwem-osd-color-text (osd strspec-list)
  "In OSD's win draw colored text specified by STRSPEC-LIST."
  (xwem-osd-clear osd)
  (let ((curstr ""))
    (X-Dpy-send-excursion (xwem-osd-xdpy osd)
      (mapcar (lambda (strspec)
		(let* ((xdpy (xwem-osd-xdpy osd))
		       (str (concat curstr (car strspec)))
		       (yoff (- (X-Text-height xdpy (X-Gc-font (xwem-osd-mask-gc osd)) str)
				(X-Text-descent xdpy (X-Gc-font (xwem-osd-mask-gc osd)) str))))
		  (xwem-osd-set-xwin-color osd (cdr strspec))
		  (XDrawString xdpy (xwem-osd-xmask osd) (xwem-osd-mask-gc osd)
			       0 yoff str)
		  (X-XShapeMask xdpy (xwem-osd-xwin osd)
				X-XShape-Bounding X-XShapeSet 0 0 (xwem-osd-xmask osd))
		
		  (setq curstr (concat curstr (car strspec)))))
	      strspec-list))))
    
(defun xwem-osd-text-add (osd x y string &optional color)
  "In OSD's context at X Y coordinates add STRING colored with COLOR."
  (let* ((xdpy (xwem-osd-xdpy osd))
	 (yoff (- (X-Text-height xdpy (X-Gc-font (xwem-osd-mask-gc osd)) string)
		  (X-Text-descent xdpy (X-Gc-font (xwem-osd-mask-gc osd)) string)))
	 osin)

    ;; Setup OSD instance
    (setq osin (xwem-osd-add-instance osd 0 color))
    (setf (xwem-osd-instance-type osin) 'text)
    (XDrawString xdpy (xwem-osd-instance-xmask osin) (xwem-osd-mask-gc osd)
		 x (+ y yoff) string)
    (X-XShapeMask xdpy (xwem-osd-instance-xwin osin)
		  X-XShape-Bounding X-XShapeSet 0 0 (xwem-osd-instance-xmask osin))
    (xwem-osd-instance-show osin)

    ;; Update window shape
    (XDrawString xdpy (xwem-osd-xmask osd) (xwem-osd-mask-gc osd)
		 x (+ y yoff) string)
    (X-XShapeMask xdpy (xwem-osd-xwin osd)
		  X-XShape-Bounding X-XShapeUnion 0 0 (xwem-osd-xmask osd))
    ))

(defun xwem-osd-set-line-width (osd new-line-width)
  "Set OSD's gc line width to NEW-LINE-WIDTH."
  (setf (X-Gc-line-width (xwem-osd-gc osd)) new-line-width)
  (XChangeGC (xwem-osd-xdpy osd) (xwem-osd-gc osd))

  (setf (X-Gc-line-width (xwem-osd-mask-gc osd)) new-line-width)
  (XChangeGC (xwem-osd-xdpy osd) (xwem-osd-mask-gc osd))
  )

(defun xwem-osd-line-add (osd x0 y0 x1 y1 &optional color)
  "In OSD's window add line."
  (let ((xdpy (xwem-osd-xdpy osd))
	osin)
    
    ;; Create OSD line instance
    (setq osin (xwem-osd-add-instance osd 0 color))
    (setf (xwem-osd-instance-type osin) 'line)
    (XDrawLine xdpy (xwem-osd-instance-xmask osin) (xwem-osd-mask-gc osd)
	       x0 y0 x1 y1)
    (X-XShapeMask xdpy (xwem-osd-instance-xwin osin)
		  X-XShape-Bounding X-XShapeSet 0 0 (xwem-osd-instance-xmask osin))
    (xwem-osd-instance-show osin)

    ;; Update OSD window shape
    (XDrawLine xdpy (xwem-osd-xmask osd) (xwem-osd-mask-gc osd)
	       x0 y0 x1 y1)
    (X-XShapeMask (xwem-osd-xdpy osd) (xwem-osd-xwin osd)
		  X-XShape-Bounding X-XShapeUnion 0 0 (xwem-osd-xmask osd))
    ))

(defun xwem-osd-dots-add (osd dots type &optional color)
  "In OSD's window add DOTS of TYPE."
  (let ((xdpy (xwem-osd-xdpy osd))
        osin)

    ;; Create OSD dots instancne
    (setq osin (xwem-osd-add-instance osd 0 color))
    (setf (xwem-osd-instance-type osin) 'dots)
    (xwem-diag-plot-dots type (xwem-osd-instance-xmask osin) (xwem-osd-mask-gc osd)
                         0 (xwem-osd-height osd) dots)
    (X-XShapeMask xdpy (xwem-osd-instance-xwin osin)
		  X-XShape-Bounding X-XShapeSet 0 0 (xwem-osd-instance-xmask osin))
    (xwem-osd-instance-show osin)

    ;; Update OSD window shape
    (xwem-diag-plot-dots type (xwem-osd-xmask osd) (xwem-osd-mask-gc osd)
                         0 (xwem-osd-height osd) dots)
    (X-XShapeMask (xwem-osd-xdpy osd) (xwem-osd-xwin osd)
		  X-XShape-Bounding X-XShapeUnion 0 0 (xwem-osd-xmask osd))
    ))

(defun xwem-osd-arc-add (osd xarc &optional color)
  "In OSD's window draw arc specified by XARC."
  (let ((xdpy (xwem-osd-xdpy osd))
	osin)

    ;; Create OSD arc instance
    (setq osin (xwem-osd-add-instance osd 0 color))
    (setf (xwem-osd-instance-type osin) 'arc)
    (XDrawArcs xdpy (xwem-osd-instance-xmask osin) (xwem-osd-mask-gc osd)
	       (list xarc))
    (X-XShapeMask xdpy (xwem-osd-instance-xwin osin)
		  X-XShape-Bounding X-XShapeSet 0 0 (xwem-osd-instance-xmask osin))

    ;; Update OSD shape
    (XDrawArcs xdpy (xwem-osd-xmask osd) (xwem-osd-mask-gc osd)
	       (list xarc))
    (X-XShapeMask (xwem-osd-xdpy osd) (xwem-osd-xwin osd)
		  X-XShape-Bounding X-XShapeUnion 0 0 (xwem-osd-xmask osd))
    ))

(defun xwem-osd-rect-add (osd x y width height &optional color)
  "In OSD's window add rectangle specified by X Y WIDTH and HEIGHT."
  (let ((xdpy (xwem-osd-xdpy osd))
	osin)

    ;; Created OSD rect instance
    (setq osin (xwem-osd-add-instance osd 0 color))
    (setf (xwem-osd-instance-type osin) 'rect)
    (XDrawRectangle xdpy (xwem-osd-instance-xmask osin) (xwem-osd-mask-gc osd)
		    x y width height)
    (X-XShapeMask xdpy (xwem-osd-instance-xwin osin)
		  X-XShape-Bounding X-XShapeSet 0 0 (xwem-osd-instance-xmask osin))

    ;; Update OSD shape
    (XDrawRectangle xdpy (xwem-osd-xmask osd) (xwem-osd-mask-gc osd)
		    x y width height)
    (X-XShapeMask (xwem-osd-xdpy osd) (xwem-osd-xwin osd)
		  X-XShape-Bounding X-XShapeUnion 0 0 (xwem-osd-xmask osd))
    ))

;;; You might consider more powerfull `working' package, which is part
;;; of CEDET.
(defun xwem-osd-working-bar-display (tot-len percents)
  "Return a string with a bar-graph end percentile showing percentage.
TOT-LEN is the total length of bar.  PERCENTS is percentage state."
  (let* ((prstr (int-to-string percents))
	 (len (- tot-len (+ 10 (length prstr))))
	 (dcs (truncate (* len (/ percents 100.0))))
	 (tlen (- len dcs)))
    (concat ": ["
	    (make-string (if (> dcs 0) dcs 0) ?#)
	    (make-string (if (> tlen 0) tlen 0) ?.)
	    "] ... " prstr "%")))

(defun xwem-osd-working-percent-bar (osd prompt percents)
  "Display percentage with PERCENTS done bar prompting PROMPT."
  (require 'working)

  (let ((osdcw (xwem-osd-char-width osd)))
    (xwem-osd-text osd (concat prompt (xwem-osd-working-bar-display (- osdcw (length prompt)) percents)))))

					
;;; Testing:
;;  (setq mosd (xwem-osd-create (xwem-dpy) 10 20 400 200))
;;  (xwem-osd-set-color mosd "green4")
;;  (xwem-osd-set-font mosd "10x20")
;;  (xwem-osd-text mosd "test")
;;  (xwem-osd-show mosd)
    
;;  (progn
;;    (setq i 0)
;;    (xwem-osd-show mosd)
;;    (xwem-osd-set-color mosd "red4")
;;    (while (< i 100)
;;      (cond ((= i 60) (xwem-osd-set-color mosd "green4"))
;;          ((= i 30) (xwem-osd-set-color mosd "yellow4")))
;;      (xwem-osd-working-percent-bar mosd "Processing" i)
;;      (sleep-for 0.01)
;;      (incf i 1))
;;    (xwem-osd-set-color mosd "red4")
;;    (xwem-osd-text mosd "Processing done."))
    
;;  (xwem-osd-destroy mosd)

;; Here is example from Steve Youngs <sryoungs@bigpond.net.au> to
;; display date using OSD:

;;   (defvar sy-osd-date ni)
;;   (copy-face 'default 'sy-osd-date-face)
;;   (set-face-foreground 'sy-osd-date-face "cyan")
;; 
;;   (defun sy-update-osd-date-maybe (&optional force-update)
;;     (let* ((now (decode-time))
;;            (cur-hour (nth 2 now))
;;            (cur-min (nth 1 now))
;;            (cur-comp-time (+ (* cur-hour 60) cur-min)))
;;       (when (or force-update (= 0 cur-comp-time))
;;         (xwem-osd-text sy-osd (format-time-string "%a, %b%e")))))
;;     
;;   (defun sy-show-date-osd ()
;;     (let* ((fromleft 830)
;;            (fromtop 740)
;;            (face `sy-osd-face)
;;            (xwem-osd-always-ontop t))     ; Force date to be always ontop
;;       (setq sy-osd (xwem-osd-create (xwem-dpy) fromleft fromtop 400 200))
;;       (xwem-osd-set-color sy-osd (face-foreground-name face))
;;       (xwem-osd-set-font sy-osd (face-font-name face))
;;       (sy-update-osd-date-maybe t)
;;       (xwem-osd-show sy-osd)
;;   
;;       (start-itimer "sy-osd-date-itimer"
;;                     'sy-update-osd-date-maybe
;;                     60 60)))
;;   
;;   (defun sy-destroy-date-osd ()
;;     (delete-itimer  "sy-osd-date-itimer")
;;     (when (xwem-osd-p sy-osd)
;;       (xwem-osd-destroy sy-osd)))
;;     
;;   (add-hook 'xwem-after-init-hook 'sy-show-date-osd)



(provide 'xwem-osd)

;;; xwem-osd.el ends here
