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