Add a couple of exceptions to .gitignore
[packages] / xemacs-packages / zenirc / src / zenirc-popup.el
1 ;;; zenirc-popup.el --- pop up zenirc buffer window on signal
2
3 ;; Copyright (C) 1994, 1995 Noah S. Friedman
4
5 ;; Author: Noah Friedman <friedman@prep.ai.mit.edu>
6 ;; Maintainer: friedman@prep.ai.mit.edu
7 ;; Keywords: extensions
8 ;; Created: 1994-06-23
9
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
13 ;; any later version.
14 ;;
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 ;; GNU General Public License for more details.
19 ;;
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with this program; if not, you can either send email to this
22 ;; program's maintainer or write to: The Free Software Foundation,
23 ;; Inc.; 675 Massachusetts Avenue; Cambridge, MA 02139, USA.
24
25 ;;; Commentary:
26
27 ;; After loading this package, any signal detected by regexps in
28 ;; zenirc-signal-alist will cause zenirc to check if the message was
29 ;; visible in any of the windows on visible frames (or, if running emacs
30 ;; 18, on the single X or terminal frame it supports).  If not, it splits
31 ;; the largest visible window (according to various parameters; see the
32 ;; variables below) and displays the portion of the zenirc buffer with the
33 ;; most recently inserted message.
34
35 ;; This is done rather than moving point in an existing window (if any
36 ;; show the zenirc buffer at all) because it is assumed that if you are
37 ;; elsewhere in the buffer, it is for a reason.  Likewise, it doesn't take
38 ;; over other windows, but creates a new one.
39
40 ;; This functionality can be disabled at any time by disabling
41 ;; zenirc-popup-mode.  This variable can be made buffer-local, but it is
42 ;; not by default.
43
44 ;; You can also choose to create new frames instead of splitting windows.
45
46 ;; Note that throughout this program, the Emacs "frame" terminology is
47 ;; used.  Lucid never switched to the "frame" nomenclature adopted by Emacs
48 ;; after the two sets of sources diverged; it uses "screen" instead.  To
49 ;; ensure that this library works in both versions, this program uses its
50 ;; own aliases for the various frame/screen operations.  However, all
51 ;; variables and functions defined here use the Emacs terminology.
52
53 ;;; Code:
54
55 \f
56 (require 'zenirc)
57
58 (defvar zenirc-popup-mode t
59   "*If non-nil, then display buried zenirc when messages appear.")
60
61 (defvar zenirc-popup-ratio 4
62   "*Reciprocal proportion of a window to use up when splitting windows.
63 This value should be an integer greater than zero.
64
65 This variable is used to determine how much of an old window to use
66 for the new one.  The reciprocal is used, so a value of 1 causes the window
67 to appear full-screen, 2 makes the window half of the screen, 3 makes it
68 one third, etc.
69
70 See the documentation for the function `zenirc-popup-window' for more info.")
71
72 (defvar zenirc-popup-min-height (default-value 'window-min-height)
73   "*Minimum height of popup windows, expressed as an integer.
74 When splitting windows, zenirc-popup-ratio is used to determined its size.
75 However, the actual height of the new window will be no less than the
76 number of lines specified by zenirc-popup-min-height or window-min-height,
77 whichever is larger.
78
79 If pop-up-windows is nil, no windows will pop up at all.
80
81 See the documentation for the function `zenirc-popup-window' for more info.")
82
83 (defvar zenirc-popup-available-frames 'visible
84   "*Value used to determine which frames to search for buffer windows.
85
86 This variable determines which frames will be searched to see if a
87 buffer is already visible in a window.  It may be set as follows:
88
89 * If `t', then search all frames.
90 * If `nil', search only current frame.
91 * If `visible', search all frames which are visible
92   (i.e. not iconified or completely obscured).
93 * If `0', search all visible or iconified frames.
94 * If set to a specific frame object, consider only that frame.
95   This is useful if you have a dedicated frame for that process.
96
97 Multiple frames only exist in emacs 19; if using emacs 18, the value of
98 this variable doesn't matter.")
99
100 (defvar zenirc-popup-make-new-frames nil
101   "*If `t' and it is possible to make a new frame to display buffer, do so.
102 The following conditions must be met in order to make a new frame:
103
104 * Both this variable and `pop-up-frames' must be non-`nil'.
105 * No other frame must currently have a window displaying the end of
106   process output for the buffer in question.
107 * It must be possible to create new frames, i.e. in a window system
108   and in a version of emacs which supports multiple frames.
109
110 If you enable the creation of new frames, you may also want to set
111 `zenirc-popup-available-frames' to `t' or `visible' so all interesting frames
112 can be searched first.")
113
114 \f
115 (defun zenirc-popup-mode (&optional prefix)
116   "Enable or disable window popups for a zenirc buffer.
117
118 A negative prefix argument disables this mode.
119 No argument or any non-negative argument enables it.
120
121 The user may also enable or disable this mode simply by setting the
122 variable of the same name.
123
124 This function does nothing to install window-popups for any process; it
125 only determines whether the popup routines will do anything if installed."
126   (interactive "P")
127   (setq zenirc-popup-mode (>= (prefix-numeric-value prefix) 0))
128   (cond ((not (interactive-p)))
129         (zenirc-popup-mode
130          (message "zenirc-popup-mode is enabled"))
131         (t
132          (message "zenirc-popup-mode is disabled")))
133   zenirc-popup-mode)
134
135 \f
136 (defun zenirc-popup (object &optional mark)
137   "Find a window displaying buffer with output from a process, or create one.
138 The following describes the arguments to this function:
139
140 * OBJECT (required)
141   A process object, a buffer, or a buffer name.  If a process, the process
142   should have a buffer associated with it where its output normally goes.
143
144 * MARK   (optional)
145   A marker or a symbol of a variable containing a marker representing the
146   end of the process output, which indicates what portion of the buffer it
147   is desirable to see.
148   Usually this will be the process-mark for the process associated with
149   OBJECT; that is the default if not specified.  If no process exists for
150   OBJECT and no marker is specified, the default is the end of the buffer
151   associated with OBJECT.
152   If MARK is a symbol, it may be a buffer-local variable containing some
153   other arbitrary marker that will be assumed to be the end marker for that
154   buffer.  This may be useful if you have buffers used to interact with a
155   process, but which isn't the primary \"process buffer\".
156
157 If no windows currently display the relevant buffer, or some do but the
158 point of insertion for new output isn't visible in them (perhaps because
159 the window is scrolled to a prior region), zenirc-popup finds the largest
160 visible window and splits it, putting the buffer in the new window at a
161 point showing the new text.
162
163 `zenirc-popup-ratio' is used to determine how much of the old window to use
164 for the creation of a new one.  However, the actual height of the new
165 window will be no less than the number of lines specified by
166 `zenirc-popup-min-height' or `window-min-height', whichever is larger.
167
168 If `pop-up-windows' or `zenirc-popup-mode' are nil, no windows will pop up.
169 The former is an emacs-wide variable; the latter affects only this function."
170   (let* ((orig-window (selected-window))
171          (orig-buffer (current-buffer))
172          (proc (cond ((processp object)
173                       object)
174                      ((or (bufferp object)
175                           (stringp object))
176                       (get-buffer-process object))))
177          (buffer (cond ((processp object)
178                         (process-buffer object))
179                        ((bufferp object)
180                         object)
181                        ((stringp object)
182                         (get-buffer object))))
183          marker pop-up-p found)
184
185     (unwind-protect
186         (progn
187           ;; marker symbol, zenirc-popup-mode, and other zenirc-*
188           ;; parameters may be buffer-local, so do everything in the
189           ;; context of the potential buffer to be popped.
190           (set-buffer buffer)
191
192           (setq pop-up-p (and zenirc-popup-mode pop-up-windows))
193           (setq marker (cond ((null mark)
194                               (process-mark proc))
195                              ((markerp mark)
196                               mark)
197                              ((symbolp mark)
198                               (symbol-value mark))
199                              (t
200                               (point-max))))
201
202           (cond
203            (pop-up-p
204             (walk-windows (function (lambda (win)
205                                       (and (not found)
206                                            (eq (window-buffer win) buffer)
207                                            (<= marker (window-end win))
208                                            (>= marker (window-start win))
209                                            (setq found t))))
210                           nil zenirc-popup-available-frames)
211
212             (cond
213              ((and (not found)
214                    zenirc-popup-make-new-frames
215                    window-system
216                    (boundp 'pop-up-frames)
217                    pop-up-frames
218                    (fboundp 'zenirc-make-frame))
219               (zenirc-popup-frame buffer marker))
220              ((not found)
221               (zenirc-popup-window buffer marker))))))
222       (select-window orig-window)
223       (set-buffer orig-buffer))))
224
225 ;; This function should only be called when the popup-buffer is
226 ;; current; otherwise, buffer-local zenirc-* parameters may not be in
227 ;; effect when referenced.
228 (defun zenirc-popup-window (buffer marker)
229   (let* ((bigwin (if (fboundp 'zenirc-make-frame)
230                      (get-largest-window zenirc-popup-available-frames)
231                    (get-largest-window)))
232          (min-height (max window-min-height
233                           zenirc-popup-min-height))
234          (ratio (cond
235                  ((and (natnump zenirc-popup-ratio)
236                        (> zenirc-popup-ratio 0))
237                   zenirc-popup-ratio)
238                  ;; Choose some ratio too big to be useful.
239                  (t (window-height bigwin)))))
240
241     (split-window bigwin
242                   (min (- (window-height bigwin) min-height)
243                        (- (window-height bigwin)
244                           (/ (window-height bigwin) ratio))))
245
246     (select-window (next-window bigwin 'no-minibuf))
247     ;; Must use switch-to-buffer to make permanent selection of buffer
248     ;; to display in new window.
249     (switch-to-buffer buffer)
250     (goto-char marker)
251     (recenter -1)))
252
253 (defun zenirc-popup-frame (buffer marker)
254   (let ((frame (zenirc-make-frame))
255         (orig-frame (zenirc-selected-frame)))
256     (zenirc-select-frame frame)
257     (set-buffer buffer)
258     (goto-char marker)
259     (recenter -1)
260     (zenirc-select-frame orig-frame)))
261
262 (defun zenirc-signal-popup (proc string)
263   (let ((orig-buffer (current-buffer))
264         marker)
265     (unwind-protect
266         (progn
267           (set-buffer (process-buffer proc))
268           (setq marker zenirc-process-mark))
269       (set-buffer orig-buffer))
270     (zenirc-popup proc marker)))
271
272 \f
273 ;;; Ensure smooth operation in both Emacs and XEmacs/Lucid.
274 ;;; Don't just alias frame equivalent functions because that may
275 ;;; potentially confuse other programs.
276
277 (cond ((fboundp 'make-frame)
278        ;; Emacs 19
279        (defalias 'zenirc-make-frame         'make-frame)
280        (defalias 'zenirc-select-frame       'select-frame)
281        (defalias 'zenirc-selected-frame     'selected-frame))
282
283       ((fboundp 'make-screen)
284        ;; XEmacs
285        (defalias 'zenirc-make-frame         'make-screen)
286        (defalias 'zenirc-select-frame       'select-screen)
287        (defalias 'zenirc-selected-frame     'selected-screen)))
288
289 (provide 'zenirc-popup)
290
291 (zenirc-add-hook 'zenirc-signal-hook 'zenirc-signal-popup)
292
293 ;; zenirc-popup.el ends here