;;; follow-mouse.el --- Automatically select the window under the mouse -*-unibyte: t; coding: iso-8859-1;-*-

;; Copyright ? 1998,2000,2003 Kevin Rodgers

;; Author: Kevin Rodgers <>
;; Created: 12 May 1998
;; Version: $Revision: 1.17 $
;; Keywords: mouse
;; RCS: $Id: follow-mouse.el,v 1.17 2003/08/14 19:54:07 kevinr Exp kevinr $

;; 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
;; 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., 59 Temple Place, Suite 330, Boston,
;; MA 02111-1307 USA

;;; Commentary:

;; 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.

;;; Code:

(provide 'follow-mouse)

(require 'custom)			; defgroup, defcustom

(defgroup follow-mouse nil
  "Automatically select the window under the mouse."
  :group '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.")

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

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

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

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

(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)
      ;; Toggle it:
	(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]
	      (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:

(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
  (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))
			(windowp event-window)
			(or (not (window-minibuffer-p event-window))
			    (minibuffer-window-active-p event-window)))
		     (or (eq (window-buffer current-window)
			     (window-buffer event-window))
			 (run-hooks 'mouse-leave-buffer-hook))
		     (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