;;; 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
;; 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., 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, `\\\\[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, `\\\\[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, `\\\\[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): ")
;;;###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)))
(progn
(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