;;; -*-unibyte: t;-*-

;;;; follow-mouse.el -- Automatically select the window under the mouse.

;;; RCS $Id: follow-mouse.el,v 1.1 2002/07/21 14:05:54 joerg Exp $

;;; Description:
;;; By default, a window within an Emacs frame must be selected by
;;; typing `C-x o' (other-window) or by clicking [mouse-1] on the mode
;;; line or the buffer itself (mouse-set-point); this corresponds to a
;;; "click to type" window manager policy.  follow-mouse.el implements a
;;; "focus follows mouse" window manager policy, so that a window is
;;; selected when the mouse moves over it.
;;; 
;;; To enable follow-mouse, put this in your ~/.emacs file:
;;;     (turn-on-follow-mouse)
;;; 
;;; follow-mouse can be enabled or disabled interactively with the
;;; `M-x turn-on-follow-mouse', `M-x turn-off-follow-mouse', and
;;; `M-x toggle-follow-mouse' commands.
;;; 
;;; By default, follow-mouse will deselect an active minibuffer window;
;;; to prevent that, just unset the
;;; `follow-mouse-deselect-active-minibuffer' option.
;;; 
;;; By default, follow-mouse also raises the frame whose window is
;;; selected; to disable that, just unset the
;;; `follow-mouse-auto-raise-frame' option.

;;; Copyright:
;;; 
;;; Copyright © 1998,2000 Kevin Rodgers
;;; 
;;; This program 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 of the License, or
;;; at your option) any later version.
;;; 
;;; This program 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 this program; if not, write to the Free Software
;;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
;;; 
;;; My employer (Information Handling Services) has not disclaimed any
;;; copyright interest in follow-mouse.el.
;;; 
;;; Kevin Rodgers <kevinr@ihs.com>          Lead Software Engineer
;;; Information Handling Services           Electronic Systems Development
;;; 15 Inverness Way East, M/S A114         GO BUFFS!
;;; Englewood CO 80112-5776 USA             1+ (303) 397-2807

;;; LCD Archive Entry:
;;; 
;;; follow-mouse|Kevin Rodgers|kevinr@ihs.com|
;;; Automatically select the window under the mouse|
;;; $Date: 2002/07/21 14:05:54 $|$Revision: 1.1 $||

;;; Code:
(provide 'follow-mouse)

(defvar follow-mouse nil
  "If non-nil, `\\<special-event-map>\\[follow-mouse-select-window]' \
selects the window under the mouse.
Don't set this variable directly; use `\\[toggle-follow-mouse]' instead")

(defvar follow-mouse-deselect-active-minibuffer t
  "*If non-nil, `\\<special-event-map>\\[follow-mouse-select-window]' \
deselects an active minibuffer window.")
(put 'follow-mouse-deselect-active-minibuffer 'variable-interactive
     "XLeave active minibuffer window? (t or nil): ")

(defvar follow-mouse-auto-raise-frame t
  "*If non-nil, `\\<special-event-map>\\[follow-mouse-select-window]' \
raises the frame as well.")
(put 'follow-mouse-auto-raise-frame 'variable-interactive
     "XAutomatically raise the selected window's frame? (t or nil): ")

;;;###autoload
(defun turn-on-follow-mouse ()
  "Moving the mouse will automatically select the window under it."
  (interactive)
  (toggle-follow-mouse 1 (interactive-p)))

;;;###autoload
(defun turn-off-follow-mouse ()
  "Moving the mouse will not automatically select the window under it."
  (interactive)
  (toggle-follow-mouse 0 (interactive-p)))

;;;###autoload
(defun toggle-follow-mouse (&optional arg verbose)
  "Toggle whether moving the mouse automatically selects the window under it.
If the optional prefix ARG is specified, follow-mouse is enabled if it is
positive, and disabled otherwise.  If called interactively, or the optional
VERBOSE argument is non-nil, display a confirmation message."
  (interactive (list current-prefix-arg t))
  (if (or (null arg)
          (if (> (prefix-numeric-value arg) 0)
              (not follow-mouse)
            follow-mouse))
      ;; Toggle it:
      (progn
        (cond ((setq follow-mouse (not follow-mouse))
               ;; Save the current value of track-mouse before (re)setting it:
               (put 'follow-mouse 'track-mouse track-mouse)
               (setq track-mouse t)
               ;; Save the current binding of [mouse-movement] before
               ;; (re)binding it:
               (put 'follow-mouse 'mouse-movement
                    (lookup-key special-event-map [mouse-movement]))
               (define-key special-event-map [mouse-movement]
                 'follow-mouse-select-window))
              (t                        ; disable
               ;; Restore the previous value of track-mouse:
               (setq track-mouse (get 'follow-mouse 'track-mouse))
               ;; Restore the previous binding of [mouse-movement]:
               (define-key special-event-map [mouse-movement]
                 (get 'follow-mouse 'mouse-movement))))
        (if (or (interactive-p) verbose)
            (message "Follow mouse is %s"
                     (if follow-mouse "enabled" "disabled"))))
    (if (or (interactive-p) verbose)
        (message "Follow mouse is already %s"
                 (if follow-mouse "enabled" "disabled"))))    
  ;; Return the result:
  follow-mouse)

(defun follow-mouse-select-window (event)
  "*Like `mouse-select-window', if `follow-mouse' is set.
Otherwise, do nothing; in particular, don't generate an error if EVENT
occurs outside a window or in an inactive minibuffer window.
See `follow-mouse-deselect-active-minibuffer' and
`follow-mouse-auto-raise-frame'."
  (interactive "e")
  (prog1 (if follow-mouse
             (let ((current-window (get-buffer-window (current-buffer)))
                   (event-window (posn-window (event-start event))))
               (if (and (or (not (window-minibuffer-p current-window))
                            (not (minibuffer-window-active-p current-window))
                            follow-mouse-deselect-active-minibuffer)
                        (windowp event-window)
                        (or (not (window-minibuffer-p event-window))
                            (minibuffer-window-active-p event-window)))
                   (if follow-mouse-auto-raise-frame
                       (mouse-select-window event)
                     (select-window event-window)))))
    ;; Enable dragging:
    (setq unread-command-events
          (nconc unread-command-events (list event)))))

;;;; follow-mouse.el ends here