source: branches/working-0709/ccl/cocoa-ide/hemlock/src/archive/window.lisp

Last change on this file was 6567, checked in by Gary Byers, 18 years ago

Move lots of (currently unused, often unlikely to ever be used) stuff to an
archive directory.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.6 KB
Line 
1;;; -*- Log: hemlock.log; Package: Hemlock-Internals -*-
2;;;
3;;; **********************************************************************
4;;; This code was written as part of the CMU Common Lisp project at
5;;; Carnegie Mellon University, and has been placed in the public domain.
6;;;
7#+CMU (ext:file-comment
8 "$Header$")
9;;;
10;;; **********************************************************************
11;;;
12;;; This file contains implementation independent code which implements
13;;; the Hemlock window primitives and most of the code which defines
14;;; other aspects of the interface to redisplay.
15;;;
16;;; Written by Bill Chiles and Rob MacLachlan.
17;;;
18
19(in-package :hemlock-internals)
20
21(defconstant unaltered-bits #b000
22 "This is the value of the dis-line-flags when a line is neither moved nor
23 changed nor new.")
24(defconstant changed-bit #b001
25 "This bit is set in the dis-line-flags when a line is found to be changed.")
26(defconstant moved-bit #b010
27 "This bit is set in the dis-line-flags when a line is found to be moved.")
28(defconstant new-bit #b100
29 "This bit is set in the dis-line-flags when a line is found to be new.")
30
31
32
33;;;; CURRENT-WINDOW.
34
35(defvar *current-window* nil "The current window object.")
36(defvar *window-list* () "A list of all window objects.")
37
38(declaim (inline current-window))
39
40(defun current-window ()
41 "Return the current window. The current window is specially treated by
42 redisplay in several ways, the most important of which is that is does
43 recentering, ensuring that the Buffer-Point of the current window's
44 Window-Buffer is always displayed. This may be set with Setf."
45 *current-window*)
46
47(defun %set-current-window (new-window)
48 (invoke-hook hemlock::set-window-hook new-window)
49 (move-mark (window-point *current-window*)
50 (buffer-point (window-buffer *current-window*)))
51 (move-mark (buffer-point (window-buffer new-window))
52 (window-point new-window))
53 (setq *current-window* new-window))
54
55
56
57
58;;;; Window structure support.
59
60(defun %print-hwindow (obj stream depth)
61 (declare (ignore depth))
62 (write-string "#<Hemlock Window \"" stream)
63 (write-string (buffer-name (window-buffer obj)) stream)
64 (write-string "\">" stream))
65
66
67(defun window-buffer (window)
68 "Return the buffer which is displayed in Window."
69 (window-%buffer window))
70
71(defun %set-window-buffer (window new-buffer)
72 (unless (bufferp new-buffer) (error "~S is not a buffer." new-buffer))
73 (unless (windowp window) (error "~S is not a window." window))
74 (unless (eq new-buffer (window-buffer window))
75 (invoke-hook hemlock::window-buffer-hook window new-buffer)
76 ;;
77 ;; Move the window's marks to the new start.
78 (let ((buffer (window-buffer window)))
79 (setf (buffer-windows buffer) (delete window (buffer-windows buffer)))
80 (move-mark (buffer-display-start buffer) (window-display-start window))
81 (push window (buffer-windows new-buffer))
82 (move-mark (window-point window) (buffer-point new-buffer))
83 (move-mark (window-display-start window) (buffer-display-start new-buffer))
84 (move-mark (window-display-end window) (buffer-display-start new-buffer)))
85 ;;
86 ;; Delete all the dis-lines, and nil out the line and chars so they get
87 ;; gc'ed.
88 (let ((first (window-first-line window))
89 (last (window-last-line window))
90 (free (window-spare-lines window)))
91 (unless (eq (cdr first) *the-sentinel*)
92 (shiftf (cdr last) free (cdr first) *the-sentinel*))
93 (dolist (dl free)
94 (setf (dis-line-line dl) nil (dis-line-old-chars dl) nil))
95 (setf (window-spare-lines window) free))
96 ;;
97 ;; Set the last line and first&last changed so we know there's nothing there.
98 (setf (window-last-line window) *the-sentinel*
99 (window-first-changed window) *the-sentinel*
100 (window-last-changed window) *the-sentinel*)
101 ;;
102 ;; Make sure the window gets updated, and set the buffer.
103 (setf (window-tick window) -3)
104 (setf (window-%buffer window) new-buffer)))
105
106
107
108
109;;; %INIT-REDISPLAY sets up redisplay's internal data structures. We create
110;;; initial windows, setup some hooks to cause modeline recomputation, and call
111;;; any device init necessary. This is called from ED.
112;;;
113(defun %init-redisplay (display)
114 (%init-screen-manager display)
115 (add-hook hemlock::buffer-major-mode-hook 'queue-buffer-change)
116 (add-hook hemlock::buffer-minor-mode-hook 'queue-buffer-change)
117 (add-hook hemlock::buffer-name-hook 'queue-buffer-change)
118 (add-hook hemlock::buffer-pathname-hook 'queue-buffer-change)
119 (add-hook hemlock::buffer-modified-hook 'queue-buffer-change)
120 (add-hook hemlock::window-buffer-hook 'queue-window-change)
121 (let ((device (device-hunk-device (window-hunk (current-window)))))
122 (funcall (device-init device) device))
123 (center-window *current-window* (current-point)))
124
125
126
127
128;;;; Modelines-field structure support.
129
130(defun print-modeline-field (obj stream ignore)
131 (declare (ignore ignore))
132 (write-string "#<Hemlock Modeline-field " stream)
133 (prin1 (modeline-field-%name obj) stream)
134 (write-string ">" stream))
135
136(defun print-modeline-field-info (obj stream ignore)
137 (declare (ignore ignore))
138 (write-string "#<Hemlock Modeline-field-info " stream)
139 (prin1 (modeline-field-%name (ml-field-info-field obj)) stream)
140 (write-string ">" stream))
141
142
143(defvar *modeline-field-names* (make-hash-table))
144
145(defun make-modeline-field (&key name width function)
146 "Returns a modeline-field object."
147 (unless (or (eq width nil) (and (integerp width) (plusp width)))
148 (error "Width must be nil or a positive integer."))
149 (when (gethash name *modeline-field-names*)
150 (with-simple-restart (continue
151 "Use the new definition for this modeline field.")
152 (error "Modeline field ~S already exists."
153 (gethash name *modeline-field-names*))))
154 (setf (gethash name *modeline-field-names*)
155 (%make-modeline-field name function width)))
156
157(defun modeline-field (name)
158 "Returns the modeline-field object named name. If none exists, return nil."
159 (gethash name *modeline-field-names*))
160
161
162(declaim (inline modeline-field-name modeline-field-width
163 modeline-field-function))
164
165(defun modeline-field-name (ml-field)
166 "Returns the name of a modeline field object."
167 (modeline-field-%name ml-field))
168
169(defun %set-modeline-field-name (ml-field name)
170 (check-type ml-field modeline-field)
171 (when (gethash name *modeline-field-names*)
172 (error "Modeline field ~S already exists."
173 (gethash name *modeline-field-names*)))
174 (remhash (modeline-field-%name ml-field) *modeline-field-names*)
175 (setf (modeline-field-%name ml-field) name)
176 (setf (gethash name *modeline-field-names*) ml-field))
177
178(defun modeline-field-width (ml-field)
179 "Returns the width of a modeline field."
180 (modeline-field-%width ml-field))
181
182(declaim (special *buffer-list*))
183
184(defun %set-modeline-field-width (ml-field width)
185 (check-type ml-field modeline-field)
186 (unless (or (eq width nil) (and (integerp width) (plusp width)))
187 (error "Width must be nil or a positive integer."))
188 (unless (eql width (modeline-field-%width ml-field))
189 (setf (modeline-field-%width ml-field) width)
190 (dolist (b *buffer-list*)
191 (when (buffer-modeline-field-p b ml-field)
192 (dolist (w (buffer-windows b))
193 (update-modeline-fields b w)))))
194 width)
195
196(defun modeline-field-function (ml-field)
197 "Returns the function of a modeline field object. It returns a string."
198 (modeline-field-%function ml-field))
199
200(defun %set-modeline-field-function (ml-field function)
201 (check-type ml-field modeline-field)
202 (check-type function (or symbol function))
203 (setf (modeline-field-%function ml-field) function)
204 (dolist (b *buffer-list*)
205 (when (buffer-modeline-field-p b ml-field)
206 (dolist (w (buffer-windows b))
207 (update-modeline-field b w ml-field))))
208 function)
209
210
211
212
213;;;; Modelines maintenance.
214
215;;; Each window stores a modeline-buffer which is a string hunk-width-limit
216;;; long. Whenever a field is updated, we must maintain a maximally long
217;;; representation of the modeline in case the window is resized. Updating
218;;; then first gets the modeline-buffer setup, and second blasts the necessary
219;;; portion into the window's modeline-dis-line, setting the dis-line's changed
220;;; flag.
221;;;
222
223(defun update-modeline-fields (buffer window)
224 "Recompute all the fields of buffer's modeline for window, so the next
225 redisplay will reflect changes."
226 (let ((ml-buffer (window-modeline-buffer window)))
227 (declare (simple-string ml-buffer))
228 (when ml-buffer
229 (let* ((ml-buffer-len
230 (do ((finfos (buffer-%modeline-fields buffer) (cdr finfos))
231 (start 0 (blt-modeline-field-buffer
232 ml-buffer (car finfos) buffer window start)))
233 ((null finfos) start)))
234 (dis-line (window-modeline-dis-line window))
235 (len (min (window-width window) ml-buffer-len)))
236 (replace (the simple-string (dis-line-chars dis-line)) ml-buffer
237 :end1 len :end2 len)
238 (setf (window-modeline-buffer-len window) ml-buffer-len)
239 (setf (dis-line-length dis-line) len)
240 (setf (dis-line-flags dis-line) changed-bit)))))
241
242;;; UPDATE-MODELINE-FIELD must replace the entire dis-line-chars with ml-buffer
243;;; after blt'ing into buffer. Otherwise it has to do all the work
244;;; BLT-MODELINE-FIELD-BUFFER to figure out how to adjust dis-line-chars. It
245;;; isn't worth it. Since things could have shifted around, after calling
246;;; BLT-MODELINE-FIELD-BUFFER, we get the last field's end to know how long
247;;; the buffer is now.
248;;;
249(defun update-modeline-field (buffer window field)
250 "Recompute the field of the buffer's modeline for window, so the next
251 redisplay will reflect the change. Field is either a modeline-field object
252 or the name of one for buffer."
253 (let ((finfo (internal-buffer-modeline-field-p buffer field)))
254 (unless finfo
255 (error "~S is not a modeline-field or the name of one for buffer ~S."
256 field buffer))
257 (let ((ml-buffer (window-modeline-buffer window))
258 (dis-line (window-modeline-dis-line window)))
259 (declare (simple-string ml-buffer))
260 (blt-modeline-field-buffer ml-buffer finfo buffer window
261 (ml-field-info-start finfo) t)
262 (let* ((ml-buffer-len (ml-field-info-end
263 (car (last (buffer-%modeline-fields buffer)))))
264 (dis-len (min (window-width window) ml-buffer-len)))
265 (replace (the simple-string (dis-line-chars dis-line)) ml-buffer
266 :end1 dis-len :end2 dis-len)
267 (setf (window-modeline-buffer-len window) ml-buffer-len)
268 (setf (dis-line-length dis-line) dis-len)
269 (setf (dis-line-flags dis-line) changed-bit)))))
270
271(defvar *truncated-field-char* #\!)
272
273;;; BLT-MODELINE-FIELD-BUFFER takes a Hemlock buffer, Hemlock window, the
274;;; window's modeline buffer, a modeline-field-info object, a start in the
275;;; modeline buffer, and an optional indicating whether a variable width field
276;;; should be handled carefully. When the field is fixed-width, this is
277;;; simple. When it is variable, we possibly have to shift all the text in the
278;;; buffer right or left before storing the new string, updating all the
279;;; finfo's after the one we're updating. It is an error for the
280;;; modeline-field-function to return anything but a simple-string with
281;;; standard-chars. This returns the end of the field blasted into ml-buffer.
282;;;
283(defun blt-modeline-field-buffer (ml-buffer finfo buffer window start
284 &optional fix-other-fields-p)
285 (declare (simple-string ml-buffer))
286 (let* ((f (ml-field-info-field finfo))
287 (width (modeline-field-width f))
288 (string (funcall (modeline-field-function f) buffer window))
289 (str-len (length string)))
290 (declare (simple-string string))
291 (setf (ml-field-info-start finfo) start)
292 (setf (ml-field-info-end finfo)
293 (cond
294 ((not width)
295 (let ((end (min (+ start str-len) hunk-width-limit))
296 (last-end (ml-field-info-end finfo)))
297 (when (and fix-other-fields-p (/= end last-end))
298 (blt-ml-field-buffer-fix ml-buffer finfo buffer window
299 end last-end))
300 (replace ml-buffer string :start1 start :end1 end :end2 str-len)
301 end))
302 ((= str-len width)
303 (let ((end (min (+ start width) hunk-width-limit)))
304 (replace ml-buffer string :start1 start :end1 end :end2 width)
305 end))
306 ((> str-len width)
307 (let* ((end (min (+ start width) hunk-width-limit))
308 (end-1 (1- end)))
309 (replace ml-buffer string :start1 start :end1 end-1 :end2 width)
310 (setf (schar ml-buffer end-1) *truncated-field-char*)
311 end))
312 (t
313 (let ((buf-replace-end (min (+ start str-len) hunk-width-limit))
314 (buf-field-end (min (+ start width) hunk-width-limit)))
315 (replace ml-buffer string
316 :start1 start :end1 buf-replace-end :end2 str-len)
317 (fill ml-buffer #\space :start buf-replace-end :end buf-field-end)
318 buf-field-end))))))
319
320;;; BLT-ML-FIELD-BUFFER-FIX shifts the contents of ml-buffer in the direction
321;;; of last-end to end. finfo is a modeline-field-info structure in buffer's
322;;; list of these. If there are none following finfo, then we simply store the
323;;; new end of the buffer. After blt'ing the text around, we have to update
324;;; all the finfos' starts and ends making sure nobody gets to stick out over
325;;; the ml-buffer's end.
326;;;
327(defun blt-ml-field-buffer-fix (ml-buffer finfo buffer window end last-end)
328 (declare (simple-string ml-buffer))
329 (let ((finfos (do ((f (buffer-%modeline-fields buffer) (cdr f)))
330 ((null f) (error "This field must be here."))
331 (if (eq (car f) finfo)
332 (return (cdr f))))))
333 (cond
334 ((not finfos)
335 (setf (window-modeline-buffer-len window) (min end hunk-width-limit)))
336 (t
337 (let ((buffer-len (window-modeline-buffer-len window)))
338 (replace ml-buffer ml-buffer
339 :start1 end
340 :end1 (min (+ end (- buffer-len last-end)) hunk-width-limit)
341 :start2 last-end :end2 buffer-len)
342 (let ((diff (- end last-end)))
343 (macrolet ((frob (f)
344 `(setf ,f (min (+ ,f diff) hunk-width-limit))))
345 (dolist (f finfos)
346 (frob (ml-field-info-start f))
347 (frob (ml-field-info-end f)))
348 (frob (window-modeline-buffer-len window)))))))))
349
350
351
352
353;;;; Default modeline and update hooks.
354
355(make-modeline-field :name :hemlock-literal :width 8
356 :function #'(lambda (buffer window)
357 "Returns \"Hemlock \"."
358 (declare (ignore buffer window))
359 "Hemlock "))
360
361(make-modeline-field
362 :name :package
363 :function #'(lambda (buffer window)
364 "Returns the value of buffer's \"Current Package\" followed
365 by a colon and two spaces, or a string with one space."
366 (declare (ignore window))
367 (if (hemlock-bound-p 'hemlock::current-package :buffer buffer)
368 (let ((val (variable-value 'hemlock::current-package
369 :buffer buffer)))
370 (if val
371 (format nil "~A: " val)
372 " "))
373 " ")))
374
375(make-modeline-field
376 :name :modes
377 :function #'(lambda (buffer window)
378 "Returns buffer's modes followed by one space."
379 (declare (ignore window))
380 (format nil "~A " (buffer-modes buffer))))
381
382(make-modeline-field
383 :name :modifiedp
384 :function #'(lambda (buffer window)
385 "Returns \"* \" if buffer is modified, or the empty string."
386 (declare (ignore window))
387 (let ((modifiedp (buffer-modified buffer)))
388 (if modifiedp
389 "* "
390 ""))))
391
392(make-modeline-field
393 :name :buffer-name
394 :function #'(lambda (buffer window)
395 "Returns buffer's name followed by a colon and a space if the
396 name is not derived from the buffer's pathname, or the empty
397 string."
398 (declare (ignore window))
399 (let ((pn (buffer-pathname buffer))
400 (name (buffer-name buffer)))
401 (cond ((not pn)
402 (format nil "~A: " name))
403 ((string/= (hemlock::pathname-to-buffer-name pn) name)
404 (format nil "~A: " name))
405 (t "")))))
406
407
408;;; MAXIMUM-MODELINE-PATHNAME-LENGTH-HOOK is called whenever "Maximum Modeline
409;;; Pathname Length" is set.
410;;;
411(defun maximum-modeline-pathname-length-hook (name kind where new-value)
412 (declare (ignore name new-value))
413 (if (eq kind :buffer)
414 (hi::queue-buffer-change where)
415 (dolist (buffer *buffer-list*)
416 (when (and (buffer-modeline-field-p buffer :buffer-pathname)
417 (buffer-windows buffer))
418 (hi::queue-buffer-change buffer)))))
419
420(defun buffer-pathname-ml-field-fun (buffer window)
421 "Returns the namestring of buffer's pathname if there is one. When
422 \"Maximum Modeline Pathname Length\" is set, and the namestring is too long,
423 return a truncated namestring chopping off leading directory specifications."
424 (declare (ignore window))
425 (let ((pn (buffer-pathname buffer)))
426 (if pn
427 (let* ((name (namestring pn))
428 (length (length name))
429 ;; Prefer a buffer local value over the global one.
430 ;; Because variables don't work right, blow off looking for
431 ;; a value in the buffer's modes. In the future this will
432 ;; be able to get the "current" value as if buffer were current.
433 (max (if (hemlock-bound-p 'hemlock::maximum-modeline-pathname-length
434 :buffer buffer)
435 (variable-value 'hemlock::maximum-modeline-pathname-length
436 :buffer buffer)
437 (variable-value 'hemlock::maximum-modeline-pathname-length
438 :global))))
439 (declare (simple-string name))
440 (if (or (not max) (<= length max))
441 name
442 (let* ((extra-chars (+ (- length max) 3))
443 (slash (or (position #\/ name :start extra-chars)
444 ;; If no slash, then file-namestring is very
445 ;; long, and we should include all of it:
446 (position #\/ name :from-end t
447 :end extra-chars))))
448 (if slash
449 (concatenate 'simple-string "..." (subseq name slash))
450 name))))
451 "")))
452
453(make-modeline-field
454 :name :buffer-pathname
455 :function 'buffer-pathname-ml-field-fun)
456
457
458(defvar *default-modeline-fields*
459 (list (modeline-field :hemlock-literal)
460 (modeline-field :package)
461 (modeline-field :modes)
462 (modeline-field :modifiedp)
463 (modeline-field :buffer-name)
464 (modeline-field :buffer-pathname))
465 "This is the default value for \"Default Modeline Fields\".")
466
467
468
469;;; QUEUE-BUFFER-CHANGE is used for various buffer hooks (e.g., mode changes,
470;;; name changes, etc.), so it takes some arguments to ignore. These hooks are
471;;; invoked at a bad time to update the actual modeline-field, and user's may
472;;; have fields that change as a function of the changes this function handles.
473;;; This makes his update easier. It doesn't cost much update the entire line
474;;; anyway.
475;;;
476(defun queue-buffer-change (buffer &optional something-else another-else)
477 (declare (ignore something-else another-else))
478 (push (list #'update-modelines-for-buffer buffer) *things-to-do-once*))
479
480(defun update-modelines-for-buffer (buffer)
481 (unless (eq buffer *echo-area-buffer*)
482 (dolist (w (buffer-windows buffer))
483 (update-modeline-fields buffer w))))
484
485
486;;; QUEUE-WINDOW-CHANGE is used for the "Window Buffer Hook". We ignore the
487;;; argument since this hook function is invoked before any changes are made,
488;;; and the changes must be made before the fields can be set according to the
489;;; window's buffer's properties. Therefore, we must queue the change to
490;;; happen sometime before redisplay but after the change takes effect.
491;;;
492(defun queue-window-change (window &optional something-else)
493 (declare (ignore something-else))
494 (push (list #'update-modeline-for-window window) *things-to-do-once*))
495
496(defun update-modeline-for-window (window)
497 (update-modeline-fields (window-buffer window) window))
498
499
500
501
502;;;; Bitmap setting up new windows and modifying old.
503
504(defvar dummy-line (make-window-dis-line "")
505 "Dummy dis-line that we put at the head of window's dis-lines")
506(setf (dis-line-position dummy-line) -1)
507
508
509;;; WINDOW-FOR-HUNK makes a Hemlock window and sets up its dis-lines and marks
510;;; to display starting at start.
511;;;
512(defun window-for-hunk (hunk start modelinep)
513 (check-type start mark)
514 (setf (bitmap-hunk-changed-handler hunk) #'window-changed)
515 (let ((buffer (line-buffer (mark-line start)))
516 (first (cons dummy-line *the-sentinel*))
517 (width (bitmap-hunk-char-width hunk))
518 (height (bitmap-hunk-char-height hunk)))
519 (when (or (< height minimum-window-lines)
520 (< width minimum-window-columns))
521 (error "Window too small."))
522 (unless buffer (error "Window start is not in a buffer."))
523 (let ((window
524 (internal-make-window
525 :hunk hunk
526 :display-start (copy-mark start :right-inserting)
527 :old-start (copy-mark start :temporary)
528 :display-end (copy-mark start :right-inserting)
529 :%buffer buffer
530 :point (copy-mark (buffer-point buffer))
531 :height height
532 :width width
533 :first-line first
534 :last-line *the-sentinel*
535 :first-changed *the-sentinel*
536 :last-changed first
537 :tick -1)))
538 (push window *window-list*)
539 (push window (buffer-windows buffer))
540 ;;
541 ;; Make the dis-lines.
542 (do ((i (- height) (1+ i))
543 (res ()
544 (cons (make-window-dis-line (make-string width)) res)))
545 ((= i height) (setf (window-spare-lines window) res)))
546 ;;
547 ;; Make the image up to date.
548 (update-window-image window)
549 (setf (bitmap-hunk-start hunk) (cdr (window-first-line window)))
550 ;;
551 ;; If there is a modeline, set it up.
552 (when modelinep
553 (setup-modeline-image buffer window)
554 (setf (bitmap-hunk-modeline-dis-line hunk)
555 (window-modeline-dis-line window)))
556 window)))
557
558;;; SETUP-MODELINE-IMAGE sets up the modeline-dis-line for window using the
559;;; modeline-fields list. This is used by tty redisplay too.
560;;;
561(defun setup-modeline-image (buffer window)
562 (setf (window-modeline-buffer window) (make-string hunk-width-limit))
563 (setf (window-modeline-dis-line window)
564 (make-window-dis-line (make-string (window-width window))))
565 (update-modeline-fields buffer window))
566
567;;; Window-Changed -- Internal
568;;;
569;;; The bitmap-hunk changed handler for windows. This is only called if
570;;; the hunk is not locked. We invalidate the window image and change its
571;;; size, then do a full redisplay.
572;;;
573(defun window-changed (hunk)
574 (let ((window (bitmap-hunk-window hunk)))
575 ;;
576 ;; Nuke all the lines in the window image.
577 (unless (eq (cdr (window-first-line window)) *the-sentinel*)
578 (shiftf (cdr (window-last-line window))
579 (window-spare-lines window)
580 (cdr (window-first-line window))
581 *the-sentinel*))
582 (setf (bitmap-hunk-start hunk) (cdr (window-first-line window)))
583 ;;
584 ;; Add some new spare lines if needed. If width is greater,
585 ;; reallocate the dis-line-chars.
586 (let* ((res (window-spare-lines window))
587 (new-width (bitmap-hunk-char-width hunk))
588 (new-height (bitmap-hunk-char-height hunk))
589 (width (length (the simple-string (dis-line-chars (car res))))))
590 (declare (list res))
591 (when (> new-width width)
592 (setq width new-width)
593 (dolist (dl res)
594 (setf (dis-line-chars dl) (make-string new-width))))
595 (setf (window-height window) new-height (window-width window) new-width)
596 (do ((i (- (* new-height 2) (length res)) (1- i)))
597 ((minusp i))
598 (push (make-window-dis-line (make-string width)) res))
599 (setf (window-spare-lines window) res)
600 ;;
601 ;; Force modeline update.
602 (let ((ml-buffer (window-modeline-buffer window)))
603 (when ml-buffer
604 (let ((dl (window-modeline-dis-line window))
605 (chars (make-string new-width))
606 (len (min new-width (window-modeline-buffer-len window))))
607 (setf (dis-line-old-chars dl) nil)
608 (setf (dis-line-chars dl) chars)
609 (replace chars ml-buffer :end1 len :end2 len)
610 (setf (dis-line-length dl) len)
611 (setf (dis-line-flags dl) changed-bit)))))
612 ;;
613 ;; Prepare for redisplay.
614 (setf (window-tick window) (tick))
615 (update-window-image window)
616 (when (eq window *current-window*) (maybe-recenter-window window))
617 hunk))
618
619
620
621
622;;; EDITOR-FINISH-OUTPUT is used to synch output to a window with the rest of the
623;;; system.
624;;;
625(defun editor-finish-output (window)
626 (let* ((device (device-hunk-device (window-hunk window)))
627 (finish-output (device-finish-output device)))
628 (when finish-output
629 (funcall finish-output device window))))
630
631
632
633
634;;;; Tty setting up new windows and modifying old.
635
636;;; setup-window-image -- Internal
637;;;
638;;; Set up the dis-lines and marks for Window to display starting
639;;; at Start. Height and Width are the number of lines and columns in
640;;; the window.
641;;;
642(defun setup-window-image (start window height width)
643 (check-type start mark)
644 (let ((buffer (line-buffer (mark-line start)))
645 (first (cons dummy-line *the-sentinel*)))
646 (unless buffer (error "Window start is not in a buffer."))
647 (setf (window-display-start window) (copy-mark start :right-inserting)
648 (window-old-start window) (copy-mark start :temporary)
649 (window-display-end window) (copy-mark start :right-inserting)
650 (window-%buffer window) buffer
651 (window-point window) (copy-mark (buffer-point buffer))
652 (window-height window) height
653 (window-width window) width
654 (window-first-line window) first
655 (window-last-line window) *the-sentinel*
656 (window-first-changed window) *the-sentinel*
657 (window-last-changed window) first
658 (window-tick window) -1)
659 (push window *window-list*)
660 (push window (buffer-windows buffer))
661 ;;
662 ;; Make the dis-lines.
663 (do ((i (- height) (1+ i))
664 (res ()
665 (cons (make-window-dis-line (make-string width)) res)))
666 ((= i height) (setf (window-spare-lines window) res)))
667 ;;
668 ;; Make the image up to date.
669 (update-window-image window)))
670
671;;; change-window-image-height -- Internal
672;;;
673;;; Milkshake.
674;;;
675(defun change-window-image-height (window new-height)
676 ;; Nuke all the lines in the window image.
677 (unless (eq (cdr (window-first-line window)) *the-sentinel*)
678 (shiftf (cdr (window-last-line window))
679 (window-spare-lines window)
680 (cdr (window-first-line window))
681 *the-sentinel*))
682 ;; Add some new spare lines if needed.
683 (let* ((res (window-spare-lines window))
684 (width (length (the simple-string (dis-line-chars (car res))))))
685 (declare (list res))
686 (setf (window-height window) new-height)
687 (do ((i (- (* new-height 2) (length res)) (1- i)))
688 ((minusp i))
689 (push (make-window-dis-line (make-string width)) res))
690 (setf (window-spare-lines window) res)))
Note: See TracBrowser for help on using the repository browser.