Update of /project/beirc/cvsroot/beirc
In directory clnet:/tmp/cvs-serv22818
Modified Files:
application.lisp beirc.asd message-display.lisp receivers.lisp
Added Files:
events.lisp
Log Message:
Speedup redisplay; time display; factor out events; robustify pane creation.
* The foo-event handler now calls redisplay only if it is invoked for
the last foo-event for the current event's receiver. This speeds up
redisplay considerably if many messages come in simultaneously.
* Added time/date display for some message types
* Moved event definitions to events.lisp
* Pane creation doesn't happen in the irc listener thread anymore,
but is triggered in the ui thread via a new-sheet-event.
--- /project/beirc/cvsroot/beirc/application.lisp 2006/03/06 17:53:58 1.52
+++ /project/beirc/cvsroot/beirc/application.lisp 2006/03/12 09:48:57 1.53
@@ -75,6 +75,7 @@
(define-application-frame beirc (redisplay-frame-mixin
standard-application-frame)
((connection-processes :initform nil :accessor connection-processes)
+ (ui-process :initform (current-process) :accessor ui-process)
(ignored-nicks :initform nil)
(receivers :initform (make-hash-table :test #'equal) :accessor receivers)
(server-receivers :initform nil :reader server-receivers)
@@ -168,7 +169,7 @@
(with-text-family (t :sans-serif)
(multiple-value-bind (seconds minutes hours) (decode-universal-time (get-universal-time))
seconds
- (format t "~2,'0D:~2,'0D ~A~:[~;(away)~] on ~A~@[ speaking to ~A~]~100T~D messages"
+ (format t "~2,'0D:~2,'0D ~A~:[~;(away)~] ~@[on ~A~]~@[ speaking to ~A~]~100T~D messages"
hours minutes
(current-nickname)
(away-status *application-frame* (current-connection *application-frame*))
@@ -199,23 +200,6 @@
;; "~:@>")
;; prefix)))
-
-;;; Here comes the trick:
-
-;;; Although I would pretty much prefer an implementation of CLIM
-;;; which is thread safe, I figure we better go through the central
-;;; event loop. We define a new event class, subclass of
-;;; WINDOW-MANAGER-EVENT, and when ever we want to update the display
-;;; we send it to the frame.
-
-(defclass foo-event (clim:window-manager-event)
- ((sheet :initarg :sheet :reader event-sheet)
- (receiver :initarg :receiver :reader receiver)))
-
-;;for updating the time display, triggered from TICKER
-(defclass bar-event (clim:window-manager-event)
- ((sheet :initarg :sheet :reader event-sheet)))
-
;;;
(defun pane-scrolled-to-bottom-p (pane)
@@ -245,14 +229,25 @@
(redraw-receiver receiver))
(receivers *application-frame*))))
+;;; event handling methods
+
+(defmethod handle-event ((frame beirc) (event new-sheet-event))
+ (funcall (sheet-creation-closure event) frame))
+
(defmethod handle-event ((frame beirc) (event foo-event))
;; Hack:
;; Figure out if we are scrolled to the bottom.
(let* ((receiver (receiver event))
- (pane (actual-application-pane (pane receiver))))
+ (pane (actual-application-pane (pane receiver)))
+ (next-event (event-peek (frame-top-level-sheet frame))))
(let ((btmp (pane-scrolled-to-bottom-p pane)))
- (setf (pane-needs-redisplay pane) t)
- (redisplay-frame-panes frame)
+ (update-drawing-options receiver)
+ ;; delay redisplay until this is the last event in the queue
+ ;; (for this event's receiver).
+ (unless (and (typep next-event 'foo-event)
+ (eql (receiver next-event) receiver))
+ (setf (pane-needs-redisplay pane) t)
+ (redisplay-frame-panes frame))
(when btmp (scroll-pane-to-bottom pane)))
(medium-force-output (sheet-medium pane)) ;###
))
@@ -299,10 +294,8 @@
(when (message-directed-to-me-p message)
(incf (messages-directed-to-me receiver)))
(incf (all-unseen-messages receiver)))
- (update-drawing-options receiver)
- (clim-internals::event-queue-prepend
- (climi::frame-event-queue frame)
- (make-instance 'foo-event :sheet frame :receiver receiver))
+ (queue-event (frame-top-level-sheet frame)
+ (make-instance 'foo-event :sheet frame :receiver receiver))
nil)
(defun post-message (frame message)
@@ -776,6 +769,7 @@
(tab-layout:remove-pane (find-pane-named frame 'server)
(find-pane-named frame 'query)))
(setf (server-receiver frame connection) server-receiver)
+ (setf (ui-process *application-frame*) (current-process))
(setf (connection-process *application-frame* connection)
(clim-sys:make-process #'(lambda ()
(restart-case
--- /project/beirc/cvsroot/beirc/beirc.asd 2006/02/26 18:41:21 1.6
+++ /project/beirc/cvsroot/beirc/beirc.asd 2006/03/12 09:48:57 1.7
@@ -9,8 +9,9 @@
:depends-on (:mcclim :cl-irc :split-sequence :tab-layout)
:components ((:file "package")
(:file "variables" :depends-on ("package"))
- (:file "receivers" :depends-on ("package" "variables"))
+ (:file "events" :depends-on ("package"))
+ (:file "receivers" :depends-on ("package" "variables" "events"))
(:file "presentations" :depends-on ("package" "variables" "receivers"))
(:file "message-display" :depends-on ("package" "variables" "presentations"))
- (:file "application" :depends-on ("package" "variables" "presentations" "receivers"))
+ (:file "application" :depends-on ("package" "variables" "presentations" "events" "receivers"))
(:file "message-processing" :depends-on ("package" "variables" "receivers" "application"))))
\ No newline at end of file
--- /project/beirc/cvsroot/beirc/message-display.lisp 2006/03/02 21:46:49 1.38
+++ /project/beirc/cvsroot/beirc/message-display.lisp 2006/03/12 09:48:57 1.39
@@ -224,6 +224,8 @@
(irc:irc-rpl_unaway-message))))
(defmethod print-message (message receiver)
+ ;; default message if we don't know how to render a message.
+ #+(or) (break "~S" message) ; uncomment to debug
(irc:destructuring-arguments (&whole args &last body) message
(formatting-message (t message receiver)
((format t "!!! ~A" (irc:source message)))
@@ -302,7 +304,7 @@
((with-drawing-options (*standard-output* :ink +gray33+ :text-size :small)
(present nickname 'nickname)
(format-message* (format nil " is away: ~A" away-msg)
- :start-length (length (second (irc:arguments message)))))))))
+ :start-length (length nickname)))))))
(defmethod print-message ((message irc:irc-rpl_whoisidentified-message) receiver)
(irc:destructuring-arguments (me nickname body) message
@@ -312,7 +314,29 @@
((with-drawing-options (*standard-output* :ink +gray33+ :text-size :small)
(present nickname 'nickname)
(write-char #\Space)
- (format-message* body :start-length (length (second (irc:arguments message)))))))))
+ (format-message* body :start-length (length nickname)))))))
+
+(defun unix-epoch-to-universal-time (epoch-time)
+ (+ epoch-time 2208988800 ; seconds between 1970-01-01 0:00 and 1900-01-01 0:00
+ ))
+
+(defun format-unix-epoch (unix-epoch)
+ (multiple-value-bind (second minute hour date month year)
+ (decode-universal-time (unix-epoch-to-universal-time unix-epoch))
+ (format nil "~4,1,0,'0@A-~2,1,0,'0@A-~2,1,0,'0@A, ~2,1,0,'0@A:~2,1,0,'0@A:~2,1,0,'0@A"
+ year month date hour minute second)))
+
+(defmethod print-message ((message irc:irc-rpl_whoisidle-message) receiver)
+ (irc:destructuring-arguments (me nickname idle signon &rest rest) message
+ (declare (ignore me rest))
+ (formatting-message (t message receiver)
+ ((format t " "))
+ ((with-drawing-options (*standard-output* :ink +gray33+ :text-size :small)
+ (present nickname 'nickname)
+ (write-char #\Space)
+ (format-message* (format nil "was idle ~A seconds, signed on: ~A"
+ idle (format-unix-epoch (parse-integer signon)))
+ :start-length (length nickname)))))))
;;; channel management messages
@@ -343,18 +367,25 @@
(formatting-message (t message receiver)
((format t " "))
((with-drawing-options (*standard-output* :ink +gray33+ :text-size :small)
- (if (null sender)
- (format-message* (format nil "Topic for ~A: ~A" channel topic))
- (progn
- (present sender 'nickname)
- (format-message* (format nil " set the topic for ~A to ~A" channel topic))))))))
+ (cond
+ ((and (null sender) (null topic))
+ (format-message* (format nil "No topic for ~A" channel)))
+ ((null sender)
+ (format-message* (format nil "Topic for ~A: ~A" channel topic)))
+ ((null topic)
+ (present sender 'nickname)
+ (format-message* (format nil " cleared the topic of ~A" channel)))
+ (t
+ (present sender 'nickname)
+ (format-message* (format nil " set the topic for ~A to ~A" channel topic))))))))
(defmethod print-message ((message irc:irc-topic-message) receiver)
(irc:destructuring-arguments (channel &last topic) message
(print-topic receiver message (irc:source message) channel topic)))
(defmethod print-message ((message irc:irc-rpl_topic-message) receiver)
- (irc:destructuring-arguments (channel &last topic) message
+ (irc:destructuring-arguments (target channel &optional topic) message
+ (declare (ignore target))
(print-topic receiver message nil channel topic)))
(defmethod print-message ((message irc:irc-rpl_topicwhotime-message) receiver)
@@ -362,10 +393,9 @@
((format t " "))
((with-drawing-options (*standard-output* :ink +gray33+ :text-size :small)
(irc:destructuring-arguments (me channel who time) message
- (declare (ignore me
- time ; TODO: no date display for now.
- ))
- (format-message* (format nil "~A topic set by ~A" channel who)))))))
+ (declare (ignore me))
+ (format-message* (format nil "~A topic set by ~A on ~A" channel who
+ (format-unix-epoch (parse-integer time)))))))))
(defmethod print-message ((message irc:irc-rpl_namreply-message) receiver)
(irc:destructuring-arguments (me privacy channel &last nicks) message
--- /project/beirc/cvsroot/beirc/receivers.lisp 2006/03/06 10:21:28 1.21
+++ /project/beirc/cvsroot/beirc/receivers.lisp 2006/03/12 09:48:57 1.22
@@ -85,19 +85,24 @@
(rec (find-receiver name connection frame)))
(if rec
rec
- (let ((*application-frame* frame)
- (receiver (apply 'make-paneless-receiver normalized-name :connection connection
- initargs)))
- (initialize-receiver-with-pane receiver frame
- (with-look-and-feel-realization
- ((frame-manager *application-frame*) *application-frame*)
- (make-clim-application-pane
- :display-function
- (lambda (frame pane)
- (beirc-app-display frame pane receiver))
- :display-time nil
- :min-width 600 :min-height 800
- :incremental-redisplay t)))
+ (let* ((*application-frame* frame)
+ (receiver (apply 'make-paneless-receiver normalized-name :connection connection
+ initargs))
+ (creator (lambda (frame)
+ (initialize-receiver-with-pane receiver frame
+ (with-look-and-feel-realization
+ ((frame-manager *application-frame*) *application-frame*)
+ (make-clim-application-pane
+ :display-function
+ (lambda (frame pane)
+ (beirc-app-display frame pane receiver))
+ :display-time nil
+ :min-width 600 :min-height 800
+ :incremental-redisplay t)))
+ (update-drawing-options receiver))))
+ (if (equal (current-process) (ui-process frame))
+ (funcall creator frame)
+ (queue-event (frame-top-level-sheet frame) (make-instance 'new-sheet-event :sheet frame :creator creator)))
(setf (gethash (list connection normalized-name) (receivers frame)) receiver)
receiver))))
@@ -209,18 +214,21 @@
(declare (ignore modes args))
(intern-receiver channel (irc:connection message) frame :channel channel)))))
-(macrolet ((define-current-receiver-message-types (&rest mtypes)
+(macrolet ((define-current-receiver-or-server-message-types (&rest mtypes)
`(progn
,@(loop for mtype in mtypes
collect `(defmethod receiver-for-message ((message ,mtype) frame)
- (current-receiver frame))))))
- (define-current-receiver-message-types
+ (if (equal (connection (current-receiver frame)) (irc:connection message))
+ (current-receiver frame)
+ (server-receiver frame (irc:connection message))))))))
+ (define-current-receiver-or-server-message-types
irc:irc-rpl_whoisuser-message
irc:irc-rpl_whoischannels-message
- irc:irc-rpl_whoisserver-message
- irc:irc-rpl_whoisidentified-message
- irc:irc-rpl_away-message
- irc:irc-err_nosuchnick-message))
+ irc:irc-rpl_whoisserver-message
+ irc:irc-rpl_whoisidentified-message
+ irc:irc-rpl_whoisidle-message
+ irc:irc-rpl_away-message
+ irc:irc-err_nosuchnick-message))
(macrolet ((define-ignore-message-types (&rest mtypes)
`(progn
@@ -270,10 +278,12 @@
(define-delegate current-focused-nicks focused-nicks t))
(defun update-drawing-options (receiver)
- (set-drawing-options-for-pane-in-tab-layout (pane receiver)
- `(:ink ,(cond ((> (messages-directed-to-me receiver) 0) +green+)
- ((> (unseen-messages receiver) 0) +red+)
- (t +black+)))))
+ (when (and (slot-boundp receiver 'pane) (sheetp (pane receiver))
+ (find-in-tab-panes-list (pane receiver) 'tab-layout-pane))
+ (set-drawing-options-for-pane-in-tab-layout (pane receiver)
+ `(:ink ,(cond ((> (messages-directed-to-me receiver) 0) +green+)
+ ((> (unseen-messages receiver) 0) +red+)
+ (t +black+))))))
(defmethod switch-to-pane :after ((pane sheet) (parent (eql 'tab-layout-pane)))
(let ((my-tab-layout-pane (find-pane-named *application-frame* 'query)))
--- /project/beirc/cvsroot/beirc/events.lisp 2006/03/12 09:48:57 NONE
+++ /project/beirc/cvsroot/beirc/events.lisp 2006/03/12 09:48:57 1.1
(in-package :beirc)
;;; Here comes the trick:
;;; Although I would pretty much prefer an implementation of CLIM
;;; which is thread safe, I figure we better go through the central
;;; event loop. We define a new event class, subclass of
;;; WINDOW-MANAGER-EVENT, and when ever we want to update the display
;;; we send it to the frame.
(defclass foo-event (clim:window-manager-event)
((sheet :initarg :sheet :reader event-sheet)
(receiver :initarg :receiver :reader receiver)))
;;for updating the time display, triggered from TICKER
(defclass bar-event (clim:window-manager-event)
((sheet :initarg :sheet :reader event-sheet)))
(defclass new-sheet-event (clim:window-manager-event)
((sheet :initarg :sheet :reader event-sheet)
(closure :initarg :creator :reader sheet-creation-closure)
(receiver :initarg :receiver :reader receiver)))