;;; cursor-chg.el --- Change cursor dynamically, depending on the context. ;; ;; Filename: cursor-chg.el ;; Description: Change cursor dynamically, depending on the context. ;; Author: Drew Adams ;; Maintainer: Drew Adams ;; Copyright (C) 2006-2009, Drew Adams, all rights reserved. ;; Created: Tue Aug 29 11:23:06 2006 ;; Version: 20.1 ;; Last-Updated: Sat Aug 1 15:14:46 2009 (-0700) ;; By: dradams ;; Update #: 191 ;; URL: http://www.emacswiki.org/cgi-bin/wiki/cursor-chg.el ;; Keywords: cursor, accessibility ;; Compatibility: GNU Emacs: 20.x, 21.x, 22.x, 23.x ;; ;; Features that might be required by this library: ;; ;; None ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Commentary: ;; ;; This library provides three kinds of changes to the text cursor: ;; ;; 1. When a buffer is read-only or is in overwrite mode, the cursor ;; type changes to `curchg-overwrite/read-only-cursor-type'. This ;; is controlled by command `change-cursor-mode' and user option ;; `curchg-change-cursor-on-overwrite/read-only-flag'. ;; ;; 2. When an input method is in use, the cursor color changes to ;; `curchg-input-method-cursor-color'. This is controlled by ;; command `change-cursor-mode' and user option ;; `curchg-change-cursor-on-input-method-flag'. ;; ;; 3. When Emacs is idle, the cursor type changes to ;; `curchg-idle-cursor-type'. This is controlled by command ;; `toggle-cursor-type-when-idle'. ;; ;; To turn on all three types of cursor change by default, put the ;; following in your Emacs init file (~/.emacs): ;; ;; (require 'cursor-chg) ; Load this library ;; (change-cursor-mode 1) ; On for overwrite/read-only/input mode ;; (toggle-cursor-type-when-idle 1) ; On when idle ;; ;; Note: Library `oneonone.el' provides the same functionality as ;; library `cursor-chg.el', and more. If you use library ;; `oneonone.el', then do NOT also use library `cursor-chg.el'. ;; ;; Note for Emacs 20: There is a bug in Emacs 20 which can lead to a ;; fatal error (Emacs crash) when using `query-replace' with ;; idle-cursor change enabled. If you use Emacs 20, then consider ;; using `toggle-cursor-type-when-idle' to disable idle-cursor change ;; while you use `query-replace'. ;; ;; User options defined here: ;; ;; `curchg-change-cursor-on-input-method-flag', ;; `curchg-change-cursor-on-overwrite/read-only-flag', ;; `curchg-default-cursor-color', `curchg-default-cursor-type', ;; `curchg-idle-cursor-type', `curchg-input-method-cursor-color', ;; `curchg-overwrite/read-only-cursor-type'. ;; ;; Commands defined here: ;; ;; `change-cursor-mode', `curchg-change-cursor-when-idle-interval', ;; `curchg-set-cursor-type', `curchg-toggle-cursor-type-when-idle', ;; `set-cursor-type', `toggle-cursor-type-when-idle'. ;; ;; Internal variables defined here: ;; ;; `curchg-change-cursor-when-idle-p', `curchg-idle-interval', ;; `curchg-idle-timer', `curchg-last-cursor-type'. ;; ;; Non-interactive functions defined here: ;; ;; `curchg-change-cursor-on-input-method', ;; `curchg-change-cursor-on-overwrite/read-only', ;; `curchg-change-cursor-to-idle-type', ;; `curchg-change-cursor-to-idle-type-off'. ;; ;; Acknowledgements: ;; ;; The cursor-changing on input method and read-only was inspired by ;; Juri Linkov . Joe Casadonte ;; wrote a similar hook (`joc-cursor-type-set-hook'), which he got ;; from Steve Kemp... ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Change log: ;; ;; 2006/10/28 dadams ;; curchg-default-cursor-color, curchg-input-method-cursor-color: ;; Changed :type to 'color for Emacs 21+. ;; 2006/09/04 dadams ;; curchg-idle-timer: Cancel beforehand, and cancel after defining. ;; curchg-toggle-cursor-type-when-idle: ;; Use curchg-change-cursor-to-idle-type-off on pre-command-hook. ;; Don't read an event; just turn it on. ;; Added: curchg-change-cursor-to-idle-type-off. ;; 2006/09/03 dadams ;; Created. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; 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, 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; see the file COPYING. If not, write to ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth ;; Floor, Boston, MA 02110-1301, USA. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Code: ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;------- User Options ------------------------------------- ;; Emacs 20 only (unless (fboundp 'define-minor-mode) (defcustom change-cursor-mode nil "*Toggle changing cursor type and color. Setting this variable directly does not take effect; use either \\[customize] or command `change-cursor-mode'." :set (lambda (symbol value) (change-cursor-mode (if value 1 -1))) :initialize 'custom-initialize-default :type 'boolean :group 'cursor :require 'cursor-chg)) (defcustom curchg-change-cursor-on-input-method-flag t "*Non-nil means to use a different cursor when using an input method." :type 'boolean :group 'cursor) (defcustom curchg-change-cursor-on-overwrite/read-only-flag t "*Non-nil means use a different cursor for overwrite mode or read-only." :type 'boolean :group 'cursor) (defcustom curchg-default-cursor-color (or (cdr (assq 'cursor-color default-frame-alist)) "Red") "*Default text cursor color for non-special frames." :type (if (>= emacs-major-version 21) 'color 'string) :group 'cursor) (defcustom curchg-default-cursor-type 'bar "*Default text cursor type." :type 'symbol :group 'cursor) (defcustom curchg-idle-cursor-type 'box "*Text cursor type when Emacs is idle." :type 'symbol :group 'cursor) (defcustom curchg-input-method-cursor-color "Orange" "*Default cursor color if using an input method. This has no effect if `curchg-change-cursor-on-input-method-flag' is nil." :type (if (>= emacs-major-version 21) 'color 'string) :group 'cursor) (defcustom curchg-overwrite/read-only-cursor-type 'box "*Default text cursor type for overwrite mode or read-only buffer. This applies only to non-special frames. This has no effect if `curchg-change-cursor-on-overwrite/read-only-flag' is nil." :type 'symbol :group 'cursor) ;;------- Internal Variables ------------------------------- (defvar curchg-last-cursor-type curchg-default-cursor-type "Saved last cursor type.") (defvar curchg-idle-interval 2 "Number of seconds to wait before changing to alternate cursor type. The alternate cursor type is `curchg-idle-cursor-type'. Do NOT change this yourself to change the wait period; instead, use `\\[curchg-change-cursor-when-idle-interval]'.") (defvar curchg-idle-timer (progn ; Cancel to prevent duplication. (when (boundp 'curchg-idle-timer) (cancel-timer curchg-idle-timer)) (run-with-idle-timer curchg-idle-interval t 'curchg-change-cursor-to-idle-type)) "Timer used to change the cursor to alternate type when Emacs is idle.") ;; Turn it off, by default. You must use `toggle-cursor-type-when-idle' to turn it on. (cancel-timer curchg-idle-timer) (defvar curchg-change-cursor-when-idle-p nil "Non-nil means to use an alternate cursor type whenever Emacs is idle. Do NOT change this yourself; instead, use `\\[toggle-cursor-type-when-idle]'.") ;;------- Commands ----------------------------------------- (unless (fboundp 'set-cursor-type) (defalias 'set-cursor-type 'curchg-set-cursor-type)) ;; This is essentially from Juri Linkov . (defun curchg-set-cursor-type (cursor-type) "Set the cursor type of the selected frame to CURSOR-TYPE. When called interactively, prompt for the type to use. To get the frame's current cursor type, use `frame-parameters'." (interactive (list (intern (completing-read "Cursor type: " (mapcar 'list '("box" "hollow" "bar" "hbar" nil)))))) (modify-frame-parameters (selected-frame) (list (cons 'cursor-type cursor-type)))) (defalias 'toggle-cursor-type-when-idle 'curchg-toggle-cursor-type-when-idle) (defun curchg-toggle-cursor-type-when-idle (&optional arg) "Turn on or off automatically changing cursor type when Emacs is idle. When on, use `curchg-idle-cursor-type' whenever Emacs is idle. With prefix argument, turn on if ARG > 0; else turn off." (interactive "P") (setq curchg-change-cursor-when-idle-p (if arg (> (prefix-numeric-value arg) 0) (not curchg-change-cursor-when-idle-p))) (cond (curchg-change-cursor-when-idle-p (timer-activate-when-idle curchg-idle-timer) (add-hook 'pre-command-hook 'curchg-change-cursor-to-idle-type-off) (message "Turned ON changing cursor when Emacs is idle.")) (t (cancel-timer curchg-idle-timer) (remove-hook 'pre-command-hook 'curchg-change-cursor-to-idle-type-off) (message "Turned OFF changing cursor when Emacs is idle.")))) (defun curchg-change-cursor-when-idle-interval (secs) "Set wait until automatically change cursor type when Emacs is idle. Whenever Emacs is idle for this many seconds, the cursor type will change to `curchg-idle-cursor-type'. To turn on or off automatically changing the cursor type when idle, use `\\[toggle-cursor-type-when-idle]." (interactive "nSeconds to idle, before changing cursor type: ") (timer-set-idle-time curchg-idle-timer (setq curchg-idle-interval secs) t)) (if (fboundp 'define-minor-mode) ;; Emacs 21 and later. (define-minor-mode change-cursor-mode "Toggle changing cursor type and color. With numeric ARG, turn cursor changing on if and only if ARG is positive. When this mode is on, `curchg-change-cursor-on-input-method' and `curchg-change-cursor-on-overwrite/read-only-flag' control cursor changing." :init-value nil :global t :group 'frames :link `(url-link :tag "Send Bug Report" ,(concat "mailto:" "drew.adams" "@" "oracle" ".com?subject=\ cursor-chg.el bug: \ &body=Describe bug here, starting with `emacs -q'. \ Don't forget to mention your Emacs and library versions.")) :link '(url-link :tag "Other Libraries by Drew" "http://www.emacswiki.org/cgi-bin/wiki/DrewsElispLibraries") :link '(url-link :tag "Download" "http://www.emacswiki.org/cgi-bin/wiki/cursor-chg.el") :link '(url-link :tag "Description" "http://www.emacswiki.org/cgi-bin/wiki/ChangingCursorDynamically") :link '(emacs-commentary-link :tag "Commentary" "cursor-chg") (cond (change-cursor-mode (if curchg-change-cursor-on-overwrite/read-only-flag (add-hook 'post-command-hook 'curchg-change-cursor-on-overwrite/read-only) (curchg-set-cursor-type curchg-default-cursor-type) (remove-hook 'post-command-hook 'curchg-change-cursor-on-overwrite/read-only)) (if curchg-change-cursor-on-input-method-flag (add-hook 'post-command-hook 'curchg-change-cursor-on-input-method) (setq current-input-method nil) (curchg-change-cursor-on-input-method) (remove-hook 'post-command-hook 'curchg-change-cursor-on-input-method))) (t (curchg-set-cursor-type curchg-default-cursor-type) (setq current-input-method nil) (curchg-change-cursor-on-input-method) (remove-hook 'post-command-hook 'curchg-change-cursor-on-overwrite/read-only) (remove-hook 'post-command-hook 'curchg-change-cursor-on-input-method)))) ;; Emacs 20 (defun change-cursor-mode (&optional arg) "Toggle changing cursor type and color. With numeric ARG, turn cursor changing on if and only if ARG is positive. When this mode is on, `curchg-change-cursor-on-input-method' and `curchg-change-cursor-on-overwrite/read-only-flag' control cursor changing." (interactive "P") (setq change-cursor-mode (if arg (> (prefix-numeric-value arg) 0) (not change-cursor-mode))) (cond (change-cursor-mode (if curchg-change-cursor-on-overwrite/read-only-flag (add-hook 'post-command-hook 'curchg-change-cursor-on-overwrite/read-only) (curchg-set-cursor-type curchg-default-cursor-type) (remove-hook 'post-command-hook 'curchg-change-cursor-on-overwrite/read-only)) (if curchg-change-cursor-on-input-method-flag (add-hook 'post-command-hook 'curchg-change-cursor-on-input-method) (setq current-input-method nil) (curchg-change-cursor-on-input-method) (remove-hook 'post-command-hook 'curchg-change-cursor-on-input-method)) (message "Change cursor on overwrite/read-only: %s; on input method: %s" (if curchg-change-cursor-on-overwrite/read-only-flag "ON" "OFF") (if curchg-change-cursor-on-input-method-flag "ON" "OFF"))) (t (curchg-set-cursor-type curchg-default-cursor-type) (setq current-input-method nil) (curchg-change-cursor-on-input-method) (remove-hook 'post-command-hook 'curchg-change-cursor-on-overwrite/read-only) (remove-hook 'post-command-hook 'curchg-change-cursor-on-input-method) (message "Turned OFF changing cursor on overwrite/read-only and input method"))))) ;;------- Non-Interactive Functions ------------------------ ;; This is inspired by code from Juri Linkov . (defun curchg-change-cursor-on-input-method () "Set cursor type depending on whether an input method is used or not." (set-cursor-color (if current-input-method curchg-input-method-cursor-color curchg-default-cursor-color))) ;; This is from Juri Linkov , with read-only added. (defun curchg-change-cursor-on-overwrite/read-only () "Set cursor type differently for overwrite mode and read-only buffer. That is, use one cursor type for overwrite mode and read-only buffers, and another cursor type otherwise." (curchg-set-cursor-type (if (or buffer-read-only overwrite-mode) curchg-overwrite/read-only-cursor-type curchg-default-cursor-type))) (defun curchg-change-cursor-to-idle-type () "Change the cursor to `curchg-idle-cursor-type' when Emacs is idle." (let ((type (cdr (assoc 'cursor-type (frame-parameters))))) (unless (eq type curchg-idle-cursor-type) (setq curchg-last-cursor-type type) (curchg-set-cursor-type curchg-idle-cursor-type)))) (defun curchg-change-cursor-to-idle-type-off () "Turn off changing the cursor to `curchg-idle-cursor-type' when idle." (when curchg-last-cursor-type (curchg-set-cursor-type curchg-last-cursor-type))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (provide 'cursor-chg) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; cursor-chg.el ends here