;;!emacs
;;
;; FILE:         hui-window.el
;; SUMMARY:      Smart Mouse Key window and modeline depress/release actions.
;; USAGE:        GNU Emacs Lisp Library, Load only when mouse is available.
;;
;; AUTHOR:       Bob Weiner
;; ORG:          Motorola, Inc., PWDG
;;
;; ORIG-DATE:    21-Sep-92
;; LAST-MOD:     10-May-93 at 12:19:33 by Bob Weiner
;;
;; This file is part of Hyperbole.
;;
;; Copyright (C) 1992, 1993, Brown University, Providence, RI
;; Developed with support from Motorola Inc.
;; 
;; Permission to use, modify and redistribute this software and its
;; documentation for any purpose other than its incorporation into a
;; commercial product is hereby granted without fee.  A distribution fee
;; may be charged with any redistribution.  Any distribution requires
;; that the above copyright notice appear in all copies, that both that
;; copyright notice and this permission notice appear in supporting
;; documentation, and that neither the name of Brown University nor the
;; author's name be used in advertising or publicity pertaining to
;; distribution of the software without specific, written prior permission.
;; 
;; Brown University makes no representations about the suitability of this
;; software for any purpose.  It is provided "as is" without express or
;; implied warranty.
;;
;; DESCRIPTION:  
;;
;;   Must be loaded AFTER smart-key-mouse-alist has been defined in
;;   "hui-mouse.el".
;;
;;   Handles drags in same window or across windows and modeline depresses.
;;
;; What drags and modeline presses do.
;; ==============================================================================
;; Context                                     Smart Key
;;                                 Primary                    Secondary
;; ==============================================================================
;; Drag horizontally within window
;;     Left to right               Scroll to buffer end       Split window across
;;     Right to left               Scroll to buffer begin     Delete window
;; Click in modeline
;;     Left window edge            Bury buffer                Unbury bottom buffer
;;     Right window edge           Info                       Smart Key Summ
;;     Otherwise                   Smart or popup menus       Popup menus
;; Modeline depress & wind release Resize window height       <- same
;; Drag from shared window side    Resize window's width      <- same
;; Drag from one window to another Create/modify a link but   Swap buffers
;; Drag vertically within window   Split window sideways      <- same
;; Drag diagonally within window   Save ring screen-config    Restore ring config
;;
;; DESCRIP-END.

;;; ************************************************************************
;;; Public variables
;;; ************************************************************************

(defvar sm-mouse-edge-sensitivity 3
  "*Number of characters from screen edges within which a click is considered at an edge.")

(defvar sm-mouse-side-sensitivity 1
  "*Characters in either direction from window side within which a click is considered on the side.")

(defvar sm-mouse-x-drag-sensitivity 3
  "*Number of chars mouse must move horizontally between depress/release to register a horizontal drag.")

(defvar sm-mouse-y-drag-sensitivity 2
  "*Number of lines mouse must move vertically between depress/release to register a vertical drag.")

(defvar sm-mouse-x-diagonal-sensitivity 4
  "*Number of chars mouse must move horizontally between depress/release to register a diagonal drag.")
(defvar sm-mouse-y-diagonal-sensitivity 3
  "*Number of lines mouse must move vertically between depress/release to register a diagonal drag.")

;;;
;;; Add mode line handling to smart-key-mouse-alist dispatch table.
;;;
(if (not (boundp 'smart-key-mouse-alist))
    (error
      "\"hui-modeln.el\": smart-key-mouse-alist must be defined before loading this.")
  (or (memq 'sm-mouse-drag-window-side
	    (mapcar (function (lambda (elt) (let ((pred (car elt)))
					      (if (listp pred) (car pred)))))
		    smart-key-mouse-alist))
      (setq smart-key-mouse-alist
	    (append
	      '(
		((sm-mouse-drag-window-side) .
		 ((sm-mouse-resize-window-side) .
		  (sm-mouse-resize-window-side 'secondary)))
		((setq smart-key-value 
		       (and (not (sm-mouse-drag-between-windows))
			    (sm-mouse-drag-horizontally))) .
		 ((sm-mouse-horizontal) . (sm-mouse-horizontal-meta)))
		((sm-mouse-depress-in-modeline) .
		 ((sm-mouse-modeline) . (sm-mouse-modeline-meta)))
		((sm-mouse-drag-between-windows) .
		 ((hui:link-directly) . (sm-mouse-swap-buffers 'secondary)))
		((sm-mouse-drag-vertically) .
		 ((sm-split-window-horizontally) .
		  (sm-split-window-horizontally)))
		((setq smart-key-value (sm-mouse-drag-diagonally)) .
		 ((wconfig-ring-save) .
		  (wconfig-yank-pop
		    (prefix-numeric-value current-prefix-arg))))
		)
	      smart-key-mouse-alist))))


;;; ************************************************************************
;;; Public functions
;;; ************************************************************************

(defun sm-mouse-depress-in-modeline ()
  "Returns non-nil if Smart Key was depressed on a window mode line.
If free variable 'meta' is non-nil, uses secondary Smart Key."
  (let ((args (if meta *smart-key-meta-depress-args*
		*smart-key-depress-args*)))
    (if hyperb:window-system
      (let* ((w (smart-window-of-coords args))
	     (mode-ln (and w (1- (nth 3 (window-edges w)))))
	     (last-press-y (sm-mouse-y-coord args))
	     )
	(and last-press-y mode-ln (= last-press-y mode-ln))))))

(defun sm-mouse-drag-between-windows ()
  "Returns non-nil if last Smart Key depress and release were in different windows.
If free variable 'meta' is non-nil, uses secondary Smart Key."
  (if meta
      (and smart-key-meta-depress-window smart-key-meta-release-window
	   (not (eq smart-key-meta-depress-window
		    smart-key-meta-release-window)))
    (and smart-key-depress-window smart-key-release-window
	 (not (eq smart-key-depress-window smart-key-release-window)))))

(defun sm-mouse-drag-diagonally ()
  "Returns non-nil iff last Smart Key use was a diagonal drag within a single window.
If free variable 'meta' is non-nil, uses secondary Smart Key.
Value returned is nil if not a diagonal drag, or one of the following symbols
depending on the direction of the drag: southeast, southwest, northwest, northeast."
  (let ((last-depress-x) (last-release-x)
	(last-depress-y) (last-release-y))
    (if meta
	(setq last-depress-x (sm-mouse-x-coord *smart-key-meta-depress-args*)
	      last-release-x (sm-mouse-x-coord *smart-key-meta-release-args*)
	      last-depress-y (sm-mouse-y-coord *smart-key-meta-depress-args*)
	      last-release-y (sm-mouse-y-coord *smart-key-meta-release-args*))
      (setq last-depress-x (sm-mouse-x-coord *smart-key-depress-args*)
	    last-release-x (sm-mouse-x-coord *smart-key-release-args*)
	    last-depress-y (sm-mouse-y-coord *smart-key-depress-args*)
	    last-release-y (sm-mouse-y-coord *smart-key-release-args*)))
    (and last-depress-x last-release-x last-depress-y last-release-y
	 (>= (- (max last-depress-x last-release-x)
		(min last-depress-x last-release-x))
	     sm-mouse-x-diagonal-sensitivity)
	 (>= (- (max last-depress-y last-release-y)
		(min last-depress-y last-release-y))
	     sm-mouse-y-diagonal-sensitivity)
	 (cond
	   ((< last-depress-x last-release-x)
	    (if (< last-depress-y last-release-y)
		'southeast 'northeast))
	   (t (if (< last-depress-y last-release-y)
		  'southwest 'northwest))))))

(defun sm-mouse-drag-horizontally ()
  "Returns non-nil iff last Smart Key use was a horizontal drag within a single window.
If free variable 'meta' is non-nil, uses secondary Smart Key.
Value returned is nil if not a horizontal drag, 'left if drag moved left or
'right otherwise."
  (let ((last-depress-x) (last-release-x)
	(last-depress-y) (last-release-y))
    (if meta
	(setq last-depress-x (sm-mouse-x-coord *smart-key-meta-depress-args*)
	      last-release-x (sm-mouse-x-coord *smart-key-meta-release-args*)
	      last-depress-y (sm-mouse-y-coord *smart-key-meta-depress-args*)
	      last-release-y (sm-mouse-y-coord *smart-key-meta-release-args*))
      (setq last-depress-x (sm-mouse-x-coord *smart-key-depress-args*)
	    last-release-x (sm-mouse-x-coord *smart-key-release-args*)
	    last-depress-y (sm-mouse-y-coord *smart-key-depress-args*)
	    last-release-y (sm-mouse-y-coord *smart-key-release-args*)))
    (and last-depress-x last-release-x last-depress-y last-release-y
	 (>= (- (max last-depress-x last-release-x)
		(min last-depress-x last-release-x))
	     sm-mouse-x-drag-sensitivity)
	 ;; Don't want to register vertical drags here, so ensure any
	 ;; vertical movement was less than the vertical drag sensitivity.
	 (< (- (max last-depress-y last-release-y)
	       (min last-depress-y last-release-y))
	    sm-mouse-y-drag-sensitivity)
	 (if (< last-depress-x last-release-x) 'right 'left))))

(defun sm-mouse-drag-vertically ()
  "Returns non-nil iff last Smart Key use was a vertical drag within a single window.
If free variable 'meta' is non-nil, uses secondary Smart Key.
Value returned is nil if not a vertical line drag, 'up if drag moved up or
'down otherwise."
  (let ((last-depress-x) (last-release-x)
	(last-depress-y) (last-release-y))
    (if meta
	(setq last-depress-x (sm-mouse-x-coord *smart-key-meta-depress-args*)
	      last-release-x (sm-mouse-x-coord *smart-key-meta-release-args*)
	      last-depress-y (sm-mouse-y-coord *smart-key-meta-depress-args*)
	      last-release-y (sm-mouse-y-coord *smart-key-meta-release-args*))
      (setq last-depress-x (sm-mouse-x-coord *smart-key-depress-args*)
	    last-release-x (sm-mouse-x-coord *smart-key-release-args*)
	    last-depress-y (sm-mouse-y-coord *smart-key-depress-args*)
	    last-release-y (sm-mouse-y-coord *smart-key-release-args*)))
    (and last-depress-x last-release-x last-depress-y last-release-y
	 (>= (- (max last-depress-y last-release-y)
		(min last-depress-y last-release-y))
	     sm-mouse-y-drag-sensitivity)
	 ;; Don't want to register horizontal drags here, so ensure any
	 ;; horizontal movement was less than or equal to the horizontal drag
	 ;; sensitivity.
	 (<= (- (max last-depress-x last-release-x)
		(min last-depress-x last-release-x))
	     sm-mouse-x-drag-sensitivity)
	 (if (< last-depress-y last-release-y) 'down 'up))))

(or (fboundp 'abs)
    (defun abs (number)
      "Return the absolute value of NUMBER."
      (cond
	((< number 0)
	 (- 0 number))
	(t number))))

(defun sm-mouse-drag-window-side ()
  "Returns non-nil if Smart Key was dragged from a window side divider.
If free variable 'meta' is non-nil, uses secondary Smart Key."
  (if hyperb:window-system
      (let* ((depress-args (if meta *smart-key-meta-depress-args*
			     *smart-key-depress-args*))
	     (release-args (if meta *smart-key-meta-release-args*
			     *smart-key-release-args*))
	     (w (smart-window-of-coords depress-args))
	     (side-ln (and w (1- (nth 2 (window-edges w)))))
	     (last-press-x   (sm-mouse-x-coord depress-args))
	     (last-release-x (sm-mouse-x-coord release-args))
	     )
	(and last-press-x last-release-x side-ln
	     (/= last-press-x last-release-x)
	     (/= (1+ side-ln) (screen-width))
	     (<= (max (- last-press-x side-ln) (- side-ln last-press-x))
		 sm-mouse-side-sensitivity)))))

(defun sm-split-window-horizontally ()
  "Splits current window in two evenly, side by side.
Beeps and prints message if can't split window further."
  (interactive)
  (let ((window-min-width 5))
    (condition-case ()
	(split-window-horizontally nil)
      (error (progn (beep)
		    (message
		      "(sm-split-window-horizontally): Can't split window further."))))))

(defun sm-split-window-vertically ()
  "Splits current window in two evenly, one above the other.
Beeps and prints message if can't split window further."
  (interactive)
  (let ((window-min-height 2))
    (condition-case ()
	(if (fboundp 'split-window-quietly)
	    (split-window-quietly nil)
	  (split-window-vertically nil))
      (error
	(progn
	  (beep)
	  (message
	    "(sm-split-window-vertically): Can't split window further."))))))

(defun smart-coords-in-window-p (coords window)
  "Tests if COORDS are in WINDOW.  Returns WINDOW if they are, nil otherwise."
  (if hyperb:emacs19-p
      (eq (posn-window (event-start coords)) window)
    (let* ((edges (window-edges window))
	   (w-xmin (nth 0 edges))
	   (w-ymin (nth 1 edges))
	   (w-xmax (nth 2 edges))
	   (w-ymax (nth 3 edges))
	   (x  (sm-mouse-x-coord coords))
	   (y  (sm-mouse-y-coord coords)))
      (and (<= w-xmin x) (<= x w-xmax)
	   (<= w-ymin y) (<= y w-ymax)
	   window))))

(defun smart-window-of-coords (coords)
  "Returns window in which COORDS fall or nil if none.
Ignores minibuffer window."
  (if hyperb:emacs19-p
      (posn-window (event-start coords))
    (let ((window-list (hypb:window-list 'no-minibuf))
	  (window)
	  (w))
      (while (and (not window) window-list)
	(setq w (car window-list)
	      window-list (cdr window-list)
	      window (smart-coords-in-window-p coords w)))
      window)))

;;; ************************************************************************
;;; Private functions
;;; ************************************************************************

(defun sm-mouse-horizontal ()
  "Goes to buffer end if drag was to the right, otherwise goes to beginning."
  (if (eq smart-key-value 'right)
      (end-of-buffer)
    (beginning-of-buffer)))

(defun sm-mouse-horizontal-meta ()
  "Splits window vertically if drag was to the right, otherwise deletes window."
  (if (eq smart-key-value 'right)
      (sm-split-window-vertically)
    (delete-window)))

(defun sm-mouse-modeline ()
  "Handles Smart Key depresses on a window mode line.
If key is:
 (1) clicked on left edge of a window's modeline,
     window's buffer is buried (placed at bottom of buffer list);
 (2) clicked on right edge of a window's modeline,
     the Info buffer is displayed, or if already displayed and the
     modeline clicked belongs to a window displaying Info, the Info
     buffer is hidden;
 (3) clicked anywhere in the middle of a window's modeline,
     a Smart Menu (if available) or a popup menu (if available)
     is displayed;
 (4) dragged vertically from modeline to within a window,
     the modeline is moved to point of key release, thereby resizing
     its window and potentially its vertical neighbors."
  (let ((w (smart-window-of-coords *smart-key-depress-args*)))
    (if w (select-window w))
    (cond ((sm-mouse-modeline-click)
	   (cond ((sm-mouse-release-left-edge)  (bury-buffer))
		 ((sm-mouse-release-right-edge)
		  (if (eq major-mode 'Info-mode)
		      (Info-exit)
		    (info)))
		 (t (if (fboundp 'smart-menu)
			(smart-menu)
		      ;; Use popup menus in future.
		      )
		      )))
	  (t (sm-mouse-modeline-resize-window)))
    ))

(defun sm-mouse-modeline-meta ()
  "Handles secondary Smart Key depresses on a window mode line.
If secondary key is:
 (1) clicked on left edge of a window's modeline,
     bottom buffer in buffer list is unburied and placed in window;
 (2) clicked on right edge of a window's modeline,
     the summary of Smart Key behavior is displayed, or if already
     displayed and the modeline clicked belongs to a window displaying
     the summary, the summary buffer is hidden;
 (3) clicked anywhere in the middle of a window's modeline,
     a popup menu (if available) is displayed;
 (4) dragged vertically from modeline to within a window,
     the modeline is moved to point of key release, thereby resizing
     its window and potentially its vertical neighbors."
  (let ((val)
	(w (smart-window-of-coords *smart-key-meta-depress-args*)))
    (if w (select-window w))
    (cond ((sm-mouse-modeline-click 'secondary)
	   (cond ((sm-mouse-release-left-edge 'secondary)
		  (let* ((bufs (buffer-list))
			 (entry (1- (length bufs))))
		    (while (not (setq val (nth entry bufs)
				      val (and (/= (aref (buffer-name val) 0)
						   ? )
					       val)))
		      (setq entry (1- entry)))
		    (switch-to-buffer val)))
		 ((sm-mouse-release-right-edge 'secondary)
		  (if (equal (buffer-name) (hypb:help-buf-name "Smart"))
		      (smart-key-help-hide)
		    (smart-key-summarize 'current-window)))
		 (t))) ;; Reserved for future popup menus.
	  (t (sm-mouse-modeline-resize-window 'secondary)))))

(defun sm-mouse-modeline-click (&optional secondary)
  "Returns non-nil if last Smart Key depress and release was at same point in a modeline.
Optional SECONDARY non-nil means test for secondary Smart Key click instead."
  ;; Assume depress was in modeline and that any drag has already been handled.
  ;; So just check that release was in modeline.
  (sm-mouse-modeline-release secondary))

(defun sm-mouse-modeline-release (&optional secondary)
  "Returns non-nil if Smart Key was released on a window mode line.
Optional non-nil SECONDARY means test release of secondary Smart Key instead."
  (let ((args (if secondary *smart-key-meta-release-args*
		*smart-key-release-args*)))
    (if (and hyperb:window-system args)
      (let* ((w (smart-window-of-coords args))
	     (mode-ln (and w (1- (nth 3 (window-edges w)))))
	     (last-press-y (sm-mouse-y-coord args))
	     )
	(and last-press-y mode-ln (= last-press-y mode-ln))))))

(defun sm-mouse-modeline-resize-window (&optional secondary)
  "Resizes window whose mode line was depressed upon by the Smart Key.
Optional arg SECONDARY non-nil means use values from secondary Smart Key instead.
Resize amount depends upon the vertical difference between press and release
of the Smart Key."
  (if (not hyperb:window-system)
      nil
    (let* ((owind (selected-window))
	   (window (smart-window-of-coords
		     (if secondary *smart-key-meta-depress-args*
		       *smart-key-depress-args*)))
	   (mode-ln (and window (1- (nth 3 (window-edges window)))))
	   (last-release-y
	     (sm-mouse-y-coord
	       (if secondary *smart-key-meta-release-args*
		 *smart-key-release-args*)))
	   (shrink-amount (- mode-ln last-release-y))
	   )
      ;; Restore position of point prior to Smart key release.
      (if smart-key-release-prev-point
	  (let ((obuf (current-buffer)))
	    (unwind-protect
		(progn
		  (set-buffer (marker-buffer smart-key-release-prev-point))
		  (goto-char (marker-position smart-key-release-prev-point)))
	      (set-buffer obuf))))
      (cond
	((>= (+ mode-ln 2) (screen-height))
	 (error
	   "(sm-mouse-modeline-resize-window): Can't move bottom window on screen."))
	((< (length (hypb:window-list 'no-minibuf)) 2)
	 (error
	   "(sm-mouse-modeline-resize-window): Can't resize sole window on screen."))
	(t (unwind-protect
	       (progn
		 (select-window window)
		 (shrink-window shrink-amount)
		 ;; Keep redisplay from scrolling other window.
		 (select-window (next-window nil 'no-mini))
		 (condition-case ()
		     (scroll-down shrink-amount)
		   (error nil))
		 )
	     (select-window owind)))))))

(defun sm-mouse-release-left-edge (&optional secondary)
  "Returns non-nil if last Smart Key release was at left window edge.
'sm-mouse-edge-sensitivity' value determines how near to actual edge the
release must be."
  (let ((window-left (car (window-edges)))
	(last-release-x
	  (sm-mouse-x-coord
	    (if secondary *smart-key-meta-release-args*
	      *smart-key-release-args*))))
    (and last-release-x (< (- last-release-x window-left) sm-mouse-edge-sensitivity)
	 (>= (- last-release-x window-left) 0))))

(defun sm-mouse-release-right-edge (&optional secondary)
  "Returns non-nil if last Smart Key release was at right window edge.
'sm-mouse-edge-sensitivity' value determines how near to actual edge the
release must be."
  (let ((window-right (nth 2 (window-edges)))
	(last-release-x
	  (sm-mouse-x-coord
	    (if secondary *smart-key-meta-release-args*
	      *smart-key-release-args*))))
    (and last-release-x (>= (+ last-release-x sm-mouse-edge-sensitivity)
			    window-right)
	 (>= (- window-right last-release-x) 0))))

(defun sm-mouse-resize-window-side (&optional secondary)
  "Resizes window whose side was depressed upon by the Smart Key.
Optional arg SECONDARY non-nil means use values from secondary Smart Key instead.
Resize amount depends upon the horizontal difference between press and release
of the Smart Key."
  (if (not hyperb:window-system)
      nil
    (let* ((owind (selected-window))
	   (window (smart-window-of-coords
		     (if secondary *smart-key-meta-depress-args*
		       *smart-key-depress-args*)))
	   (side-ln (and window (1- (nth 2 (window-edges window)))))
	   (last-release-x
	     (sm-mouse-x-coord
	       (if secondary *smart-key-meta-release-args*
		 *smart-key-release-args*)))
	   (shrink-amount (- side-ln last-release-x))
	   )
      ;; Restore position of point prior to Smart key release.
      (if smart-key-release-prev-point
	  (let ((obuf (current-buffer)))
	    (unwind-protect
		(progn
		  (set-buffer (marker-buffer smart-key-release-prev-point))
		  (goto-char (marker-position smart-key-release-prev-point)))
	      (set-buffer obuf))))
      (cond
	((>= (+ side-ln 2) (screen-width))
	 (error
	   "(sm-mouse-resize-window-side): Can't change width of full screen width window."))
	((< (length (hypb:window-list 'no-minibuf)) 2)
	 (error
	   "(sm-mouse-resize-window-side): Can't resize sole window on screen."))
	(t (unwind-protect
	       (progn
		 (select-window window)
		 (shrink-window-horizontally shrink-amount)
		 )
	     (select-window owind)))))))

(defun sm-mouse-swap-buffers (&optional secondary)
  "Swaps buffers in windows selected with last Smart Key depress and release.
If optional arg SECONDARY is non-nil, uses secondary Smart Key."
  (let* ((w1 (if secondary smart-key-meta-depress-window
	       smart-key-depress-window))
	 (w2 (if secondary smart-key-meta-release-window
	       smart-key-release-window))
	 (w1-buf (and w1 (window-buffer w1)))
	 (w2-buf (and w2 (window-buffer w2)))
	 )
    (or (and w1 w2)
	(error "(sm-mouse-swap-buffers): Last depress or release not within a window."))
    ;; Swap window buffers.
    (set-window-buffer w1 w2-buf)
    (set-window-buffer w2 w1-buf)))

(defun sm-mouse-swap-windows (&optional secondary)
  "Swaps windows selected with last Smart Key depress and release.
If optional arg SECONDARY is non-nil, uses secondary Smart Key."
  (let* ((w1 (if secondary smart-key-meta-depress-window
	       smart-key-depress-window))
	 (w2 (if secondary smart-key-meta-release-window
	       smart-key-release-window))
	 (w1-width  (and w1 (window-width w1)))
	 (w1-height (and w1 (window-height w1)))
	 (w2-width  (and w2 (window-width w2)))
	 (w2-height (and w2 (window-height w2)))
	 )
    (or (and w1 w2)
	(error "(sm-mouse-swap-windows): Last depress or release not within a window."))
    (unwind-protect
	(progn
	  (select-window w1)
	  (if (not (= w1-height (screen-height)))
	      (shrink-window (- w1-height w2-height)))
	  (if (not (= w1-width (screen-width)))
	      (shrink-window-horizontally (- w1-width w2-width)))
	  (select-window w2)
	  (setq w2-width (window-width w2)
		w2-height (window-height w2))
	  (if (not (= w2-height (screen-height)))
	      (shrink-window (- w2-height w1-height)))
	  (if (not (= w2-width (screen-width)))
	      (shrink-window-horizontally (- w2-width w1-width)))
	  )
      (select-window w2)
      )))

(defun sm-mouse-x-coord (args)
  "Returns x coordinate in chars from window system dependent ARGS."
  (let ((x (eval (cdr (assoc hyperb:window-system
			     '(("emacs19" . (if (eventp args)
						(+ (car (nth
							 2 (event-start args)))
						   (nth 0 (window-edges
							   (car
							    (car (cdr args))
							    ))))
					      (car args)))
			       ("lemacs" .  (if (eventp args)
						(event-x args)
					      (car args)))
			       ("xterm"  .  (car args))
			       ("epoch"  .  (nth 0 args))   ;; Epoch V4
			       ("sun"    .  (nth 1 args))
			       ("next"   .  (nth 1 args))
			       ("apollo" .  (car args))
			       ))))))
    (if (integerp x) x (error "(sm-mouse-x-coord): invalid X coord: %s" x))))

(defun sm-mouse-y-coord (args)
  "Returns y coordinate in screen lines from window system dependent ARGS."
  (let ((y (eval (cdr (assoc hyperb:window-system
			     '(("emacs19" . (if (eventp args)
						(+ (cdr (nth
							 2 (event-start args)))
						   (nth 1 (window-edges
							   (car
							    (car (cdr args))
							    ))))
					      (cdr args)))
			       ("lemacs" .  (if (eventp args)
						(event-y args)
					      (cdr args)))
			       ("xterm"  .  (nth 1 args))
			       ("epoch"  .  (nth 1 args))   ;; Epoch V4
			       ("sun"    .  (nth 2 args))
			       ("next"   .  (nth 2 args))
			       ("apollo" .  (nth 1 args))
			       ))))))
    (if (integerp y) y (error "(sm-mouse-y-coord): invalid Y coord: %s" y))))


;;; ************************************************************************
;;; Private variables
;;; ************************************************************************


(provide 'hui-window)
