From 0245cc374015a67f5c17fec1342c8a35cbd41779 Mon Sep 17 00:00:00 2001 From: Martin Rudalics Date: Thu, 2 Jul 2015 09:03:45 +0200 Subject: [PATCH] Improve accessibility of window dividers. (Bug#20183) * lisp/faces.el (window-divider) (window-divider-first-pixel, window-divider-last-pixel): Change membership from `frames' to `window-divider' customization group. * lisp/frame.el (window-divider): New customization group. (window-divider-mode): New minor mode. (window-divider-default-bottom-width) (window-divider-default-right-width): New options. (frame--window-divider-previous-mode): New variable. (frame-window-divider-width-valid-p) (frame--window-divider-mode-apply) (frame--window-divider-mode-set-and-apply): New functions. * lisp/menu-bar.el (menu-bar-options-save): Save window-divider-mode settings. (menu-bar-window-divider-customize) (menu-bar-bottom-and-right-window-divider) (menu-bar-right-window-divider, menu-bar-bottom-window-divider) (menu-bar-no-window-divider): New functions. (menu-bar-showhide-window-divider-menu): New variable. (menu-bar-showhide-menu): Show/hide window divider menu. * lisp/mouse.el (mouse-split-window-vertically) (mouse-split-window-horizontally): Replace `error' by `user-error'. Bind `window-combination-resize' to nil. (top-level): Add/reorder mouse key bindings on mode- and vertical-line. --- lisp/faces.el | 6 +-- lisp/frame.el | 128 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ lisp/menu-bar.el | 92 ++++++++++++++++++++++++++++++++++++++- lisp/mouse.el | 33 +++++++++----- 4 files changed, 244 insertions(+), 15 deletions(-) diff --git a/lisp/faces.el b/lisp/faces.el index 9857a7bd4de..511b3541265 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -2506,7 +2506,7 @@ is used for the inner part while the first pixel line/column is drawn with the `window-divider-first-pixel' face and the last pixel line/column with the `window-divider-last-pixel' face." :version "24.4" - :group 'frames + :group 'window-divider :group 'basic-faces) (defface window-divider-first-pixel @@ -2517,7 +2517,7 @@ line/column is drawn with the foreground of this face. If you do not want to accentuate the first pixel line/column, set this to the same as `window-divider' face." :version "24.4" - :group 'frames + :group 'window-divider :group 'basic-faces) (defface window-divider-last-pixel @@ -2528,7 +2528,7 @@ line/column is drawn with the foreground of this face. If you do not want to accentuate the last pixel line/column, set this to the same as `window-divider' face." :version "24.4" - :group 'frames + :group 'window-divider :group 'basic-faces) (defface minibuffer-prompt diff --git a/lisp/frame.el b/lisp/frame.el index 077687eeb66..ffa01b4dcc1 100644 --- a/lisp/frame.el +++ b/lisp/frame.el @@ -1749,6 +1749,134 @@ left untouched. FRAME nil or omitted means use the selected frame." 'delete-frame-functions "22.1") +;;; Window dividers. +(defgroup window-divider nil + "Window dividers." + :version "25.1" + :group 'frames + :group 'windows) + +(defvar frame--window-divider-previous-mode nil + "Previous value of `window-divider-mode'. +This is the value seen when `window-divider-mode' was switched +off the last time. It's reused when `window-divider-mode' is +switched on again.") + +(defcustom window-divider-mode nil + "Specify whether to display window dividers and where. +Possible values are nil (no dividers), `bottom-only' (dividers on +the bottom of each window only), `right-only' (dividers on the +right of each window only), and t (dividers on the bottom and on +the right of each window)." + :type '(choice (const :tag "None (nil)" nil) + (const :tag "Bottom only" bottom-only) + (const :tag "Right only" right-only) + (const :tag "Bottom and right" t)) + :initialize 'custom-initialize-default + :set (lambda (_symbol value) + (frame--window-divider-mode-set-and-apply value)) + :group 'window-divider + :version "25.1") + +(define-minor-mode window-divider-mode + "Display dividers between windows (Window Divider mode). +With a prefix argument ARG, enable Window Divider mode if ARG is +positive, and disable it otherwise. If called from Lisp, enable +the mode if ARG is omitted or nil. + +The option `window-divider-default-width' allows to customize the +width of dividers displayed by this mode." + :group 'window-divider + :global t + :variable (window-divider-mode + . (lambda (value) + (frame--window-divider-mode-set-and-apply + (and value + (or frame--window-divider-previous-mode + (default-value 'window-divider-mode) + 'right-only)))))) + +(defun frame-window-divider-width-valid-p (value) + "Return non-nil if VALUE is a positive number." + (and (numberp value) (> value 0))) + +(defcustom window-divider-default-bottom-width 6 + "Default width of dividers on bottom of windows. +The value must be a positive integer and takes effect when bottom +dividers are displayed by `window-divider-mode'. + +To adjust bottom dividers for frames individually, use the frame +parameter `bottom-divider-width'." + :type '(restricted-sexp + :tag "Default bottom divider width" + :match-alternatives (frame-window-divider-width-valid-p)) + :group 'window-divider + :initialize 'custom-initialize-default + :set (lambda (symbol value) + (set-default symbol value) + (when window-divider-mode + (frame--window-divider-mode-apply))) + :version "25.1") + +(defcustom window-divider-default-right-width 6 + "Default width of dividers on the right of windows. +The value must be a positive integer and takes effect when right +dividers are displayed by `window-divider-mode'. + +To adjust right dividers for frames individually, use the frame +parameter `right-divider-width'." + :type '(restricted-sexp + :tag "Default right divider width" + :match-alternatives (frame-window-divider-width-valid-p)) + :group 'window-divider + :initialize 'custom-initialize-default + :set (lambda (symbol value) + (set-default symbol value) + (when window-divider-mode + (frame--window-divider-mode-apply))) + :version "25.1") + +(defun frame--window-divider-mode-apply () + "Apply window divider widths." + (let ((bottom (if (memq window-divider-mode '(bottom-only t)) + window-divider-default-bottom-width + 0)) + (right (if (memq window-divider-mode '(right-only t)) + window-divider-default-right-width + 0))) + (modify-all-frames-parameters + (list (cons 'bottom-divider-width bottom) + (cons 'right-divider-width right))) + (setq default-frame-alist + (assq-delete-all + 'bottom-divider-width default-frame-alist)) + (setq default-frame-alist + (assq-delete-all + 'right-divider-width default-frame-alist)) + (when (> bottom 0) + (setq default-frame-alist + (cons + (cons 'bottom-divider-width bottom) + default-frame-alist))) + (when (> right 0) + (setq default-frame-alist + (cons + (cons 'right-divider-width right) + default-frame-alist))))) + +(defun frame--window-divider-mode-set-and-apply (value) + "Set window divider mode to VALUE and apply widths." + (unless value + ;; Remember current mode. + (setq frame--window-divider-previous-mode window-divider-mode)) + (set-default 'window-divider-mode value) + ;; Pacify customize rigmarole. + (put 'window-divider-mode 'customized-value + (if (memq value '(nil t)) + (list value) + (list (list 'quote value)))) + (frame--window-divider-mode-apply)) + ;; Blinking cursor (defgroup cursor nil diff --git a/lisp/menu-bar.el b/lisp/menu-bar.el index 22a0b8faaba..5a69084f98d 100644 --- a/lisp/menu-bar.el +++ b/lisp/menu-bar.el @@ -683,7 +683,7 @@ by \"Save Options\" in Custom buffers.") (dolist (elt '(scroll-bar-mode debug-on-quit debug-on-error ;; Somehow this works, when tool-bar and menu-bar don't. - tooltip-mode + tooltip-mode window-divider-mode save-place uniquify-buffer-name-style fringe-mode indicate-empty-lines indicate-buffer-boundaries case-fold-search font-use-system-font @@ -711,6 +711,92 @@ by \"Save Options\" in Custom buffers.") ;; The "Show/Hide" submenu of menu "Options" +(defun menu-bar-window-divider-customize () + "Show customization buffer for `window-divider' group." + (interactive) + (customize-group 'window-divider)) + +(defun menu-bar-bottom-and-right-window-divider () + "Display dividers on the bottom and right of each window." + (interactive) + (customize-set-variable 'window-divider-mode t)) + +(defun menu-bar-right-window-divider () + "Display dividers only on the right of each window." + (interactive) + (customize-set-variable 'window-divider-mode 'right-only)) + +(defun menu-bar-bottom-window-divider () + "Display dividers only at the bottom of each window." + (interactive) + (customize-set-variable 'window-divider-mode 'bottom-only)) + +(defun menu-bar-no-window-divider () + "Do not display window dividers." + (interactive) + (customize-set-variable 'window-divider-mode nil)) + +;; For the radio buttons below we check whether the respective dividers +;; are displayed on the selected frame. This is not fully congruent +;; with `window-divder-mode' but makes the menu entries work also when +;; dividers are displayed by manipulating frame parameters directly. +(defvar menu-bar-showhide-window-divider-menu + (let ((menu (make-sparse-keymap "Window Divider"))) + (bindings--define-key menu [customize] + '(menu-item "Customize" menu-bar-window-divider-customize + :help "Customize window dividers" + :visible (memq (window-system) '(x w32)))) + + (bindings--define-key menu [bottom-and-right] + '(menu-item "Bottom and Right" + menu-bar-bottom-and-right-window-divider + :help "Display window divider on the bottom and right of each window" + :visible (memq (window-system) '(x w32)) + :button (:radio + . (and (frame-window-divider-width-valid-p + (cdr (assq 'bottom-divider-width + (frame-parameters)))) + (frame-window-divider-width-valid-p + (cdr (assq 'right-divider-width + (frame-parameters)))))))) + (bindings--define-key menu [right-only] + '(menu-item "Right Only" + menu-bar-right-window-divider + :help "Display window divider on the right of each window only" + :visible (memq (window-system) '(x w32)) + :button (:radio + . (and (not (frame-window-divider-width-valid-p + (cdr (assq 'bottom-divider-width + (frame-parameters))))) + (frame-window-divider-width-valid-p + (cdr (assq 'right-divider-width + (frame-parameters)))))))) + (bindings--define-key menu [bottom-only] + '(menu-item "Bottom Only" + menu-bar-bottom-window-divider + :help "Display window divider on the bottom of each window only" + :visible (memq (window-system) '(x w32)) + :button (:radio + . (and (frame-window-divider-width-valid-p + (cdr (assq 'bottom-divider-width + (frame-parameters)))) + (not (frame-window-divider-width-valid-p + (cdr (assq 'right-divider-width + (frame-parameters))))))))) + (bindings--define-key menu [no-divider] + '(menu-item "None" + menu-bar-no-window-divider + :help "Do not display window dividers" + :visible (memq (window-system) '(x w32)) + :button (:radio + . (and (not (frame-window-divider-width-valid-p + (cdr (assq 'bottom-divider-width + (frame-parameters))))) + (not (frame-window-divider-width-valid-p + (cdr (assq 'right-divider-width + (frame-parameters))))))))) + menu)) + (defun menu-bar-showhide-fringe-ind-customize () "Show customization buffer for `indicate-buffer-boundaries'." (interactive) @@ -1072,6 +1158,10 @@ mail status in mode line")) (frame-visible-p (symbol-value 'speedbar-frame)))))) + (bindings--define-key menu [showhide-window-divider] + `(menu-item "Window Divider" ,menu-bar-showhide-window-divider-menu + :visible (memq (window-system) '(x w32)))) + (bindings--define-key menu [showhide-fringe] `(menu-item "Fringe" ,menu-bar-showhide-fringe-menu :visible (display-graphic-p))) diff --git a/lisp/mouse.el b/lisp/mouse.el index 9bb00cb105e..221d30bc3d8 100644 --- a/lisp/mouse.el +++ b/lisp/mouse.el @@ -338,9 +338,12 @@ This command must be bound to a mouse click." (first-line window-min-height) (last-line (- (window-height) window-min-height))) (if (< last-line first-line) - (error "Window too short to split") - (split-window-vertically - (min (max new-height first-line) last-line)))))) + (user-error "Window too short to split") + ;; Bind `window-combination-resize' to nil so we are sure to get + ;; the split right at the line clicked on. + (let (window-combination-resize) + (split-window-vertically + (min (max new-height first-line) last-line))))))) (defun mouse-split-window-horizontally (click) "Select Emacs window mouse is on, then split it horizontally in half. @@ -354,9 +357,12 @@ This command must be bound to a mouse click." (first-col window-min-width) (last-col (- (window-width) window-min-width))) (if (< last-col first-col) - (error "Window too narrow to split") - (split-window-horizontally - (min (max new-width first-col) last-col)))))) + (user-error "Window too narrow to split") + ;; Bind `window-combination-resize' to nil so we are sure to get + ;; the split right at the column clicked on. + (let (window-combination-resize) + (split-window-horizontally + (min (max new-width first-col) last-col))))))) (defun mouse-drag-line (start-event line) "Drag a mode line, header line, or vertical line with the mouse. @@ -1915,20 +1921,25 @@ choose a font." ;; vertical-line prevents Emacs from signaling an error when the mouse ;; button is released after dragging these lines, on non-toolkit ;; versions. -(global-set-key [mode-line mouse-1] 'mouse-select-window) -(global-set-key [mode-line drag-mouse-1] 'mouse-select-window) -(global-set-key [mode-line down-mouse-1] 'mouse-drag-mode-line) (global-set-key [header-line down-mouse-1] 'mouse-drag-header-line) (global-set-key [header-line mouse-1] 'mouse-select-window) +;; (global-set-key [mode-line drag-mouse-1] 'mouse-select-window) +(global-set-key [mode-line down-mouse-1] 'mouse-drag-mode-line) +(global-set-key [mode-line mouse-1] 'mouse-select-window) (global-set-key [mode-line mouse-2] 'mouse-delete-other-windows) (global-set-key [mode-line mouse-3] 'mouse-delete-window) (global-set-key [mode-line C-mouse-2] 'mouse-split-window-horizontally) (global-set-key [vertical-scroll-bar C-mouse-2] 'mouse-split-window-vertically) -(global-set-key [vertical-line C-mouse-2] 'mouse-split-window-vertically) +(global-set-key [horizontal-scroll-bar C-mouse-2] 'mouse-split-window-horizontally) (global-set-key [vertical-line down-mouse-1] 'mouse-drag-vertical-line) +(global-set-key [vertical-line mouse-1] 'mouse-select-window) +(global-set-key [vertical-line C-mouse-2] 'mouse-split-window-vertically) (global-set-key [right-divider down-mouse-1] 'mouse-drag-vertical-line) +(global-set-key [right-divider mouse-1] 'ignore) +(global-set-key [right-divider C-mouse-2] 'mouse-split-window-vertically) (global-set-key [bottom-divider down-mouse-1] 'mouse-drag-mode-line) -(global-set-key [vertical-line mouse-1] 'mouse-select-window) +(global-set-key [bottom-divider mouse-1] 'ignore) +(global-set-key [bottom-divider C-mouse-2] 'mouse-split-window-horizontally) (provide 'mouse) -- 2.11.4.GIT