| 1 | ;;; widen-window.el --- Widening selecting window |
|---|
| 2 | |
|---|
| 3 | ;; Copyright (C) 2008 Yuto Hayamizu |
|---|
| 4 | |
|---|
| 5 | ;; Author: Yuto Hayamizu <y.hayamizu@gmail.com> |
|---|
| 6 | ;; Keywords: convenience |
|---|
| 7 | ;; Version: 0.1.0 |
|---|
| 8 | |
|---|
| 9 | ;; This file is free software; you can redistribute it and/or modify |
|---|
| 10 | ;; it under the terms of the GNU General Public License as published by |
|---|
| 11 | ;; the Free Software Foundation; either version 3, or (at your option) |
|---|
| 12 | ;; any later version. |
|---|
| 13 | |
|---|
| 14 | ;; This file is distributed in the hope that it will be useful, |
|---|
| 15 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 16 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 17 | ;; GNU General Public License for more details. |
|---|
| 18 | |
|---|
| 19 | ;; You should have received a copy of the GNU General Public License |
|---|
| 20 | ;; along with GNU Emacs; see the file COPYING. If not, write to |
|---|
| 21 | ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|---|
| 22 | ;; Boston, MA 02110-1301, USA. |
|---|
| 23 | |
|---|
| 24 | ;;; Commentary: |
|---|
| 25 | |
|---|
| 26 | ;; This minor mode, widen window mode, provides a function that widen |
|---|
| 27 | ;; selected window automatically. |
|---|
| 28 | ;; It was tested only on Emacs 22. |
|---|
| 29 | |
|---|
| 30 | ;; In order to use this minor mode, put this file into |
|---|
| 31 | ;; a directory included in load-path, |
|---|
| 32 | ;; and add following code to your .emacs. |
|---|
| 33 | ;; +------------------------+ |
|---|
| 34 | ;; (require 'widen-window) |
|---|
| 35 | ;; (global-widen-window-mode t) |
|---|
| 36 | ;; +------------------------+ |
|---|
| 37 | |
|---|
| 38 | ;; You can change the window size ratio by customizing `ww-ratio'. |
|---|
| 39 | ;; `ww-ratio' must be greater than 0.0 and less than 1.0 . |
|---|
| 40 | |
|---|
| 41 | ;; If you want to avoid widen window mode in a certain |
|---|
| 42 | ;; major mode(say `foo-mode'), customize the variable `ww-nonwide-modes'. |
|---|
| 43 | |
|---|
| 44 | ;; Because this is still early release, sometimes window widening |
|---|
| 45 | ;; might not work even if it should. If you find some functions to be |
|---|
| 46 | ;; advised, add them to `ww-advised-functions'. |
|---|
| 47 | |
|---|
| 48 | ;;; Code: |
|---|
| 49 | |
|---|
| 50 | (require 'easy-mmode) |
|---|
| 51 | (require 'cl) |
|---|
| 52 | |
|---|
| 53 | (defgroup widen-window nil |
|---|
| 54 | "Widen selected window" |
|---|
| 55 | :group 'convenience |
|---|
| 56 | :prefix "widen-window-") |
|---|
| 57 | |
|---|
| 58 | (defcustom ww-ratio 0.625 |
|---|
| 59 | "This is a ratio which the selected window takes up in window subtree." |
|---|
| 60 | :group 'widen-window |
|---|
| 61 | :type 'number |
|---|
| 62 | ) |
|---|
| 63 | |
|---|
| 64 | (defcustom ww-nonwide-modes |
|---|
| 65 | '(dummy1-mode dummy2-mode) |
|---|
| 66 | "Major modes `widen-current-window' cannot run." |
|---|
| 67 | :type '(list symbol) |
|---|
| 68 | :group 'widen-window) |
|---|
| 69 | |
|---|
| 70 | (defcustom ww-height |
|---|
| 71 | t |
|---|
| 72 | "If `ww-height' is non-nil, widen-window for height will work." |
|---|
| 73 | :type '(choice (const :tag "Yes" t) |
|---|
| 74 | (const :tag "No" nil)) |
|---|
| 75 | :group 'widen-window) |
|---|
| 76 | |
|---|
| 77 | (defcustom ww-width |
|---|
| 78 | t |
|---|
| 79 | "If `ww-width' is non-nil, widen-window for width will work." |
|---|
| 80 | :type '(choice (const :tag "Yes" t) |
|---|
| 81 | (const :tag "No" nil)) |
|---|
| 82 | :group 'widen-window) |
|---|
| 83 | |
|---|
| 84 | (defcustom ww-advised-functions |
|---|
| 85 | '(other-window |
|---|
| 86 | split-window |
|---|
| 87 | switch-to-buffer |
|---|
| 88 | mouse-drag-region |
|---|
| 89 | delete-window |
|---|
| 90 | add-change-log-entry-other-window |
|---|
| 91 | ) |
|---|
| 92 | "Functions to be advised. Window widening function `widen-current-window' is fired after advised function was called." |
|---|
| 93 | :type '(list symbol) |
|---|
| 94 | :group 'widen-window) |
|---|
| 95 | |
|---|
| 96 | (defun widen-current-window () |
|---|
| 97 | (interactive) |
|---|
| 98 | |
|---|
| 99 | (unless (minibufferp (current-buffer)) |
|---|
| 100 | (cond |
|---|
| 101 | ((>= 0 ww-ratio) (setq ww-ratio 0.2)) |
|---|
| 102 | ((<= 1 ww-ratio) (setq ww-ratio 0.8))) |
|---|
| 103 | |
|---|
| 104 | (let* ((current-window (selected-window)) |
|---|
| 105 | (window-tree (bw-get-tree (selected-frame)))) |
|---|
| 106 | (when window-tree |
|---|
| 107 | ;; Sometimes, you cannot get correctly resized windows |
|---|
| 108 | ;; by calling ww-subtree only once. |
|---|
| 109 | ;; So ww-subtree is called repeatedly until |
|---|
| 110 | ;; you can get what you want. |
|---|
| 111 | (let ((sizeinfo-history nil) |
|---|
| 112 | (last-sizeinfo nil) |
|---|
| 113 | (windows (window-list nil nil))) |
|---|
| 114 | (while (not (member last-sizeinfo sizeinfo-history)) |
|---|
| 115 | (setq sizeinfo-history |
|---|
| 116 | (cons last-sizeinfo sizeinfo-history)) |
|---|
| 117 | (setq last-sizeinfo |
|---|
| 118 | (mapcar (lambda (w) |
|---|
| 119 | (window-edges w)) |
|---|
| 120 | windows)) |
|---|
| 121 | (ww-subtree |
|---|
| 122 | window-tree current-window |
|---|
| 123 | (- (bw-r window-tree) (bw-l window-tree)) |
|---|
| 124 | (- (bw-b window-tree) (bw-t window-tree))) |
|---|
| 125 | ))) |
|---|
| 126 | ))) |
|---|
| 127 | |
|---|
| 128 | (defun ww-bw-wid (window-or-tree) |
|---|
| 129 | (- (bw-r window-or-tree) (bw-l window-or-tree))) |
|---|
| 130 | |
|---|
| 131 | (defun ww-bw-hei (window-or-tree) |
|---|
| 132 | (- (bw-b window-or-tree) (bw-t window-or-tree))) |
|---|
| 133 | |
|---|
| 134 | (defun ww-sign (num) |
|---|
| 135 | (if (>= num 0) |
|---|
| 136 | +1 |
|---|
| 137 | -1)) |
|---|
| 138 | |
|---|
| 139 | (defun ww-adjust-window (wtree delta horiz-p) |
|---|
| 140 | "Smart wrapper of `bw-adjust-window' |
|---|
| 141 | |
|---|
| 142 | If `bw-adjust-window' fails to change the size of a window to specified size(ex. tried too big size), it does nothing (on Emacs22), and `widen-current-window' thinks that resizing iteration was finished, and `widen-current-window' actually does nothing. |
|---|
| 143 | If `ww-adjust-window' fails to resize, it tries smaller change than specified." |
|---|
| 144 | (if horiz-p |
|---|
| 145 | ;; width changes |
|---|
| 146 | (let (last-width) |
|---|
| 147 | (while (> (abs delta) 0) |
|---|
| 148 | (setq last-width (ww-bw-wid wtree)) |
|---|
| 149 | (bw-adjust-window wtree delta horiz-p) |
|---|
| 150 | (let ((wid-change (- (ww-bw-wid wtree) last-width))) |
|---|
| 151 | (if (eq wid-change 0) |
|---|
| 152 | (setq delta (* (ww-sign delta) (floor (* 0.66 (abs delta))))) |
|---|
| 153 | (setq delta (- delta wid-change)))))) |
|---|
| 154 | |
|---|
| 155 | ;; height changes |
|---|
| 156 | (let (last-height) |
|---|
| 157 | (while (> (abs delta) 0) |
|---|
| 158 | (setq last-height (ww-bw-hei wtree)) |
|---|
| 159 | (bw-adjust-window wtree delta horiz-p) |
|---|
| 160 | (let ((hei-change (- (ww-bw-hei wtree) last-height))) |
|---|
| 161 | (if (eq hei-change 0) |
|---|
| 162 | (setq delta (* (ww-sign delta) (floor (* 0.66 (abs delta))))) |
|---|
| 163 | (setq delta (- delta hei-change)))))) |
|---|
| 164 | ) |
|---|
| 165 | ) |
|---|
| 166 | |
|---|
| 167 | (defun ww-subtree (wtree cur-win wid hei) |
|---|
| 168 | (setq wtree (bw-refresh-edges wtree)) |
|---|
| 169 | (unless wid (setq wid (ww-bw-wid wtree))) |
|---|
| 170 | (unless hei (setq hei (ww-bw-hei wtree))) |
|---|
| 171 | (let ((wtree-wid (ww-bw-wid wtree)) |
|---|
| 172 | (wtree-hei (ww-bw-hei wtree))) |
|---|
| 173 | (if (windowp wtree) |
|---|
| 174 | (progn |
|---|
| 175 | (when wid |
|---|
| 176 | (let ((dw (- wid wtree-wid))) |
|---|
| 177 | (when (/= 0 dw) |
|---|
| 178 | (ww-adjust-window wtree dw t)))) |
|---|
| 179 | (when hei |
|---|
| 180 | (let ((dh (- hei wtree-hei))) |
|---|
| 181 | (when (/= 0 dh) |
|---|
| 182 | (ww-adjust-window wtree dh nil)))) |
|---|
| 183 | ) |
|---|
| 184 | (let* ((children (cdr (assq 'childs wtree))) |
|---|
| 185 | (cwin-num (length children)) |
|---|
| 186 | (cwin-bigger-wid wid) |
|---|
| 187 | (cwin-bigger-hei hei) |
|---|
| 188 | (cwin-smaller-wid wid) |
|---|
| 189 | (cwin-smaller-hei hei)) |
|---|
| 190 | (case (bw-dir wtree) |
|---|
| 191 | ((hor) |
|---|
| 192 | (setq cwin-smaller-wid |
|---|
| 193 | (floor (/ (* wtree-wid (- 1 ww-ratio)) |
|---|
| 194 | (- cwin-num 1)))) |
|---|
| 195 | (setq cwin-bigger-wid |
|---|
| 196 | (- wtree-wid (* (- cwin-num 1) |
|---|
| 197 | cwin-smaller-wid)))) |
|---|
| 198 | ((ver) |
|---|
| 199 | (setq cwin-smaller-hei |
|---|
| 200 | (floor (/ (* wtree-hei (- 1 ww-ratio)) |
|---|
| 201 | (- cwin-num 1)))) |
|---|
| 202 | (setq cwin-bigger-hei |
|---|
| 203 | (- wtree-hei (* (- cwin-num 1) |
|---|
| 204 | cwin-smaller-hei))))) |
|---|
| 205 | (dolist (cwin children) |
|---|
| 206 | (if (ww-find-window-in-subtree cwin cur-win) |
|---|
| 207 | (ww-subtree |
|---|
| 208 | cwin cur-win |
|---|
| 209 | (if ww-width cwin-bigger-wid (ww-bw-wid cwin)) |
|---|
| 210 | (if ww-height cwin-bigger-hei (ww-bw-hei cwin))) |
|---|
| 211 | (ww-subtree |
|---|
| 212 | cwin cur-win |
|---|
| 213 | (if ww-width cwin-smaller-wid (ww-bw-wid cwin)) |
|---|
| 214 | (if ww-height cwin-smaller-hei (ww-bw-hei cwin))))) |
|---|
| 215 | )))) |
|---|
| 216 | |
|---|
| 217 | (defun ww-find-window-in-subtree (wt window) |
|---|
| 218 | (block func |
|---|
| 219 | (cond |
|---|
| 220 | ((windowp wt) |
|---|
| 221 | (if (equal wt window) |
|---|
| 222 | window |
|---|
| 223 | nil)) |
|---|
| 224 | (t |
|---|
| 225 | (dolist (subwt (cdr (assq 'childs wt))) |
|---|
| 226 | (let ((ret (ww-find-window-in-subtree subwt window))) |
|---|
| 227 | (when ret |
|---|
| 228 | (return-from func window)))) |
|---|
| 229 | nil)))) |
|---|
| 230 | |
|---|
| 231 | (defun ww-setup-advice () |
|---|
| 232 | (dolist (func ww-advised-functions) |
|---|
| 233 | (when (fboundp func) |
|---|
| 234 | (eval `(defadvice ,func (after widen-window-advice) |
|---|
| 235 | (if (and widen-window-mode (not (memq major-mode ww-nonwide-modes))) |
|---|
| 236 | (widen-current-window)))))) |
|---|
| 237 | (ad-activate-regexp "widen-window")) |
|---|
| 238 | |
|---|
| 239 | (define-minor-mode widen-window-mode |
|---|
| 240 | "Widen Window mode" |
|---|
| 241 | :lighter " WW" |
|---|
| 242 | :group 'widen-window |
|---|
| 243 | (if widen-window-mode |
|---|
| 244 | (progn |
|---|
| 245 | (ww-setup-advice) |
|---|
| 246 | (if (memq major-mode ww-nonwide-modes) |
|---|
| 247 | (widen-window-mode nil))) |
|---|
| 248 | nil)) |
|---|
| 249 | |
|---|
| 250 | (defun widen-window-mode-maybe () |
|---|
| 251 | "Return t if `widen-current-window' can run on current buffer." |
|---|
| 252 | (if (and (not (minibufferp (current-buffer))) |
|---|
| 253 | (not (memq major-mode ww-nonwide-modes))) |
|---|
| 254 | (widen-window-mode t))) |
|---|
| 255 | |
|---|
| 256 | (define-global-minor-mode global-widen-window-mode |
|---|
| 257 | widen-window-mode widen-window-mode-maybe |
|---|
| 258 | :group 'widen-window) |
|---|
| 259 | |
|---|
| 260 | ;;; for anything.el |
|---|
| 261 | ;; (defadvice anything (around disable-ww-mode activate) |
|---|
| 262 | ;; (ad-deactivate-regexp "widen-window") |
|---|
| 263 | ;; (unwind-protect |
|---|
| 264 | ;; ad-do-it |
|---|
| 265 | ;; (ad-activate-regexp "widen-window"))) |
|---|
| 266 | |
|---|
| 267 | ;; (if (fboundp 'anything) |
|---|
| 268 | ;; (ad-activate-regexp "disable-ww-mode")) |
|---|
| 269 | |
|---|
| 270 | (provide 'widen-window) |
|---|
| 271 | ;;; widen-window.el ends here |
|---|