* riece-naming.el (riece-naming-assert-join): Rename signal 'join
[elisp/riece.git] / lisp / riece-display.el
1 ;;; riece-display.el --- buffer arrangement
2 ;; Copyright (C) 1998-2003 Daiki Ueno
3
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
5 ;; Created: 1998-09-28
6 ;; Keywords: IRC, riece
7
8 ;; This file is part of Riece.
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 GNU Emacs; see the file COPYING.  If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Code:
26
27 (require 'riece-options)
28 (require 'riece-channel)
29 (require 'riece-misc)
30 (require 'riece-layout)
31
32 (defvar riece-channel-buffer-format "*Channel:%s*"
33   "Format of channel message buffer.")
34 (defvar riece-channel-buffer-alist nil
35   "An alist mapping identities to channel buffers.")
36
37 (defvar riece-update-buffer-functions nil
38   "Functions to redisplay the buffer.
39 Local to the buffer in `riece-buffer-list'.")
40   
41 (defvar riece-update-indicator-functions
42   '(riece-update-status-indicators
43     riece-update-channel-indicator
44     riece-update-long-channel-indicator
45     riece-update-channel-list-indicator)
46   "Functions to update modeline indicators.")
47
48 ;;; Qt like "signal-slot" abstraction for routing display events.
49 (defvar riece-signal-slot-obarray
50   (make-vector 31 0))
51
52 (defun riece-make-slot (function &optional filter handback)
53   "Make an instance of slot object.
54 Arguments are corresponding to callback function, filter function, and
55 a handback object, respectively.
56 This function is for internal use only."
57   (vector function filter handback))
58
59 (defun riece-slot-function (slot)
60   "Return the callback function of SLOT.
61 This function is for internal use only."
62   (aref slot 0))
63
64 (defun riece-slot-filter (slot)
65   "Return the filter function of SLOT.
66 This function is for internal use only."
67   (aref slot 1))
68
69 (defun riece-slot-handback (slot)
70   "Return the handback object of SLOT.
71 This function is for internal use only."
72   (aref slot 2))
73
74 (defun riece-make-signal (name &rest args)
75   "Make an instance of signal object.
76 The 1st arguments is the name of the signal and the rest of arguments
77 are the data of the signal."
78   (vector name args))
79
80 (defun riece-signal-name (signal)
81   "Return the name of SIGNAL."
82   (aref signal 0))
83
84 (defun riece-signal-args (signal)
85   "Return the data of SIGNAL."
86   (aref signal 1))
87
88 (defun riece-connect-signal (signal-name function &optional filter handback)
89   "Add SLOT as a listener of a signal identified by SIGNAL-NAME."
90   (let ((symbol (intern (symbol-name signal-name) riece-signal-slot-obarray)))
91     (set symbol (cons (riece-make-slot function filter handback)
92                       (if (boundp symbol)
93                           (symbol-value symbol))))))
94
95 (defun riece-emit-signal (signal)
96   "Emit SIGNAL."
97   (let ((symbol (intern-soft (symbol-name (riece-signal-name signal))
98                              riece-signal-slot-obarray))
99         slots)
100     (when symbol
101       (setq slots (symbol-value symbol))
102       (while slots
103         (condition-case error
104             (if (or (null (riece-slot-filter (car slots)))
105                     (condition-case error
106                         (funcall (riece-slot-filter (car slots)) signal)
107                       (if riece-debug
108                           (message
109                            "Error occurred in signal filter for \"%S\": %S"
110                            (riece-signal-name signal) error))
111                       nil))
112                 (funcall (riece-slot-function (car slots))
113                          signal (riece-slot-handback (car slots))))
114           (error
115            (if riece-debug
116                (message "Error occurred in slot function for \"%S\": %S"
117                         (riece-signal-name signal) error))))
118         (setq slots (cdr slots))))))
119
120 (defun riece-display-connect-signals ()
121   (riece-connect-signal
122    'riece-switch-to-channel
123    (lambda (signal handback)
124      (riece-update-status-indicators)
125      (riece-update-channel-indicator)
126      (riece-update-long-channel-indicator)
127      (force-mode-line-update t)
128      (save-excursion
129        (set-buffer riece-user-list-buffer)
130        (run-hooks 'riece-update-buffer-functions))
131      (save-excursion
132        (set-buffer riece-channel-list-buffer)
133        (run-hooks 'riece-update-buffer-functions))
134      (save-excursion
135        (riece-redraw-layout))))
136   (riece-connect-signal
137    'riece-naming-assert-channel-users
138    (lambda (signal handback)
139      (save-excursion
140        (set-buffer riece-user-list-buffer)
141        (run-hooks 'riece-update-buffer-functions))))
142   (riece-connect-signal
143    'riece-naming-assert-join
144    (lambda (signal handback)
145      (save-excursion
146        (set-buffer riece-user-list-buffer)
147        (run-hooks 'riece-update-buffer-functions)))
148    (lambda (signal)
149      (and (riece-identity-equal (nth 1 (riece-signal-args signal))
150                                 riece-current-channel)
151           (not (riece-identity-equal (car (riece-signal-args signal))
152                                      (riece-current-nickname))))))
153   (riece-connect-signal
154    'riece-naming-assert-part
155    (lambda (signal handback)
156      (save-excursion
157        (set-buffer riece-user-list-buffer)
158        (run-hooks 'riece-update-buffer-functions)))
159    (lambda (signal)
160      (and (riece-identity-equal (nth 1 (riece-signal-args signal))
161                                 riece-current-channel)
162           (not (riece-identity-equal (car (riece-signal-args signal))
163                                      (riece-current-nickname))))))
164   (riece-connect-signal
165    'riece-naming-assert-rename
166    (lambda (signal handback)
167      (save-excursion
168        (set-buffer riece-user-list-buffer)
169        (run-hooks 'riece-update-buffer-functions)))
170    (lambda (signal)
171      (and (equal (riece-identity-server (nth 1 (riece-signal-args signal)))
172                  (riece-identity-server riece-current-channel))
173           (riece-with-server-buffer (riece-identity-server
174                                      riece-current-channel)
175             (riece-identity-assoc
176              (riece-identity-prefix (nth 1 (riece-signal-args signal)))
177              (riece-channel-get-users (riece-identity-prefix
178                                        riece-current-channel))
179              t)))))
180   (riece-connect-signal
181    'riece-naming-assert-rename
182    (lambda (signal handback)
183      (riece-update-status-indicators)
184      (riece-update-channel-indicator)
185      (force-mode-line-update t))
186    (lambda (signal)
187      (riece-identity-equal (nth 1 (riece-signal-args signal))
188                            (riece-current-nickname))))
189   (riece-connect-signal
190    'riece-user-toggle-away
191    (lambda (signal handback)
192      (riece-update-status-indicators)
193      (force-mode-line-update t))
194    (lambda (signal)
195      (riece-identity-equal (nth 1 (riece-signal-args signal))
196                            (riece-current-nickname))))
197   (riece-connect-signal
198    'riece-user-toggle-operator
199    (lambda (signal handback)
200      (riece-update-status-indicators)
201      (force-mode-line-update t))
202    (lambda (signal)
203      (riece-identity-equal (nth 1 (riece-signal-args signal))
204                            (riece-current-nickname))))
205   (riece-connect-signal
206    'riece-channel-set-topic
207    (lambda (signal handback)
208      (riece-update-long-channel-indicator)
209      (force-mode-line-update t))
210    (lambda (signal)
211      (riece-identity-equal (car (riece-signal-args signal))
212                            riece-current-channel)))
213   (riece-connect-signal
214    'riece-channel-toggle-modes
215    (lambda (signal handback)
216      (riece-update-status-indicators)
217      (force-mode-line-update t))
218    (lambda (signal)
219      (riece-identity-equal (car (riece-signal-args signal))
220                            riece-current-channel)))
221   (riece-connect-signal
222    'riece-channel-toggle-operator
223    (lambda (signal handback)
224      (save-excursion
225        (set-buffer riece-user-list-buffer)
226        (run-hooks 'riece-update-buffer-functions)))
227    (lambda (signal)
228      (riece-identity-equal (car (riece-signal-args signal))
229                            riece-current-channel)))
230   (riece-connect-signal
231    'riece-channel-toggle-speaker
232    (lambda (signal handback)
233      (save-excursion
234        (set-buffer riece-user-list-buffer)
235        (run-hooks 'riece-update-buffer-functions)))
236    (lambda (signal)
237      (riece-identity-equal (car (riece-signal-args signal))
238                            riece-current-channel))))
239
240 (defun riece-update-user-list-buffer ()
241   (save-excursion
242     (if (and riece-current-channel
243              (riece-channel-p (riece-identity-prefix riece-current-channel)))
244         (let* ((users
245                 (riece-with-server-buffer (riece-identity-server
246                                            riece-current-channel)
247                   (riece-channel-get-users (riece-identity-prefix
248                                             riece-current-channel))))
249                (inhibit-read-only t)
250                buffer-read-only)
251           (erase-buffer)
252           (riece-kill-all-overlays)
253           (while users
254             (insert (if (memq ?o (cdr (car users)))
255                         "@"
256                       (if (memq ?v (cdr (car users)))
257                           "+"
258                         " "))
259                     (riece-format-identity
260                      (riece-make-identity (car (car users))
261                                           (riece-identity-server
262                                            riece-current-channel))
263                      t)
264                     "\n")
265             (setq users (cdr users)))))))
266
267 (defun riece-update-channel-list-buffer ()
268   (save-excursion
269     (let ((inhibit-read-only t)
270           buffer-read-only
271           (index 1)
272           (channels riece-current-channels))
273       (erase-buffer)
274       (riece-kill-all-overlays)
275       (while channels
276         (if (car channels)
277             (insert (riece-format-channel-list-line
278                      index (car channels))))
279         (setq index (1+ index)
280               channels (cdr channels))))))
281
282 (defun riece-format-channel-list-line (index channel)
283   (or (run-hook-with-args-until-success
284        'riece-format-channel-list-line-functions index channel)
285       (concat (format "%2d:%c" index
286                       (if (riece-identity-equal channel riece-current-channel)
287                           ?*
288                         ? ))
289               (riece-format-identity channel)
290               "\n")))
291
292 (defun riece-update-channel-indicator ()
293   (setq riece-channel-indicator
294         (if riece-current-channel
295             (riece-format-identity riece-current-channel)
296           "None")))
297
298 (defun riece-update-long-channel-indicator ()
299   (setq riece-long-channel-indicator
300         (if riece-current-channel
301             (if (riece-channel-p (riece-identity-prefix riece-current-channel))
302                 (riece-concat-channel-modes
303                  riece-current-channel
304                  (riece-concat-channel-topic
305                   riece-current-channel
306                   (riece-format-identity riece-current-channel)))
307               (riece-format-identity riece-current-channel))
308           "None")))
309
310 (defun riece-update-channel-list-indicator ()
311   (if (and riece-current-channels
312            ;; There is at least one channel.
313            (delq nil (copy-sequence riece-current-channels)))
314       (let ((index 1))
315         (setq riece-channel-list-indicator
316               (mapconcat
317                #'identity
318                (delq nil
319                      (mapcar
320                       (lambda (channel)
321                         (prog1
322                             (if channel
323                                 (format "%d:%s" index
324                                         (riece-format-identity channel)))
325                           (setq index (1+ index))))
326                       riece-current-channels))
327                ",")))
328     (setq riece-channel-list-indicator "No channel")))
329
330 (defun riece-update-status-indicators ()
331   (if riece-current-channel
332       (with-current-buffer riece-command-buffer
333         (riece-with-server-buffer (riece-identity-server riece-current-channel)
334           (setq riece-away-indicator
335                 (if (and riece-real-nickname
336                          (riece-user-get-away riece-real-nickname))
337                     "A"
338                   "-")
339                 riece-operator-indicator
340                 (if (and riece-real-nickname
341                          (riece-user-get-operator riece-real-nickname))
342                     "O"
343                   "-")
344                 riece-user-indicator riece-real-nickname))))
345   (setq riece-freeze-indicator
346         (with-current-buffer (if (and riece-channel-buffer-mode
347                                       riece-channel-buffer)
348                                  riece-channel-buffer
349                                riece-dialogue-buffer)
350           (if (eq riece-freeze 'own)
351               "f"
352             (if riece-freeze
353                 "F"
354               "-")))))
355
356 (defun riece-update-buffers (&optional buffers)
357   (unless buffers
358     (setq buffers riece-buffer-list))
359   (while buffers
360     (save-excursion
361       (set-buffer (car buffers))
362       (run-hooks 'riece-update-buffer-functions))
363     (setq buffers (cdr buffers)))
364   (run-hooks 'riece-update-indicator-functions)
365   (force-mode-line-update t)
366   (run-hooks 'riece-update-buffer-hook))
367
368 (defun riece-channel-buffer-name (identity)
369   (let ((channels (riece-identity-member identity riece-current-channels)))
370     (if channels
371         (setq identity (car channels))
372       (if riece-debug
373           (message "%S is not a member of riece-current-channels" identity)))
374     (format riece-channel-buffer-format (riece-format-identity identity))))
375
376 (eval-when-compile
377   (autoload 'riece-channel-mode "riece"))
378 (defun riece-channel-buffer-create (identity)
379   (with-current-buffer
380       (riece-get-buffer-create (riece-channel-buffer-name identity)
381                                'riece-channel-mode)
382     (setq riece-channel-buffer-alist
383           (cons (cons identity (current-buffer))
384                 riece-channel-buffer-alist))
385     (unless (eq major-mode 'riece-channel-mode)
386       (riece-channel-mode)
387       (let (buffer-read-only)
388         (riece-insert-info (current-buffer)
389                            (concat "Created on "
390                                    (funcall riece-format-time-function
391                                             (current-time))
392                                    "\n"))
393         (run-hook-with-args 'riece-channel-buffer-create-functions identity)))
394     (current-buffer)))
395
396 (defun riece-channel-buffer (identity)
397   (cdr (riece-identity-assoc identity riece-channel-buffer-alist)))
398
399 (defun riece-switch-to-channel (identity)
400   (let ((last riece-current-channel))
401     (setq riece-current-channel identity
402           riece-channel-buffer (riece-channel-buffer riece-current-channel))
403     (run-hook-with-args 'riece-after-switch-to-channel-functions last)
404     (riece-emit-signal (riece-make-signal 'riece-switch-to-channel))))
405
406 (defun riece-join-channel (identity)
407   (unless (riece-identity-member identity riece-current-channels)
408     (setq riece-current-channels
409           (riece-identity-assign-binding
410            identity riece-current-channels
411            (mapcar
412             (lambda (channel)
413               (if channel
414                   (riece-parse-identity channel)))
415             riece-default-channel-binding)))
416     (riece-channel-buffer-create identity)))
417
418 (defun riece-switch-to-nearest-channel (pointer)
419   (let ((start riece-current-channels)
420         identity)
421     (while (and start (not (eq start pointer)))
422       (if (car start)
423           (setq identity (car start)))
424       (setq start (cdr start)))
425     (unless identity
426       (while (and pointer
427                   (null (car pointer)))
428         (setq pointer (cdr pointer)))
429       (setq identity (car pointer)))
430     (if identity
431         (riece-switch-to-channel identity)
432       (let ((last riece-current-channel))
433         (run-hook-with-args 'riece-after-switch-to-channel-functions last)
434         (setq riece-current-channel nil)
435         (riece-emit-signal (riece-make-signal 'riece-switch-to-channel))))))
436
437 (defun riece-part-channel (identity)
438   (let ((pointer (riece-identity-member identity riece-current-channels)))
439     (if pointer
440         (setcar pointer nil))
441     (if (riece-identity-equal identity riece-current-channel)
442         (riece-switch-to-nearest-channel pointer))))
443
444 (defun riece-redisplay-buffers (&optional force)
445   (riece-update-buffers)
446   (riece-redraw-layout force)
447   (run-hooks 'riece-redisplay-buffers-hook))
448
449 (provide 'riece-display)
450
451 ;;; riece-display.el ends here