1 ;;; liece-xemacs.el --- XEmacs specific routines.
2 ;; Copyright (C) 1998-2000 Daiki Ueno
4 ;; Author: Daiki Ueno <ueno@unixuser.org>
9 ;; This file is part of Liece.
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
33 (require 'liece-inlines)
35 (require 'liece-commands))
37 (autoload 'liece-command-dcc-send "liece-dcc")
38 (defvar liece-nick-popup-menu)
40 (defgroup liece-toolbar nil
41 "Toolbar of your XEmacs"
45 (defgroup liece-toolbar-icons nil
46 "Toolbar Icons of your XEmacs"
48 :prefix "liece-toolbar-"
51 (defmacro liece-xemacs-icon-path (file)
52 "Search icon FILE and return absolete path of the file."
53 `(or (and liece-icon-directory
54 (expand-file-name ,file liece-icon-directory))
55 (let ((path (liece-find-path ,file "icons")))
57 (setq liece-icon-directory
58 (file-name-directory path)))
61 (define-widget 'liece-toolbar-icon 'list
62 "Edit toolbar spec entries"
63 :match (lambda (widget value)
64 (valid-plist-p value))
65 :convert-widget 'liece-toolbar-icon-convert)
68 (defconst liece-toolbar-icon-states
69 '(:up :down :disabled :cap-up :cap-down :cap-disabled)
70 "toolbar event states")
72 (defun liece-toolbar-icon-convert-1 (state)
73 (list 'group :inline t :format "%t: %v"
74 :tag (capitalize (substring (symbol-name state) 1))
75 (list 'const :format "" :value state
76 (list 'radio '(const :tag "none" nil) 'file)))))
78 (defun liece-toolbar-icon-convert (widget)
79 "Widget converter of the WIDGET `liece-toolbar-icon'."
80 (apply #'widget-put widget :args
82 (mapcar #'liece-toolbar-icon-convert-1
83 liece-toolbar-icon-states)))
86 (defcustom liece-use-toolbar (if (featurep 'toolbar)
89 "*If nil, do not use a toolbar.
90 If it is non-nil, it must be a toolbar. The five valid values are
91 `default-toolbar', `top-toolbar', `bottom-toolbar',
92 `right-toolbar', and `left-toolbar'."
93 :type '(choice (const default-toolbar)
94 (const top-toolbar) (const bottom-toolbar)
95 (const left-toolbar) (const right-toolbar)
96 (const :tag "no toolbar" nil))
97 :group 'liece-toolbar)
99 (defcustom liece-toolbar-back-icon '(:up "back.xpm")
101 :type 'liece-toolbar-icon
102 :group 'liece-toolbar-icons)
104 (defcustom liece-toolbar-forward-icon '(:up "forward.xpm")
106 :type 'liece-toolbar-icon
107 :group 'liece-toolbar-icons)
109 (defcustom liece-toolbar-reload-icon '(:up "reload.xpm")
111 :type 'liece-toolbar-icon
112 :group 'liece-toolbar-icons)
114 (defcustom liece-toolbar-home-icon '(:up "home.xpm")
116 :type 'liece-toolbar-icon
117 :group 'liece-toolbar-icons)
119 (defcustom liece-toolbar-search-icon '(:up "search.xpm")
121 :type 'liece-toolbar-icon
122 :group 'liece-toolbar-icons)
124 (defcustom liece-toolbar-location-icon '(:up "location.xpm")
126 :type 'liece-toolbar-icon
127 :group 'liece-toolbar-icons)
129 (defcustom liece-toolbar-stop-icon '(:up "stop.xpm")
131 :type 'liece-toolbar-icon
132 :group 'liece-toolbar-icons)
134 (defcustom liece-xemacs-unread-icon "balloon.xpm"
139 ;;; @ internal variables
141 (defvar liece-glyph-cache nil)
142 (defvar liece-toolbar-position (if (featurep 'toolbar)
143 (default-toolbar-position)
146 (defvar liece-toolbar-back-glyph nil)
147 (defvar liece-toolbar-forward-glyph nil)
148 (defvar liece-toolbar-reload-glyph nil)
149 (defvar liece-toolbar-home-glyph nil)
150 (defvar liece-toolbar-search-glyph nil)
151 (defvar liece-toolbar-location-glyph nil)
152 (defvar liece-toolbar-stop-glyph nil)
154 (defvar liece-toolbar-spec-list
155 '([liece-toolbar-back-glyph
156 liece-command-previous-channel t "Previous Channel"]
157 [liece-toolbar-forward-glyph
158 liece-command-next-channel t "Next Channel"]
159 [liece-toolbar-reload-glyph
160 liece-command-list t "List Channel"]
161 [liece-toolbar-home-glyph
162 liece-switch-to-channel-no-1 t "Go Home Channel"]
163 [liece-toolbar-search-glyph
164 liece-command-finger t "Finger"]
165 [liece-toolbar-location-glyph
166 liece-command-join t "Join Channel"]
167 [liece-toolbar-stop-glyph
168 liece-command-quit t "Quit IRC"]))
172 (defun liece-toolbar-icon-plist-get (spec prop)
173 "Return absolete path of icon file which SPEC has PROP."
174 (let ((icon (plist-get spec prop)))
175 (if icon (liece-locate-icon-file icon))))
177 (defun liece-toolbar-map-button-list (plist)
178 "Make toolbar icon list based on status PLIST."
179 (apply #'toolbar-make-button-list
182 (liece-toolbar-icon-plist-get plist prop))
183 liece-toolbar-icon-states)))
185 (defun liece-xemacs-setup-toolbar (bar &optional force)
186 "Prepare icons of toolbar BAR.
187 If optional argument FORCE is non-nil, always update toolbar."
189 (set-default-toolbar-position liece-toolbar-position)
191 (setq icon (aref spec 0)
194 (substring (prin1-to-string icon) -5 0)
197 (not (symbol-value icon)))
198 (set icon (liece-toolbar-map-button-list plist))))
199 (run-hooks 'liece-xemacs-setup-toolbar-hook)))
201 ;;; @ modeline decoration
203 (defun liece-xemacs-hide-modeline ()
204 "Remove modeline from current window."
205 (set-specifier has-modeline-p nil (current-buffer)))
207 (when (featurep 'scrollbar)
208 (defun liece-xemacs-hide-scrollbars ()
210 ((boundp 'horizontal-scrollbar-visible-p)
211 (set-specifier horizontal-scrollbar-visible-p nil (current-buffer)))
212 ((boundp 'scrollbar-height)
213 (set-specifier scrollbar-height 0 (current-buffer)))))
214 (add-hook 'liece-nick-mode-hook 'liece-xemacs-hide-scrollbars)
215 (add-hook 'liece-channel-list-mode-hook 'liece-xemacs-hide-scrollbars))
217 (add-hook 'liece-nick-mode-hook 'liece-xemacs-hide-modeline)
218 (add-hook 'liece-channel-list-mode-hook 'liece-xemacs-hide-modeline)
220 (defvar liece-xemacs-modeline-left-extent
221 (let ((ext (copy-extent modeline-buffer-id-left-extent)))
224 (defvar liece-xemacs-modeline-right-extent
225 (let ((ext (copy-extent modeline-buffer-id-right-extent)))
228 (add-hook 'liece-command-mode-hook 'liece-setup-toolbar)
230 (defun liece-setup-toolbar ()
231 "Prepare toolbar if wanted."
232 (when liece-use-toolbar
233 (liece-xemacs-setup-toolbar liece-toolbar-spec-list)
234 (set-specifier (symbol-value liece-use-toolbar) liece-toolbar-spec-list
237 (defun liece-xemacs-modeline-glyph ()
238 "Return a glyph of modeline pointer."
243 (if (setq file (liece-locate-icon-file
244 "liece-pointer.xpm"))
245 (list (vector 'xpm :file file)))
246 (if (setq file (liece-locate-icon-file
247 "liece-pointer.xbm"))
248 (list (vector 'xbm :file file)))
249 '([string :data "Liece:"]))))))
250 (set-glyph-face glyph 'modeline-buffer-id)
253 (defun liece-xemacs-mode-line-buffer-identification (line)
254 "Decorate 1st element of `mode-line-buffer-identification' LINE.
255 Modify whole identification by side effect."
256 (let ((id (car line)) chop)
257 (if (and (stringp id) (string-match "^Liece:" id))
259 (setq chop (match-end 0))
262 (let ((glyph (liece-xemacs-modeline-glyph)))
264 (cons liece-xemacs-modeline-left-extent glyph)
265 (cons liece-xemacs-modeline-left-extent
266 (substring id 0 chop))))
267 (cons liece-xemacs-modeline-right-extent
268 (substring id chop)))
272 (defun liece-xemacs-suppress-modeline-format ()
273 "Remove unnecessary information from `modeline-format'."
274 (setq modeline-format
275 (remrassq 'modeline-modified
276 (delq 'modeline-multibyte-status
277 (copy-sequence mode-line-format)))))
281 (defun liece-xemacs-nick-popup-menu (widget &optional event)
282 "Trigger function for popup menu."
283 (let ((pos (widget-event-point event)))
286 (if (eq major-mode 'liece-nick-mode)
287 (liece-nick-update-region))
288 (let ((menu (cdr liece-nick-popup-menu)))
289 (setq menu (nconc (list "IRCHAT" ; title: not displayed
291 "--:shadowDoubleEtchedOut")
292 (mapcar (lambda (spec)
297 (let (popup-menu-titles)
298 (popup-menu menu))))))
300 (fset 'liece-nick-popup-menu 'liece-xemacs-nick-popup-menu)
302 ;;; @ nick buffer decoration
304 (defun liece-xemacs-create-nick-glyph (file &optional string)
305 "Return a glyph of nick indicator from FILE or STRING."
307 (cdr-safe (assoc file liece-glyph-cache))
311 (if (setq file (liece-locate-icon-file file))
312 (list (vector 'xpm :file file)))
314 (list (vector 'string :data string)))))))
315 (push (cons file glyph) liece-glyph-cache)
316 (set-glyph-face glyph 'default)
319 (defun liece-xemacs-glyph-nick-region (start end)
320 "Decorate nick buffer between START and END."
322 (setq start (progn (goto-char start)(beginning-of-line)(point))
323 end (progn (goto-char end)(beginning-of-line 2)(point)))
325 (narrow-to-region start end)
326 (let ((buffer-read-only nil)
327 (inhibit-read-only t)
328 (case-fold-search nil)
329 mark file glyph ext ant)
334 e 'liece-xemacs-glyph-nick-extent)
336 e 'liece-xemacs-glyph-nick-annotation))
338 (current-buffer) start end)
339 (dolist (entry liece-nick-image-alist)
340 (setq mark (car entry)
342 glyph (liece-xemacs-create-nick-glyph
343 file (char-to-string mark)))
347 (when (eq (char-after) mark)
348 (mapcar 'delete-annotation
349 (annotations-at (1+ (point))))
350 (setq ext (make-extent (point) (1+ (point)))
351 ant (make-annotation glyph (1+ (point)) 'text))
352 (set-extent-property ext 'end-open t)
353 (set-extent-property ext 'start-open t)
354 (set-extent-property ext 'invisible t)
355 (set-extent-property ext 'intangible t)
357 ant 'liece-xemacs-glyph-nick-extent ext)
359 ext 'liece-xemacs-glyph-nick-annotation ant))
360 (beginning-of-line 2))))))))
362 (defun liece-xemacs-set-drop-functions (start end)
363 "Initialize drag and drop in DCC between START and END.
364 This function needs window system independent drag and drop
365 support (21.0 b39 or later)"
367 (liece-xemacs-set-drop-functions-buffer
368 (current-buffer) start end)
371 (defun liece-xemacs-set-drop-functions-buffer (&optional buffer start end)
372 "Initialize BUFFER drag and drop DCC settings between START and END.
373 This function needs window system independent drag and drop
374 support (21.0 b39 or later)"
376 (when (and (featurep 'x) (featurep 'dragdrop))
380 (setq start (or start (point-min))
381 end (or end (point-max)))
383 (setq start (line-beginning-position))
385 (setq end (line-beginning-position))
388 (beginning-of-line 2)
391 (narrow-to-region start end)
392 (let (buffer-read-only case-fold-search)
396 (when (extent-property e 'liece-xemacs-drop-extent)
400 (let (st nd nick func)
404 nd (line-end-position)
405 nick (buffer-substring st nd))
406 (mapcar 'delete-annotation (annotations-at nd))
407 (setq func (intern (concat "liece-xemacs-drop-function-" nick)))
409 (list 'lambda (list 'object)
410 (list 'liece-xemacs-drop-function 'object nick)))
411 (let ((ext (make-extent st nd)))
412 (set-extent-property ext 'liece-xemacs-drop-extent t)
413 (set-extent-property ext 'dragdrop-drop-functions (list func)))
414 (beginning-of-line 2))))))))
416 (defun liece-xemacs-drop-function (object nick)
417 "Drag and drop handler.
418 Always two arguments are passed, OBJECT and NICK."
419 (if (and (eq (car object) 'dragdrop_URL)
420 (stringp (cdr object))
421 (string-match "^[^:]*:\\(.*\\)" (cdr object)))
422 (let ((filename (match-string 1 (cdr object))))
423 (liece-command-dcc-send filename nick))))
425 (defadvice easy-menu-add-item
426 (around liece-fix-menu-path-switch-buffer activate)
427 "Advice for XEmacs 20.4 or earlier."
429 (set-buffer liece-command-buffer)
431 (cons (car (ad-get-arg 0)) (ad-get-arg 1))
432 (ad-get-arg 2) (ad-get-arg 3))))
435 (setq liece-x-face-insert-function
436 (function liece-x-face-insert-with-xemacs))
438 (defun liece-x-face-insert-with-xemacs (buffer str nick)
440 (let ((glyph (cdr-safe (assoc nick liece-glyph-cache))))
442 (setq glyph (make-glyph
444 ((and (featurep 'xface)
445 (memq (console-type) '(x mswindows)))
447 (t `[string :data ,str]))))
449 (push (cons nick glyph) liece-glyph-cache)
450 (set-glyph-face glyph 'default)))
452 (goto-char (point-max))
454 (set-extent-end-glyph (make-extent (point) (point)) glyph))))))
461 `(,(if (and (boundp 'filename)
463 (file-exists-p filename))
464 (file-name-directory filename)
468 (when (featurep 'xpm)
470 (defmacro liece-xemacs-logo ()
471 (let ((logo "liece.xpm")
472 (dir (if (and (boundp 'filename)
474 (file-exists-p filename))
475 (file-name-directory filename)
477 (setq logo (expand-file-name logo dir))
478 (if (file-exists-p logo)
479 (let ((buffer (generate-new-buffer " *liece-logo*"))
480 (coding-system-for-read (quote binary))
481 buffer-file-format format-alist
482 insert-file-contents-post-hook
483 insert-file-contents-pre-hook)
487 (insert-file-contents logo)
489 (kill-buffer buffer)))
492 "Warning: file \"%s\" not found." logo)
496 (defconst liece-xemacs-logo
497 (when (featurep 'xpm)
498 (liece-xemacs-logo)))
500 (defun liece-xemacs-splash-at-point (&optional height)
501 "Display splash logo in HEIGHT."
502 (or (bolp) (insert "\n"))
504 (glyph (make-glyph `[xpm :data ,liece-xemacs-logo]))
505 (lh (/ (window-pixel-height) (window-height)))
506 (lw (/ (window-pixel-width) (window-width)))
507 (liece-insert-environment-version nil)
510 (insert-char ?\n (max 0 (/ (- (or height (window-height))
511 (/ (glyph-height glyph) lh))
513 (insert-char ?\ (max 0 (/ (- (window-width)
514 (/ (glyph-width glyph) lw))
516 (when (and (featurep 'xpm) (memq (console-type) '(x mswindows)))
517 (set-extent-end-glyph
518 (make-extent (point) (point))
521 (insert-char ?\ (max 0 (/ (- (window-width) (length (liece-version))) 2)))
523 (insert (liece-version))
524 (and (find-face 'bold-italic)
525 (put-text-property bov (point) 'face 'bold-italic))
527 (set-window-start (get-buffer-window (current-buffer)) (point))
530 (defun liece-xemacs-splash (&optional arg)
531 "Display splash logo interactively.
532 If ARG is given, don't hide splash buffer."
534 (and liece-xemacs-logo
535 (let ((frame (selected-frame))
537 (liece-insert-environment-version nil))
541 (setq config (current-window-configuration))
543 (setq buffer (generate-new-buffer
544 (concat (if arg "*" " *")
545 (liece-version) "*"))))
546 (delete-other-windows)
547 (liece-xemacs-splash-at-point)
548 (set-buffer-modified-p nil)
549 (or arg (sleep-for 2)))
552 (set-window-configuration config)
553 (redisplay-frame frame)))))))
555 (or (eq 'stream (device-type))
556 (liece-xemacs-splash))
560 (defun liece-xemacs-unread-mark (chnl)
561 (if liece-display-unread-mark
562 (with-current-buffer liece-channel-list-buffer
563 (let* ((buffer-read-only nil)
564 (file (liece-xemacs-icon-path
565 liece-xemacs-unread-icon))
566 (glyph (make-glyph (vector 'xpm ':file file)))
568 (goto-char (point-min))
569 (when (re-search-forward (concat "^ ?[0-9]+: " chnl "$") nil t)
570 (goto-char (match-end 0))
572 (setq ext (make-extent (match-end 0) (1+ (match-end 0))))
573 (set-extent-end-glyph ext glyph))))))
575 (defun liece-xemacs-read-mark (chnl)
576 (if liece-display-unread-mark
577 (with-current-buffer liece-channel-list-buffer
578 (let ((buffer-read-only nil))
579 (goto-char (point-min))
580 (when (re-search-forward (concat "^ ?[0-9]+: " chnl " $") nil t)
581 (goto-char (1- (match-end 0)))
584 (defun liece-xemacs-redisplay-unread-mark ()
585 (if liece-display-unread-mark
587 (dolist (chnl liece-channel-unread-list)
588 (liece-xemacs-unread-mark chnl)))))
591 ;;; @ emulation functions
593 (defun liece-xemacs-map-extents (function)
594 "Map FUNCTION over the extents which overlap the current buffer."
595 (map-extents (lambda (extent ignore)
596 (if (overlayp extent) (funcall function extent)))))
598 (defun liece-xemacs-kill-all-overlays ()
599 "Delete all extents in the current buffer."
600 (liece-xemacs-map-extents #'delete-extent))
602 (defun liece-xemacs-overlays-at (pos)
603 "Return a list of the overlays that contain position POS."
604 (let ((ext (extent-at pos)))
605 (and ext (overlayp ext) (list ext))))
607 (fset 'liece-mode-line-buffer-identification
608 'liece-xemacs-mode-line-buffer-identification)
610 (fset 'liece-suppress-mode-line-format
611 'liece-xemacs-suppress-modeline-format)
613 (fset 'liece-kill-all-overlays 'liece-xemacs-kill-all-overlays)
614 (fset 'liece-map-overlays 'liece-xemacs-map-extents)
615 (fset 'liece-locate-data-directory 'locate-data-directory)
617 (add-hook 'liece-nick-insert-hook 'liece-xemacs-glyph-nick-region)
618 (add-hook 'liece-nick-insert-hook 'liece-xemacs-set-drop-functions)
620 (add-hook 'liece-nick-replace-hook 'liece-xemacs-glyph-nick-region)
621 (add-hook 'liece-nick-replace-hook 'liece-xemacs-set-drop-functions)
623 (if (and (featurep 'xpm)
624 (memq (console-type) '(x gtk mswindows)))
626 (fset 'liece-redisplay-unread-mark 'liece-xemacs-redisplay-unread-mark)
627 (add-hook 'liece-channel-unread-hook 'liece-xemacs-unread-mark)
628 (add-hook 'liece-channel-read-hook 'liece-xemacs-read-mark))
629 (fset 'liece-redisplay-unread-mark 'liece-emacs-redisplay-unread-mark)
630 (add-hook 'liece-channel-unread-hook 'liece-emacs-unread-mark)
631 (add-hook 'liece-channel-read-hook 'liece-emacs-read-mark))
633 (provide 'liece-xemacs)
635 ;;; liece-xemacs.el ends here