;;; window.el --- GNU Emacs window commands aside from those written in C
;; Copyright (C) 1985, 1989, 1992, 1993, 1994, 2000, 2001, 2002,
-;; 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+;; 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
;; Maintainer: FSF
;; Keywords: internal
;; GNU Emacs 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)
+;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
PROC is called with a window as argument.
Optional second arg MINIBUF t means count the minibuffer window even
-if not active. MINIBUF nil or omitted means count the minibuffer iff
+if not active. MINIBUF nil or omitted means count the minibuffer only if
it is active. MINIBUF neither t nor nil means not to count the
minibuffer even if it is active.
returned.
Optional second arg MINIBUF t means count the minibuffer window even
-if not active. MINIBUF nil or omitted means count the minibuffer iff
+if not active. MINIBUF nil or omitted means count the minibuffer only if
it is active. MINIBUF neither t nor nil means not to count the
minibuffer even if it is active.
"Kill the current buffer and delete the selected window."
(interactive)
(let ((window-to-delete (selected-window))
+ (buffer-to-kill (current-buffer))
(delete-window-hook (lambda ()
(condition-case nil
(delete-window)
(error nil)))))
- (add-hook 'kill-buffer-hook delete-window-hook t t)
- (if (kill-buffer (current-buffer))
- ;; If `delete-window' failed before, we rerun it to regenerate
- ;; the error so it can be seen in the minibuffer.
- (when (eq (selected-window) window-to-delete)
- (delete-window))
- (remove-hook 'kill-buffer-hook delete-window-hook t))))
+ (unwind-protect
+ (progn
+ (add-hook 'kill-buffer-hook delete-window-hook t t)
+ (if (kill-buffer (current-buffer))
+ ;; If `delete-window' failed before, we rerun it to regenerate
+ ;; the error so it can be seen in the echo area.
+ (when (eq (selected-window) window-to-delete)
+ (delete-window))))
+ ;; If the buffer is not dead for some reason (probably because
+ ;; of a `quit' signal), remove the hook again.
+ (condition-case nil
+ (with-current-buffer buffer-to-kill
+ (remove-hook 'kill-buffer-hook delete-window-hook t))
+ (error nil)))))
(defun quit-window (&optional kill window)
"Quit the current buffer. Bury it, and maybe delete the selected frame.
(defvar mouse-autoselect-window-window nil
"Last window recorded by delayed window autoselection.")
-(defvar mouse-autoselect-window-now nil
- "When non-nil don't delay autoselection in `handle-select-window'.")
+(defvar mouse-autoselect-window-state nil
+ "When non-nil, special state of delayed window autoselection.
+Possible values are `suspend' \(suspend autoselection after a menu or
+scrollbar interaction\) and `select' \(the next invocation of
+'handle-select-window' shall select the window immediately\).")
(defun mouse-autoselect-window-cancel (&optional force)
"Cancel delayed window autoselection.
(eq this-command 'scroll-bar-toolkit-scroll)
(memq (nth 4 (event-end last-input-event))
'(handle end-scroll)))
- (setq mouse-autoselect-window-now nil)
+ (setq mouse-autoselect-window-state nil)
(when (timerp mouse-autoselect-window-timer)
(cancel-timer mouse-autoselect-window-timer))
(remove-hook 'pre-command-hook 'mouse-autoselect-window-cancel)))
-(defun mouse-autoselect-window-start (window)
+(defun mouse-autoselect-window-start (mouse-position &optional window suspend)
"Start delayed window autoselection.
-Called when Emacs detects that the mouse has moved to the non-selected
-window WINDOW and the variable `mouse-autoselect-window' has a numeric,
-non-zero value. The return value is non-nil iff delayed autoselection
-started successfully. Delayed window autoselection is canceled when the
-mouse position has stabilized or a command is executed."
- ;; Cancel any active window autoselection.
- (mouse-autoselect-window-cancel t)
- ;; Record current mouse position in `mouse-autoselect-window-position' and
- ;; WINDOW in `mouse-autoselect-window-window'.
- (setq mouse-autoselect-window-position (mouse-position))
- (setq mouse-autoselect-window-window window)
- ;; Install timer which runs `mouse-autoselect-window-select' every
+MOUSE-POSITION is the last position where the mouse was seen as returned
+by `mouse-position'. Optional argument WINDOW non-nil denotes the
+window where the mouse was seen. Optional argument SUSPEND non-nil
+means suspend autoselection."
+ ;; Record values for MOUSE-POSITION, WINDOW, and SUSPEND.
+ (setq mouse-autoselect-window-position mouse-position)
+ (when window (setq mouse-autoselect-window-window window))
+ (setq mouse-autoselect-window-state (when suspend 'suspend))
+ ;; Install timer which runs `mouse-autoselect-window-select' after
;; `mouse-autoselect-window' seconds.
(setq mouse-autoselect-window-timer
(run-at-time
- (abs mouse-autoselect-window) (abs mouse-autoselect-window)
- 'mouse-autoselect-window-select))
- ;; Executing a command cancels window autoselection.
- (add-hook 'pre-command-hook 'mouse-autoselect-window-cancel))
+ (abs mouse-autoselect-window) nil 'mouse-autoselect-window-select)))
(defun mouse-autoselect-window-select ()
"Select window with delayed window autoselection.
If the mouse position has stabilized in a non-selected window, select
-that window. The minibuffer window is selected iff the minibuffer is
+that window. The minibuffer window is selected only if the minibuffer is
active. This function is run by `mouse-autoselect-window-timer'."
(condition-case nil
(let* ((mouse-position (mouse-position))
- (window (window-at (cadr mouse-position) (cddr mouse-position)
- (car mouse-position))))
+ (window
+ (condition-case nil
+ (window-at (cadr mouse-position) (cddr mouse-position)
+ (car mouse-position))
+ (error nil))))
(cond
+ ((or (menu-or-popup-active-p)
+ (and window
+ (not (coordinates-in-window-p (cdr mouse-position) window))))
+ ;; A menu / popup dialog is active or the mouse is on the scroll-bar
+ ;; of WINDOW, temporarily suspend delayed autoselection.
+ (mouse-autoselect-window-start mouse-position nil t))
+ ((eq mouse-autoselect-window-state 'suspend)
+ ;; Delayed autoselection was temporarily suspended, reenable it.
+ (mouse-autoselect-window-start mouse-position))
((and window (not (eq window (selected-window)))
(or (not (numberp mouse-autoselect-window))
(and (> mouse-autoselect-window 0)
;; If `mouse-autoselect-window' is positive, select
;; window if the window is the same as before.
(eq window mouse-autoselect-window-window))
- ;; Otherwise select window iff the mouse is at the same
+ ;; Otherwise select window if the mouse is at the same
;; position as before. Observe that the first test after
- ;; `mouse-autoselect-window-start' usually fails since the
- ;; value of `mouse-autoselect-window-position' recorded there
- ;; is the position where the mouse has entered the new window
- ;; and not necessarily where the mouse has stopped moving.
+ ;; starting autoselection usually fails since the value of
+ ;; `mouse-autoselect-window-position' recorded there is the
+ ;; position where the mouse has entered the new window and
+ ;; not necessarily where the mouse has stopped moving.
(equal mouse-position mouse-autoselect-window-position))
- ;; The minibuffer is a candidate window iff it's active.
+ ;; The minibuffer is a candidate window if it's active.
(or (not (window-minibuffer-p window))
(eq window (active-minibuffer-window))))
- ;; Mouse position has stabilized in non-selected window: Cancel window
- ;; autoselection and try to select that window.
+ ;; Mouse position has stabilized in non-selected window: Cancel
+ ;; delayed autoselection and try to select that window.
(mouse-autoselect-window-cancel t)
;; Select window where mouse appears unless the selected window is the
;; minibuffer. Use `unread-command-events' in order to execute pre-
;; and post-command hooks and trigger idle timers. To avoid delaying
- ;; autoselection again, temporarily set `mouse-autoselect-window-now'
- ;; to t.
+ ;; autoselection again, set `mouse-autoselect-window-state'."
(unless (window-minibuffer-p (selected-window))
- (setq mouse-autoselect-window-now t)
+ (setq mouse-autoselect-window-state 'select)
(setq unread-command-events
(cons (list 'select-window (list window))
unread-command-events))))
(not (numberp mouse-autoselect-window))
(equal mouse-position mouse-autoselect-window-position))
;; Mouse position has either stabilized in the selected window or at
- ;; `mouse-autoselect-window-position': Cancel window autoselection.
+ ;; `mouse-autoselect-window-position': Cancel delayed autoselection.
(mouse-autoselect-window-cancel t))
(t
- ;; Mouse position has not stabilized yet, record new mouse position in
- ;; `mouse-autoselect-window-position' and any window at that position
- ;; in `mouse-autoselect-window-window'.
- (setq mouse-autoselect-window-position mouse-position)
- (setq mouse-autoselect-window-window window))))
+ ;; Mouse position has not stabilized yet, resume delayed
+ ;; autoselection.
+ (mouse-autoselect-window-start mouse-position window))))
(error nil)))
(defun handle-select-window (event)
(minibuffer-window-active-p window)))
(unless (and (numberp mouse-autoselect-window)
(not (zerop mouse-autoselect-window))
- (not mouse-autoselect-window-now)
- ;; When `mouse-autoselect-window' has a numeric, non-zero
- ;; value, delay window autoselection by that value.
- ;; `mouse-autoselect-window-start' returns non-nil iff it
- ;; successfully installed a timer for this purpose.
- (mouse-autoselect-window-start window))
- ;; Re-enable delayed window autoselection.
- (setq mouse-autoselect-window-now nil)
+ (not (eq mouse-autoselect-window-state 'select))
+ (progn
+ ;; Cancel any delayed autoselection.
+ (mouse-autoselect-window-cancel t)
+ ;; Start delayed autoselection from current mouse position
+ ;; and window.
+ (mouse-autoselect-window-start (mouse-position) window)
+ ;; Executing a command cancels delayed autoselection.
+ (add-hook
+ 'pre-command-hook 'mouse-autoselect-window-cancel)))
+ ;; Reset state of delayed autoselection.
+ (setq mouse-autoselect-window-state nil)
(when mouse-autoselect-window
;; Run `mouse-leave-buffer-hook' when autoselecting window.
(run-hooks 'mouse-leave-buffer-hook))