Hi, I'll post here my updated version of stop-focus instead of the wiki because it needs a small patch ( http://sawfish.wikia.com/wiki/Slide-window-hook ) that I recently proposed (yesterday ^__^). It could interest the persons that use a "sloppy" focus mode (enter-only, stop-focus) as it tries to solve all the invariants that change the windows position not introduced by a mouse movement, like windows unmapping, change of desktop, moving resizing a window with the keyboard.
I've found at least a couple of corner cases: Firefox child windows seems to confuse it when the pointer is not inside the Firefox window and, with my current configuration, unmapping/closing a windows, the expected window is not focused (the next MRU window). I've found yesterday that this doesn't happen with Sawfish running alone (i.e. not in a Gnome session) and with a clean configuration, so probably I can try to isolate why it fails. I don't consider it perfect yet but, IMHO, it's an improvement to the default enter-only focus mode (and without using warp-pointer hacks).. ;;;; stop-focus.jl -- focuses a window when the cursor enters the ;;;; window and remains stationary for a period of time. ;; Copyright (C) 2000 John Kodis <[email protected]>. The sawfish ;; stop-focus.jl module is based on hover-focus.jl by Nils Barth, ;; which was influenced by scwm's hover-focus.scm by John Kodis and ;; Greg Badros, which was in turn based on scwm's auto-raise.scm by ;; Maciej Stachowiak and Greg Badros. That's one hell of a pedigree ;; for a hundred lines of code. ;; Andrea Vettorello <[email protected]>, september 2008. ;; Now, a window is focused only as result of a mouse motion. To ;; achive that, the pointer position is updated and checked not only ;; on window enter events, as in the original version, but also on ;; workspace change, window unshading, window unmaximizing and window ;; slide. It tries to never focus the desktop when a window is ;; unmapped, but here (using Gnome) this doesn't happen when a window ;; is unmapped and the pointer is on the desktop. If Sawfish is ;; running alone it works as expected. I should try to isolate the ;; issue. Finally I hacked a way to enable click to focus, even if I ;; copied more code than I would liked from focus.jl... ;; This file is free software distributed under the terms of the GNU ;; General Public License; either version 2, or (at your option) any ;; later version. You should have received a copy of the GNU General ;; Public License along with sawfish; see the file COPYING. If not, ;; write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA ;; 02139, USA. (require 'timers) (require 'sawfish.wm.util.window-order) (require 'sawfish.wm.focus) (provide 'stop-focus) ;; Variables (defcustom stop-focus-delay 250 "Delay in milliseconds until a window gains focus (in stop-focus mode)." :group (focus) :type number :range (0 . 5000)) (defcustom stop-focus-slop 10 "Distance the cursor can move when stopped (in stop-focus mode)." :group (focus) :type number :range (0 . 5000)) (defvar stop-focus-timer nil) (defvar stop-focus-positions nil) (defvar stop-focus-count nil) (defvar stop-focus-interval nil) ;; Functions ;; motion -- approximates the distance from the eldest saved pointer ;; position to the current pointer location. (defun motion () (let* ((point (query-pointer)) (dx (abs (- (caar stop-focus-positions) (car point)))) (dy (abs (- (cdar stop-focus-positions) (cdr point))))) (+ (max dx dy) (/ (min dx dy) 2)))) ;; stopped-p -- determines if the pointer has stopped, based on motion ;; and allowable position slop. (defun stopped-p () (and (>= (length stop-focus-positions) stop-focus-count) (< (motion) stop-focus-slop))) ;; stop-focus-timer-handler -- focuses a window if stopped, otherwise ;; re-arms timer and pushes a new position onto the position list. (defun stop-focus-timer-handler (w) (if (stopped-p) (when (window-really-wants-input-p w) (grab-server) (set-input-focus w) (ungrab-server)) (set-timer stop-focus-timer 0 stop-focus-interval) (when (>= (length stop-focus-positions) stop-focus-count) (setq stop-focus-positions (cdr stop-focus-positions))) (setq stop-focus-positions (append stop-focus-positions (list (query-pointer)))))) ;; stop-focus-set-timer-values -- tries to split stop-focus-delay into ;; max-count intervals (arbitrarily chosen as 5), unless this would ;; reduce the interval below min-interval (20 ms, intended to reflect what ;; can be scheduled reliably), in which case fewer intervals are used. (defun stop-focus-set-timer-values () (let* ((max-count 5) (min-interval 20) (stop-time stop-focus-delay) (count (max 1 (min max-count (quotient stop-time min-interval)))) (interval (max min-interval (quotient stop-time count)))) (setq stop-focus-count count) (setq stop-focus-interval interval))) ;; stop-focus-enter -- triggered on entering any window in stop-focus ;; mode. Pushes the current pointer on the positions list, computes ;; timer parameters, and starts the focus timer running. (defun stop-focus-enter (w) (if (zerop stop-focus-delay) (when (window-really-wants-input-p w) (grab-server) (set-input-focus w) (ungrab-server)) (unless (eq w (input-focus)) (setq stop-focus-positions (list (query-pointer))) (stop-focus-set-timer-values) (setq stop-focus-timer (make-timer (lambda () (stop-focus-timer-handler w)) 0 stop-focus-interval))))) ;; stop-focus-leave -- cleans up on exiting a window by deleting the ;; focus timer. (defun stop-focus-leave (w) (when stop-focus-timer (delete-timer stop-focus-timer) (setq stop-focus-timer nil))) ;; stop-focus-update-positions -- update the mouse pointer position. (defun stop-focus-update-positions () (setq stop-focus-positions (list (query-pointer)))) (add-hook 'before-slide-hook stop-focus-update-positions) (add-hook 'leave-workspace-hook stop-focus-update-positions) (add-hook 'window-unmaximized-hook stop-focus-update-positions) (add-hook 'shade-window-hook stop-focus-update-positions) (define-focus-mode 'stop-focus (lambda (w action . args) (case action ((pointer-in) (when (window-really-wants-input-p w) (unless (or (desktop-window-p w) (equal (car stop-focus-positions) (query-pointer))) (stop-focus-enter w)))) ((pointer-out) (stop-focus-leave w)) ((enter-root) (unless (input-focus) (window-order-focus-most-recent))) ((focus-in) (focus-pop-map w)) ((focus-out add-window) (unless (or (not (window-really-wants-input-p w)) (eq w (input-focus))) (focus-push-map w click-to-focus-map)))))) -- Andrea
