Add 2012 to FSF copyright years for Emacs files
[bpt/emacs.git] / lisp / net / newst-ticker.el
CommitLineData
2900b2d8 1;; newst-ticker.el --- modeline ticker for newsticker.
2415d4c6 2
acaf905b 3;; Copyright (C) 2003-2012 Free Software Foundation, Inc.
2415d4c6
UJ
4
5;; Author: Ulf Jasper <ulf.jasper@web.de>
2900b2d8 6;; Filename: newst-ticker.el
2415d4c6
UJ
7;; URL: http://www.nongnu.org/newsticker
8;; Keywords: News, RSS, Atom
8e39154d 9;; Time-stamp: "6. Dezember 2009, 19:16:00 (ulf)"
bd78fa1d 10;; Package: newsticker
2415d4c6
UJ
11
12;; ======================================================================
13
9f7ca1a8
GM
14;; This file is part of GNU Emacs.
15
2415d4c6
UJ
16;; GNU Emacs is free software: you can redistribute it and/or modify
17;; it under the terms of the GNU General Public License as published by
18;; the Free Software Foundation, either version 3 of the License, or
19;; (at your option) any later version.
20
21;; GNU Emacs is distributed in the hope that it will be useful,
22;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24;; GNU General Public License for more details.
25
26;; You should have received a copy of the GNU General Public License
27;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
28
29;; ======================================================================
30
31;;; Commentary:
32
33;; See newsticker.el
34
35;; ======================================================================
36;;; Code:
37
8e39154d 38(require 'newst-backend)
2415d4c6
UJ
39
40(defvar newsticker--ticker-timer nil
41 "Timer for newsticker ticker.")
42
43;;;###autoload
44(defun newsticker-ticker-running-p ()
45 "Check whether newsticker's actual ticker is running.
46Return t if ticker is running, nil otherwise. Newsticker is
47considered to be running if the newsticker timer list is not
48empty."
49 (timerp newsticker--ticker-timer))
50
51;; customization group ticker
52(defgroup newsticker-ticker nil
53 "Settings for the headline ticker."
54 :group 'newsticker)
55
56(defun newsticker--set-customvar-ticker (symbol value)
57 "Set newsticker-variable SYMBOL value to VALUE.
58Calls all actions which are necessary in order to make the new
59value effective."
60 (if (or (not (boundp symbol))
61 (equal (symbol-value symbol) value))
62 (set symbol value)
63 ;; something must have changed -- restart ticker
64 (when (newsticker-running-p)
65 (message "Restarting ticker")
66 (newsticker-stop-ticker)
67 (newsticker--ticker-text-setup)
68 (newsticker-start-ticker)
69 (message ""))))
70
71(defcustom newsticker-ticker-interval
72 0.3
73 "Time interval for displaying news items in the echo area (seconds).
74If equal or less than 0 no messages are shown in the echo area. For
75smooth display (see `newsticker-scroll-smoothly') a value of 0.3 seems
76reasonable. For non-smooth display a value of 10 is a good starting
77point."
78 :type 'number
79 :set 'newsticker--set-customvar-ticker
80 :group 'newsticker-ticker)
81
82(defcustom newsticker-scroll-smoothly
83 t
84 "Decides whether to flash or scroll news items.
85If t the news headlines are scrolled (more-or-less) smoothly in the echo
86area. If nil one headline after another is displayed in the echo area.
87The variable `newsticker-ticker-interval' determines how fast this
88display moves/changes and whether headlines are shown in the echo area
89at all. If you change `newsticker-scroll-smoothly' you should also change
90`newsticker-ticker-interval'."
91 :type 'boolean
92 :group 'newsticker-ticker)
93
94(defcustom newsticker-hide-immortal-items-in-echo-area
95 t
96 "Decides whether to show immortal/non-expiring news items in the ticker.
97If t the echo area will not show immortal items. See also
98`newsticker-hide-old-items-in-echo-area'."
99 :type 'boolean
100 :set 'newsticker--set-customvar-ticker
101 :group 'newsticker-ticker)
102
103(defcustom newsticker-hide-old-items-in-echo-area
104 t
105 "Decides whether to show only the newest news items in the ticker.
106If t the echo area will show only new items, i.e. only items which have
107been added between the last two retrievals."
108 :type 'boolean
109 :set 'newsticker--set-customvar-ticker
110 :group 'newsticker-ticker)
111
112(defcustom newsticker-hide-obsolete-items-in-echo-area
113 t
114 "Decides whether to show obsolete items items in the ticker.
115If t the echo area will not show obsolete items. See also
116`newsticker-hide-old-items-in-echo-area'."
117 :type 'boolean
118 :set 'newsticker--set-customvar-ticker
119 :group 'newsticker-ticker)
120
121(defun newsticker--display-tick ()
122 "Called from the display timer.
123This function calls a display function, according to the variable
124`newsticker-scroll-smoothly'."
125 (if newsticker-scroll-smoothly
126 (newsticker--display-scroll)
127 (newsticker--display-jump)))
128
129(defsubst newsticker--echo-area-clean-p ()
130 "Check whether somebody is using the echo area / minibuffer.
131Return t if echo area and minibuffer are unused."
132 (not (or (active-minibuffer-window)
133 (and (current-message)
134 (not (string= (current-message)
135 newsticker--prev-message))))))
136
137(defun newsticker--display-jump ()
138 "Called from the display timer.
139This function displays the next ticker item in the echo area, unless
140there is another message displayed or the minibuffer is active."
141 (let ((message-log-max nil));; prevents message text from being logged
142 (when (newsticker--echo-area-clean-p)
143 (setq newsticker--item-position (1+ newsticker--item-position))
144 (when (>= newsticker--item-position (length newsticker--item-list))
145 (setq newsticker--item-position 0))
146 (setq newsticker--prev-message
147 (nth newsticker--item-position newsticker--item-list))
148 (message "%s" newsticker--prev-message))))
149
150(defun newsticker--display-scroll ()
151 "Called from the display timer.
152This function scrolls the ticker items in the echo area, unless
153there is another message displayed or the minibuffer is active."
154 (when (newsticker--echo-area-clean-p)
155 (let* ((width (- (frame-width) 1))
156 (message-log-max nil);; prevents message text from being logged
157 (i newsticker--item-position)
158 subtext
159 (s-text newsticker--scrollable-text)
160 (l (length s-text)))
161 ;; don't show anything if there is nothing to show
162 (unless (< (length s-text) 1)
163 ;; repeat the ticker string if it is shorter than frame width
164 (while (< (length s-text) width)
165 (setq s-text (concat s-text s-text)))
166 ;; get the width of the printed string
167 (setq l (length s-text))
168 (cond ((< i (- l width))
169 (setq subtext (substring s-text i (+ i width))))
170 (t
171 (setq subtext (concat
172 (substring s-text i l)
173 (substring s-text 0 (- width (- l i)))))))
174 ;; Take care of multibyte strings, for which (string-width) is
175 ;; larger than (length).
176 ;; Actually, such strings may be smaller than (frame-width)
177 ;; because return values of (string-width) are too large:
178 ;; (string-width "<japanese character>") => 2
179 (let ((t-width (1- (length subtext))))
180 (while (> (string-width subtext) width)
181 (setq subtext (substring subtext 0 t-width))
182 (setq t-width (1- t-width))))
183 ;; show the ticker text and save current position
184 (message "%s" subtext)
185 (setq newsticker--prev-message subtext)
186 (setq newsticker--item-position (1+ i))
187 (when (>= newsticker--item-position l)
188 (setq newsticker--item-position 0))))))
189
190;;;###autoload
191(defun newsticker-start-ticker ()
192 "Start newsticker's ticker (but not the news retrieval).
193Start display timer for the actual ticker if wanted and not
194running already."
195 (interactive)
196 (if (and (> newsticker-ticker-interval 0)
197 (not newsticker--ticker-timer))
198 (setq newsticker--ticker-timer
199 (run-at-time newsticker-ticker-interval
200 newsticker-ticker-interval
201 'newsticker--display-tick))))
202
203(defun newsticker-stop-ticker ()
204 "Stop newsticker's ticker (but not the news retrieval)."
205 (interactive)
206 (when newsticker--ticker-timer
207 (cancel-timer newsticker--ticker-timer)
208 (setq newsticker--ticker-timer nil)))
209
210;; ======================================================================
211;;; Manipulation of ticker text
212;; ======================================================================
213(defun newsticker--ticker-text-setup ()
214 "Build the ticker text which is scrolled or flashed in the echo area."
215 ;; reset scrollable text
216 (setq newsticker--scrollable-text "")
217 (setq newsticker--item-list nil)
218 (setq newsticker--item-position 0)
219 ;; build scrollable text from cache data
220 (let ((have-something nil))
221 (mapc
222 (lambda (feed)
223 (let ((feed-name (symbol-name (car feed))))
224 (let ((num-new (newsticker--stat-num-items (car feed) 'new))
225 (num-old (newsticker--stat-num-items (car feed) 'old))
226 (num-imm (newsticker--stat-num-items (car feed) 'immortal))
227 (num-obs (newsticker--stat-num-items (car feed) 'obsolete)))
228 (when (or (> num-new 0)
229 (and (> num-old 0)
230 (not newsticker-hide-old-items-in-echo-area))
231 (and (> num-imm 0)
232 (not newsticker-hide-immortal-items-in-echo-area))
233 (and (> num-obs 0)
234 (not newsticker-hide-obsolete-items-in-echo-area)))
235 (setq have-something t)
236 (mapc
237 (lambda (item)
238 (let ((title (replace-regexp-in-string
239 "[\r\n]+" " "
240 (newsticker--title item)))
241 (age (newsticker--age item)))
242 (unless (string= title newsticker--error-headline)
243 (when
244 (or (eq age 'new)
245 (and (eq age 'old)
246 (not newsticker-hide-old-items-in-echo-area))
247 (and (eq age 'obsolete)
248 (not
249 newsticker-hide-obsolete-items-in-echo-area))
250 (and (eq age 'immortal)
251 (not
252 newsticker-hide-immortal-items-in-echo-area)))
253 (setq title (newsticker--remove-whitespace title))
254 ;; add to flash list
255 (add-to-list 'newsticker--item-list
256 (concat feed-name ": " title) t)
257 ;; and to the scrollable text
258 (setq newsticker--scrollable-text
259 (concat newsticker--scrollable-text
260 " " feed-name ": " title " +++"))))))
261 (cdr feed))))))
262 newsticker--cache)
263 (when have-something
264 (setq newsticker--scrollable-text
265 (concat "+++ "
266 (format-time-string "%A, %H:%M"
267 newsticker--latest-update-time)
268 " ++++++" newsticker--scrollable-text)))))
269
270(defun newsticker--ticker-text-remove (feed title)
271 "Remove the item of FEED with TITLE from the ticker text."
272 ;; reset scrollable text
273 (setq newsticker--item-position 0)
274 (let ((feed-name (symbol-name feed))
275 (t-title (replace-regexp-in-string "[\r\n]+" " " title)))
276 ;; remove from flash list
277 (setq newsticker--item-list (remove (concat feed-name ": " t-title)
278 newsticker--item-list))
279 ;; and from the scrollable text
280 (setq newsticker--scrollable-text
281 (replace-regexp-in-string
282 (regexp-quote (concat " " feed-name ": " t-title " +++"))
283 ""
284 newsticker--scrollable-text))
285 (if (string-match (concat "^\\+\\+\\+ [A-Z][a-z]+, "
286 "[012]?[0-9]:[0-9][0-9] \\+\\+\\+\\+\\+\\+$")
287 newsticker--scrollable-text)
288 (setq newsticker--scrollable-text ""))))
289
8e39154d 290(provide 'newst-ticker)
041fa0d4 291
2900b2d8 292;;; newst-ticker.el ends here