• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is part of "JTA - Telnet/SSH for the JAVA(tm) platform".
3  *
4  * (c) Matthias L. Jugel, Marcus Mei�ner 1996-2005. All Rights Reserved.
5  *
6  * Please visit http://javatelnet.org/ for updates and contact.
7  *
8  * --LICENSE NOTICE--
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License
11  * as published by the Free Software Foundation; either version 2
12  * of the License, or (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  * --LICENSE NOTICE--
23  *
24  */
25 
26 package de.mud.terminal;
27 
28 import java.util.Arrays;
29 
30 /**
31  * Implementation of a Video Display Unit (VDU) buffer. This class contains all methods to
32  * manipulate the buffer that stores characters and their attributes as well as the regions
33  * displayed.
34  *
35  * @version $Id: VDUBuffer.java 503 2005-10-24 07:34:13Z marcus $
36  */
37 public class VDUBuffer {
38 
39   /** The current version id tag */
40   public final static String ID = "$Id: VDUBuffer.java 503 2005-10-24 07:34:13Z marcus $";
41 
42   /** Enable debug messages. */
43   public final static int debug = 0;
44 
45   public int height, width; /* rows and columns */
46   public boolean[] update; /* contains the lines that need update */
47   public char[][] charArray; /* contains the characters */
48   public int[][] charAttributes; /* contains character attrs */
49   public int bufSize;
50   public int maxBufSize; /* buffer sizes */
51   public int screenBase; /* the actual screen start */
52   public int windowBase; /* where the start displaying */
53   public int scrollMarker; /* marks the last line inserted */
54 
55   private int topMargin; /* top scroll margin */
56   private int bottomMargin; /* bottom scroll margin */
57 
58   // cursor variables
59   protected boolean showcursor = true;
60   protected int cursorX, cursorY;
61 
62   /** Scroll up when inserting a line. */
63   public final static boolean SCROLL_UP = false;
64   /** Scroll down when inserting a line. */
65   public final static boolean SCROLL_DOWN = true;
66 
67   /*
68    * Attributes bit-field usage:
69    *
70    * 8421 8421 8421 8421 8421 8421 8421 8421 |||| |||| |||| |||| |||| |||| |||| |||`- Bold |||| ||||
71    * |||| |||| |||| |||| |||| ||`-- Underline |||| |||| |||| |||| |||| |||| |||| |`--- Invert ||||
72    * |||| |||| |||| |||| |||| |||| `---- Low |||| |||| |||| |||| |||| |||| |||`------ Invisible ||||
73    * |||| |||| |||| ||`+-++++-+++------- Foreground Color |||| |||| |`++-++++-++------------------
74    * Background Color |||| |||| `----------------------------- Fullwidth character
75    * `+++-++++------------------------------- Reserved for future use
76    */
77 
78   /** Make character normal. */
79   public final static int NORMAL = 0x00;
80   /** Make character bold. */
81   public final static int BOLD = 0x01;
82   /** Underline character. */
83   public final static int UNDERLINE = 0x02;
84   /** Invert character. */
85   public final static int INVERT = 0x04;
86   /** Lower intensity character. */
87   public final static int LOW = 0x08;
88   /** Invisible character. */
89   public final static int INVISIBLE = 0x10;
90   /** Unicode full-width character (CJK, et al.) */
91   public final static int FULLWIDTH = 0x8000000;
92 
93   /** how much to left shift the foreground color */
94   public final static int COLOR_FG_SHIFT = 5;
95   /** how much to left shift the background color */
96   public final static int COLOR_BG_SHIFT = 14;
97   /** color mask */
98   public final static int COLOR = 0x7fffe0; /* 0000 0000 0111 1111 1111 1111 1110 0000 */
99   /** foreground color mask */
100   public final static int COLOR_FG = 0x3fe0; /* 0000 0000 0000 0000 0011 1111 1110 0000 */
101   /** background color mask */
102   public final static int COLOR_BG = 0x7fc000; /* 0000 0000 0111 1111 1100 0000 0000 0000 */
103 
104   /**
105    * Create a new video display buffer with the passed width and height in characters.
106    *
107    * @param width
108    *          the length of the character lines
109    * @param height
110    *          the amount of lines on the screen
111    */
VDUBuffer(int width, int height)112   public VDUBuffer(int width, int height) {
113     // set the display screen size
114     setScreenSize(width, height, false);
115   }
116 
117   /**
118    * Create a standard video display buffer with 80 columns and 24 lines.
119    */
VDUBuffer()120   public VDUBuffer() {
121     this(80, 24);
122   }
123 
124   /**
125    * Put a character on the screen with normal font and outline. The character previously on that
126    * position will be overwritten. You need to call redraw() to update the screen.
127    *
128    * @param c
129    *          x-coordinate (column)
130    * @param l
131    *          y-coordinate (line)
132    * @param ch
133    *          the character to show on the screen
134    * @see #insertChar
135    * @see #deleteChar
136    * @see #redraw
137    */
putChar(int c, int l, char ch)138   public void putChar(int c, int l, char ch) {
139     putChar(c, l, ch, NORMAL);
140   }
141 
142   /**
143    * Put a character on the screen with specific font and outline. The character previously on that
144    * position will be overwritten. You need to call redraw() to update the screen.
145    *
146    * @param c
147    *          x-coordinate (column)
148    * @param l
149    *          y-coordinate (line)
150    * @param ch
151    *          the character to show on the screen
152    * @param attributes
153    *          the character attributes
154    * @see #BOLD
155    * @see #UNDERLINE
156    * @see #INVERT
157    * @see #INVISIBLE
158    * @see #NORMAL
159    * @see #LOW
160    * @see #insertChar
161    * @see #deleteChar
162    * @see #redraw
163    */
164 
putChar(int c, int l, char ch, int attributes)165   public void putChar(int c, int l, char ch, int attributes) {
166     charArray[screenBase + l][c] = ch;
167     charAttributes[screenBase + l][c] = attributes;
168     if (l < height) {
169       update[l + 1] = true;
170     }
171   }
172 
173   /**
174    * Get the character at the specified position.
175    *
176    * @param c
177    *          x-coordinate (column)
178    * @param l
179    *          y-coordinate (line)
180    * @see #putChar
181    */
getChar(int c, int l)182   public char getChar(int c, int l) {
183     return charArray[screenBase + l][c];
184   }
185 
186   /**
187    * Get the attributes for the specified position.
188    *
189    * @param c
190    *          x-coordinate (column)
191    * @param l
192    *          y-coordinate (line)
193    * @see #putChar
194    */
getAttributes(int c, int l)195   public int getAttributes(int c, int l) {
196     return charAttributes[screenBase + l][c];
197   }
198 
199   /**
200    * Insert a character at a specific position on the screen. All character right to from this
201    * position will be moved one to the right. You need to call redraw() to update the screen.
202    *
203    * @param c
204    *          x-coordinate (column)
205    * @param l
206    *          y-coordinate (line)
207    * @param ch
208    *          the character to insert
209    * @param attributes
210    *          the character attributes
211    * @see #BOLD
212    * @see #UNDERLINE
213    * @see #INVERT
214    * @see #INVISIBLE
215    * @see #NORMAL
216    * @see #LOW
217    * @see #putChar
218    * @see #deleteChar
219    * @see #redraw
220    */
insertChar(int c, int l, char ch, int attributes)221   public void insertChar(int c, int l, char ch, int attributes) {
222     System.arraycopy(charArray[screenBase + l], c, charArray[screenBase + l], c + 1, width - c - 1);
223     System.arraycopy(charAttributes[screenBase + l], c, charAttributes[screenBase + l], c + 1,
224         width - c - 1);
225     putChar(c, l, ch, attributes);
226   }
227 
228   /**
229    * Delete a character at a given position on the screen. All characters right to the position will
230    * be moved one to the left. You need to call redraw() to update the screen.
231    *
232    * @param c
233    *          x-coordinate (column)
234    * @param l
235    *          y-coordinate (line)
236    * @see #putChar
237    * @see #insertChar
238    * @see #redraw
239    */
deleteChar(int c, int l)240   public void deleteChar(int c, int l) {
241     if (c < width - 1) {
242       System.arraycopy(charArray[screenBase + l], c + 1, charArray[screenBase + l], c, width - c
243           - 1);
244       System.arraycopy(charAttributes[screenBase + l], c + 1, charAttributes[screenBase + l], c,
245           width - c - 1);
246     }
247     putChar(width - 1, l, (char) 0);
248   }
249 
250   /**
251    * Put a String at a specific position. Any characters previously on that position will be
252    * overwritten. You need to call redraw() for screen update.
253    *
254    * @param c
255    *          x-coordinate (column)
256    * @param l
257    *          y-coordinate (line)
258    * @param s
259    *          the string to be shown on the screen
260    * @see #BOLD
261    * @see #UNDERLINE
262    * @see #INVERT
263    * @see #INVISIBLE
264    * @see #NORMAL
265    * @see #LOW
266    * @see #putChar
267    * @see #insertLine
268    * @see #deleteLine
269    * @see #redraw
270    */
putString(int c, int l, String s)271   public void putString(int c, int l, String s) {
272     putString(c, l, s, NORMAL);
273   }
274 
275   /**
276    * Put a String at a specific position giving all characters the same attributes. Any characters
277    * previously on that position will be overwritten. You need to call redraw() to update the
278    * screen.
279    *
280    * @param c
281    *          x-coordinate (column)
282    * @param l
283    *          y-coordinate (line)
284    * @param s
285    *          the string to be shown on the screen
286    * @param attributes
287    *          character attributes
288    * @see #BOLD
289    * @see #UNDERLINE
290    * @see #INVERT
291    * @see #INVISIBLE
292    * @see #NORMAL
293    * @see #LOW
294    * @see #putChar
295    * @see #insertLine
296    * @see #deleteLine
297    * @see #redraw
298    */
putString(int c, int l, String s, int attributes)299   public void putString(int c, int l, String s, int attributes) {
300     for (int i = 0; i < s.length() && c + i < width; i++) {
301       putChar(c + i, l, s.charAt(i), attributes);
302     }
303   }
304 
305   /**
306    * Insert a blank line at a specific position. The current line and all previous lines are
307    * scrolled one line up. The top line is lost. You need to call redraw() to update the screen.
308    *
309    * @param l
310    *          the y-coordinate to insert the line
311    * @see #deleteLine
312    * @see #redraw
313    */
insertLine(int l)314   public void insertLine(int l) {
315     insertLine(l, 1, SCROLL_UP);
316   }
317 
318   /**
319    * Insert blank lines at a specific position. You need to call redraw() to update the screen
320    *
321    * @param l
322    *          the y-coordinate to insert the line
323    * @param n
324    *          amount of lines to be inserted
325    * @see #deleteLine
326    * @see #redraw
327    */
insertLine(int l, int n)328   public void insertLine(int l, int n) {
329     insertLine(l, n, SCROLL_UP);
330   }
331 
332   /**
333    * Insert a blank line at a specific position. Scroll text according to the argument. You need to
334    * call redraw() to update the screen
335    *
336    * @param l
337    *          the y-coordinate to insert the line
338    * @param scrollDown
339    *          scroll down
340    * @see #deleteLine
341    * @see #SCROLL_UP
342    * @see #SCROLL_DOWN
343    * @see #redraw
344    */
insertLine(int l, boolean scrollDown)345   public void insertLine(int l, boolean scrollDown) {
346     insertLine(l, 1, scrollDown);
347   }
348 
349   /**
350    * Insert blank lines at a specific position. The current line and all previous lines are scrolled
351    * one line up. The top line is lost. You need to call redraw() to update the screen.
352    *
353    * @param l
354    *          the y-coordinate to insert the line
355    * @param n
356    *          number of lines to be inserted
357    * @param scrollDown
358    *          scroll down
359    * @see #deleteLine
360    * @see #SCROLL_UP
361    * @see #SCROLL_DOWN
362    * @see #redraw
363    */
insertLine(int l, int n, boolean scrollDown)364   public synchronized void insertLine(int l, int n, boolean scrollDown) {
365     char cbuf[][] = null;
366     int abuf[][] = null;
367     int offset = 0;
368     int oldBase = screenBase;
369 
370     int newScreenBase = screenBase;
371     int newWindowBase = windowBase;
372     int newBufSize = bufSize;
373 
374     if (l > bottomMargin) {
375       return;
376     }
377     int top =
378         (l < topMargin ? 0 : (l > bottomMargin ? (bottomMargin + 1 < height ? bottomMargin + 1
379             : height - 1) : topMargin));
380     int bottom =
381         (l > bottomMargin ? height - 1 : (l < topMargin ? (topMargin > 0 ? topMargin - 1 : 0)
382             : bottomMargin));
383 
384     // System.out.println("l is "+l+", top is "+top+", bottom is "+bottom+", bottomargin is "+bottomMargin+", topMargin is "+topMargin);
385 
386     if (scrollDown) {
387       if (n > (bottom - top)) {
388         n = (bottom - top);
389       }
390       int size = bottom - l - (n - 1);
391       if (size < 0) {
392         size = 0;
393       }
394       cbuf = new char[size][];
395       abuf = new int[size][];
396 
397       System.arraycopy(charArray, oldBase + l, cbuf, 0, bottom - l - (n - 1));
398       System.arraycopy(charAttributes, oldBase + l, abuf, 0, bottom - l - (n - 1));
399       System.arraycopy(cbuf, 0, charArray, oldBase + l + n, bottom - l - (n - 1));
400       System.arraycopy(abuf, 0, charAttributes, oldBase + l + n, bottom - l - (n - 1));
401       cbuf = charArray;
402       abuf = charAttributes;
403     } else {
404       try {
405         if (n > (bottom - top) + 1) {
406           n = (bottom - top) + 1;
407         }
408         if (bufSize < maxBufSize) {
409           if (bufSize + n > maxBufSize) {
410             offset = n - (maxBufSize - bufSize);
411             scrollMarker += offset;
412             newBufSize = maxBufSize;
413             newScreenBase = maxBufSize - height - 1;
414             newWindowBase = screenBase;
415           } else {
416             scrollMarker += n;
417             newScreenBase += n;
418             newWindowBase += n;
419             newBufSize += n;
420           }
421 
422           cbuf = new char[newBufSize][];
423           abuf = new int[newBufSize][];
424         } else {
425           offset = n;
426           cbuf = charArray;
427           abuf = charAttributes;
428         }
429         // copy anything from the top of the buffer (+offset) to the new top
430         // up to the screenBase.
431         if (oldBase > 0) {
432           System.arraycopy(charArray, offset, cbuf, 0, oldBase - offset);
433           System.arraycopy(charAttributes, offset, abuf, 0, oldBase - offset);
434         }
435         // copy anything from the top of the screen (screenBase) up to the
436         // topMargin to the new screen
437         if (top > 0) {
438           System.arraycopy(charArray, oldBase, cbuf, newScreenBase, top);
439           System.arraycopy(charAttributes, oldBase, abuf, newScreenBase, top);
440         }
441         // copy anything from the topMargin up to the amount of lines inserted
442         // to the gap left over between scrollback buffer and screenBase
443         if (oldBase >= 0) {
444           System.arraycopy(charArray, oldBase + top, cbuf, oldBase - offset, n);
445           System.arraycopy(charAttributes, oldBase + top, abuf, oldBase - offset, n);
446         }
447         // copy anything from topMargin + n up to the line linserted to the
448         // topMargin
449         System
450             .arraycopy(charArray, oldBase + top + n, cbuf, newScreenBase + top, l - top - (n - 1));
451         System.arraycopy(charAttributes, oldBase + top + n, abuf, newScreenBase + top, l - top
452             - (n - 1));
453         //
454         // copy the all lines next to the inserted to the new buffer
455         if (l < height - 1) {
456           System.arraycopy(charArray, oldBase + l + 1, cbuf, newScreenBase + l + 1, (height - 1)
457               - l);
458           System.arraycopy(charAttributes, oldBase + l + 1, abuf, newScreenBase + l + 1,
459               (height - 1) - l);
460         }
461       } catch (ArrayIndexOutOfBoundsException e) {
462         // this should not happen anymore, but I will leave the code
463         // here in case something happens anyway. That code above is
464         // so complex I always have a hard time understanding what
465         // I did, even though there are comments
466         System.err.println("*** Error while scrolling up:");
467         System.err.println("--- BEGIN STACK TRACE ---");
468         e.printStackTrace();
469         System.err.println("--- END STACK TRACE ---");
470         System.err.println("bufSize=" + bufSize + ", maxBufSize=" + maxBufSize);
471         System.err.println("top=" + top + ", bottom=" + bottom);
472         System.err.println("n=" + n + ", l=" + l);
473         System.err.println("screenBase=" + screenBase + ", windowBase=" + windowBase);
474         System.err.println("newScreenBase=" + newScreenBase + ", newWindowBase=" + newWindowBase);
475         System.err.println("oldBase=" + oldBase);
476         System.err.println("size.width=" + width + ", size.height=" + height);
477         System.err.println("abuf.length=" + abuf.length + ", cbuf.length=" + cbuf.length);
478         System.err.println("*** done dumping debug information");
479       }
480     }
481 
482     // this is a little helper to mark the scrolling
483     scrollMarker -= n;
484 
485     for (int i = 0; i < n; i++) {
486       cbuf[(newScreenBase + l) + (scrollDown ? i : -i)] = new char[width];
487       Arrays.fill(cbuf[(newScreenBase + l) + (scrollDown ? i : -i)], ' ');
488       abuf[(newScreenBase + l) + (scrollDown ? i : -i)] = new int[width];
489     }
490 
491     charArray = cbuf;
492     charAttributes = abuf;
493     screenBase = newScreenBase;
494     windowBase = newWindowBase;
495     bufSize = newBufSize;
496 
497     if (scrollDown) {
498       markLine(l, bottom - l + 1);
499     } else {
500       markLine(top, l - top + 1);
501     }
502 
503     display.updateScrollBar();
504   }
505 
506   /**
507    * Delete a line at a specific position. Subsequent lines will be scrolled up to fill the space
508    * and a blank line is inserted at the end of the screen.
509    *
510    * @param l
511    *          the y-coordinate to insert the line
512    * @see #deleteLine
513    */
deleteLine(int l)514   public void deleteLine(int l) {
515     int bottom = (l > bottomMargin ? height - 1 : (l < topMargin ? topMargin : bottomMargin + 1));
516     int numRows = bottom - l - 1;
517 
518     char[] discardedChars = charArray[screenBase + l];
519     int[] discardedAttributes = charAttributes[screenBase + l];
520 
521     if (numRows > 0) {
522       System.arraycopy(charArray, screenBase + l + 1, charArray, screenBase + l, numRows);
523       System.arraycopy(charAttributes, screenBase + l + 1, charAttributes, screenBase + l, numRows);
524     }
525 
526     int newBottomRow = screenBase + bottom - 1;
527     charArray[newBottomRow] = discardedChars;
528     charAttributes[newBottomRow] = discardedAttributes;
529     Arrays.fill(charArray[newBottomRow], ' ');
530     Arrays.fill(charAttributes[newBottomRow], 0);
531 
532     markLine(l, bottom - l);
533   }
534 
535   /**
536    * Delete a rectangular portion of the screen. You need to call redraw() to update the screen.
537    *
538    * @param c
539    *          x-coordinate (column)
540    * @param l
541    *          y-coordinate (row)
542    * @param w
543    *          with of the area in characters
544    * @param h
545    *          height of the area in characters
546    * @param curAttr
547    *          attribute to fill
548    * @see #deleteChar
549    * @see #deleteLine
550    * @see #redraw
551    */
deleteArea(int c, int l, int w, int h, int curAttr)552   public void deleteArea(int c, int l, int w, int h, int curAttr) {
553     int endColumn = c + w;
554     int targetRow = screenBase + l;
555     for (int i = 0; i < h && l + i < height; i++) {
556       Arrays.fill(charAttributes[targetRow], c, endColumn, curAttr);
557       Arrays.fill(charArray[targetRow], c, endColumn, ' ');
558       targetRow++;
559     }
560     markLine(l, h);
561   }
562 
563   /**
564    * Delete a rectangular portion of the screen. You need to call redraw() to update the screen.
565    *
566    * @param c
567    *          x-coordinate (column)
568    * @param l
569    *          y-coordinate (row)
570    * @param w
571    *          with of the area in characters
572    * @param h
573    *          height of the area in characters
574    * @see #deleteChar
575    * @see #deleteLine
576    * @see #redraw
577    */
deleteArea(int c, int l, int w, int h)578   public void deleteArea(int c, int l, int w, int h) {
579     deleteArea(c, l, w, h, 0);
580   }
581 
582   /**
583    * Sets whether the cursor is visible or not.
584    *
585    * @param doshow
586    */
showCursor(boolean doshow)587   public void showCursor(boolean doshow) {
588     showcursor = doshow;
589   }
590 
591   /**
592    * Check whether the cursor is currently visible.
593    *
594    * @return visibility
595    */
isCursorVisible()596   public boolean isCursorVisible() {
597     return showcursor;
598   }
599 
600   /**
601    * Puts the cursor at the specified position.
602    *
603    * @param c
604    *          column
605    * @param l
606    *          line
607    */
setCursorPosition(int c, int l)608   public void setCursorPosition(int c, int l) {
609     cursorX = c;
610     cursorY = l;
611   }
612 
613   /**
614    * Get the current column of the cursor position.
615    */
getCursorColumn()616   public int getCursorColumn() {
617     return cursorX;
618   }
619 
620   /**
621    * Get the current line of the cursor position.
622    */
getCursorRow()623   public int getCursorRow() {
624     return cursorY;
625   }
626 
627   /**
628    * Set the current window base. This allows to view the scrollback buffer.
629    *
630    * @param line
631    *          the line where the screen window starts
632    * @see #setBufferSize
633    * @see #getBufferSize
634    */
setWindowBase(int line)635   public void setWindowBase(int line) {
636     if (line > screenBase) {
637       line = screenBase;
638     } else if (line < 0) {
639       line = 0;
640     }
641     windowBase = line;
642     update[0] = true;
643     redraw();
644   }
645 
646   /**
647    * Get the current window base.
648    *
649    * @see #setWindowBase
650    */
getWindowBase()651   public int getWindowBase() {
652     return windowBase;
653   }
654 
655   /**
656    * Set the scroll margins simultaneously. If they're out of bounds, trim them.
657    *
658    * @param l1
659    *          line that is the top
660    * @param l2
661    *          line that is the bottom
662    */
setMargins(int l1, int l2)663   public void setMargins(int l1, int l2) {
664     if (l1 > l2) {
665       return;
666     }
667 
668     if (l1 < 0) {
669       l1 = 0;
670     }
671     if (l2 >= height) {
672       l2 = height - 1;
673     }
674 
675     topMargin = l1;
676     bottomMargin = l2;
677   }
678 
679   /**
680    * Set the top scroll margin for the screen. If the current bottom margin is smaller it will
681    * become the top margin and the line will become the bottom margin.
682    *
683    * @param l
684    *          line that is the margin
685    */
setTopMargin(int l)686   public void setTopMargin(int l) {
687     if (l > bottomMargin) {
688       topMargin = bottomMargin;
689       bottomMargin = l;
690     } else {
691       topMargin = l;
692     }
693     if (topMargin < 0) {
694       topMargin = 0;
695     }
696     if (bottomMargin >= height) {
697       bottomMargin = height - 1;
698     }
699   }
700 
701   /**
702    * Get the top scroll margin.
703    */
getTopMargin()704   public int getTopMargin() {
705     return topMargin;
706   }
707 
708   /**
709    * Set the bottom scroll margin for the screen. If the current top margin is bigger it will become
710    * the bottom margin and the line will become the top margin.
711    *
712    * @param l
713    *          line that is the margin
714    */
setBottomMargin(int l)715   public void setBottomMargin(int l) {
716     if (l < topMargin) {
717       bottomMargin = topMargin;
718       topMargin = l;
719     } else {
720       bottomMargin = l;
721     }
722     if (topMargin < 0) {
723       topMargin = 0;
724     }
725     if (bottomMargin >= height) {
726       bottomMargin = height - 1;
727     }
728   }
729 
730   /**
731    * Get the bottom scroll margin.
732    */
getBottomMargin()733   public int getBottomMargin() {
734     return bottomMargin;
735   }
736 
737   /**
738    * Set scrollback buffer size.
739    *
740    * @param amount
741    *          new size of the buffer
742    */
setBufferSize(int amount)743   public void setBufferSize(int amount) {
744     if (amount < height) {
745       amount = height;
746     }
747     if (amount < maxBufSize) {
748       char cbuf[][] = new char[amount][width];
749       int abuf[][] = new int[amount][width];
750       int copyStart = bufSize - amount < 0 ? 0 : bufSize - amount;
751       int copyCount = bufSize - amount < 0 ? bufSize : amount;
752       if (charArray != null) {
753         System.arraycopy(charArray, copyStart, cbuf, 0, copyCount);
754       }
755       if (charAttributes != null) {
756         System.arraycopy(charAttributes, copyStart, abuf, 0, copyCount);
757       }
758       charArray = cbuf;
759       charAttributes = abuf;
760       bufSize = copyCount;
761       screenBase = bufSize - height;
762       windowBase = screenBase;
763     }
764     maxBufSize = amount;
765 
766     update[0] = true;
767     redraw();
768   }
769 
770   /**
771    * Retrieve current scrollback buffer size.
772    *
773    * @see #setBufferSize
774    */
775   public int getBufferSize() {
776     return bufSize;
777   }
778 
779   /**
780    * Retrieve maximum buffer Size.
781    *
782    * @see #getBufferSize
783    */
784   public int getMaxBufferSize() {
785     return maxBufSize;
786   }
787 
788   /**
789    * Change the size of the screen. This will include adjustment of the scrollback buffer.
790    *
791    * @param w
792    *          of the screen
793    * @param h
794    *          of the screen
795    */
796   @SuppressWarnings("unused")
797   public void setScreenSize(int w, int h, boolean broadcast) {
798     char cbuf[][];
799     int abuf[][];
800     int maxSize = bufSize;
801 
802     if (w < 1 || h < 1) {
803       return;
804     }
805 
806     if (debug > 0) {
807       System.err.println("VDU: screen size [" + w + "," + h + "]");
808     }
809 
810     if (h > maxBufSize) {
811       maxBufSize = h;
812     }
813 
814     if (h > bufSize) {
815       bufSize = h;
816       screenBase = 0;
817       windowBase = 0;
818     }
819 
820     if (windowBase + h >= bufSize) {
821       windowBase = bufSize - h;
822     }
823 
824     if (screenBase + h >= bufSize) {
825       screenBase = bufSize - h;
826     }
827 
828     cbuf = new char[bufSize][w];
829     abuf = new int[bufSize][w];
830 
831     for (int i = 0; i < bufSize; i++) {
832       Arrays.fill(cbuf[i], ' ');
833     }
834 
835     if (bufSize < maxSize) {
836       maxSize = bufSize;
837     }
838 
839     int rowLength;
840     if (charArray != null && charAttributes != null) {
841       for (int i = 0; i < maxSize && charArray[i] != null; i++) {
842         rowLength = charArray[i].length;
843         System.arraycopy(charArray[i], 0, cbuf[i], 0, w < rowLength ? w : rowLength);
844         System.arraycopy(charAttributes[i], 0, abuf[i], 0, w < rowLength ? w : rowLength);
845       }
846     }
847 
848     int C = getCursorColumn();
849     if (C < 0) {
850       C = 0;
851     } else if (C >= width) {
852       C = width - 1;
853     }
854 
855     int R = getCursorRow();
856     if (R < 0) {
857       R = 0;
858     } else if (R >= height) {
859       R = height - 1;
860     }
861 
862     setCursorPosition(C, R);
863 
864     charArray = cbuf;
865     charAttributes = abuf;
866     width = w;
867     height = h;
868     topMargin = 0;
869     bottomMargin = h - 1;
870     update = new boolean[h + 1];
871     update[0] = true;
872     /*
873      * FIXME: ??? if(resizeStrategy == RESIZE_FONT) setBounds(getBounds());
874      */
875   }
876 
877   /**
878    * Get amount of rows on the screen.
879    */
getRows()880   public int getRows() {
881     return height;
882   }
883 
884   /**
885    * Get amount of columns on the screen.
886    */
getColumns()887   public int getColumns() {
888     return width;
889   }
890 
891   /**
892    * Mark lines to be updated with redraw().
893    *
894    * @param l
895    *          starting line
896    * @param n
897    *          amount of lines to be updated
898    * @see #redraw
899    */
markLine(int l, int n)900   public void markLine(int l, int n) {
901     for (int i = 0; (i < n) && (l + i < height); i++) {
902       update[l + i + 1] = true;
903     }
904   }
905 
906   // private static int checkBounds(int value, int lower, int upper) {
907   // if (value < lower)
908   // return lower;
909   // else if (value > upper)
910   // return upper;
911   // else
912   // return value;
913   // }
914 
915   /** a generic display that should redraw on demand */
916   protected VDUDisplay display;
917 
setDisplay(VDUDisplay display)918   public void setDisplay(VDUDisplay display) {
919     this.display = display;
920   }
921 
922   /**
923    * Trigger a redraw on the display.
924    */
redraw()925   protected void redraw() {
926     if (display != null) {
927       display.redraw();
928     }
929   }
930 }
931