diff --git a/ChangeLog b/ChangeLog index 9825294..1ecfcdc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2009-11-25 Markus Gutschke + + * On browsers that support CSS transforms, enable switching between + 80 and 132 column mode. + 2009-11-21 Markus Gutschke * Updated manual page documenting --user-css diff --git a/config.h b/config.h index 1b752d9..b9fea5e 100644 --- a/config.h +++ b/config.h @@ -138,7 +138,7 @@ #define STDC_HEADERS 1 /* Most recent revision number in the version control system */ -#define VCS_REVISION "189" +#define VCS_REVISION "190" /* Version number of package */ #define VERSION "2.10" diff --git a/configure b/configure index eb3bbbe..0ea25b8 100755 --- a/configure +++ b/configure @@ -2319,7 +2319,7 @@ ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $ ac_compiler_gnu=$ac_cv_c_compiler_gnu -VCS_REVISION=189 +VCS_REVISION=190 cat >>confdefs.h <<_ACEOF diff --git a/configure.ac b/configure.ac index 8ced8d9..da4a77d 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ AC_PREREQ(2.57) dnl This is the one location where the authoritative version number is stored AC_INIT(shellinabox, 2.10, markus@shellinabox.com) -VCS_REVISION=189 +VCS_REVISION=190 AC_SUBST(VCS_REVISION) AC_DEFINE_UNQUOTED(VCS_REVISION, "${VCS_REVISION}", [Most recent revision number in the version control system]) diff --git a/demo/vt100.js b/demo/vt100.js index b627530..db7d99b 100644 --- a/demo/vt100.js +++ b/demo/vt100.js @@ -193,39 +193,39 @@ function VT100(container) { } VT100.prototype.reset = function(clearHistory) { - this.isEsc = 0 /* ESnormal */; - this.needWrap = false; - this.autoWrapMode = true; - this.dispCtrl = false; - this.toggleMeta = false; - this.insertMode = false; - this.applKeyMode = false; - this.cursorKeyMode = false; - this.crLfMode = false; - this.offsetMode = false; - this.mouseReporting = false; - this.printing = false; + this.isEsc = 0 /* ESnormal */; + this.needWrap = false; + this.autoWrapMode = true; + this.dispCtrl = false; + this.toggleMeta = false; + this.insertMode = false; + this.applKeyMode = false; + this.cursorKeyMode = false; + this.crLfMode = false; + this.offsetMode = false; + this.mouseReporting = false; + this.printing = false; if (typeof this.printWin != 'undefined' && this.printWin && !this.printWin.closed) { this.printWin.close(); } - this.printWin = null; - this.utfEnabled = this.utfPreferred; - this.utfCount = 0; - this.utfChar = 0; - this.color = 'ansi0 bgAnsi15'; - this.style = ''; - this.attr = 0x00F0 /* ATTR_DEFAULT */; - this.useGMap = 0; - this.GMap = [ this.Latin1Map, - this.VT100GraphicsMap, - this.CodePage437Map, - this.DirectToFontMap ]; - this.translate = this.GMap[this.useGMap]; - this.top = 0; - this.bottom = this.terminalHeight; - this.lastCharacter = ' '; - this.userTabStop = [ ]; + this.printWin = null; + this.utfEnabled = this.utfPreferred; + this.utfCount = 0; + this.utfChar = 0; + this.color = 'ansi0 bgAnsi15'; + this.style = ''; + this.attr = 0x00F0 /* ATTR_DEFAULT */; + this.useGMap = 0; + this.GMap = [ this.Latin1Map, + this.VT100GraphicsMap, + this.CodePage437Map, + this.DirectToFontMap]; + this.translate = this.GMap[this.useGMap]; + this.top = 0; + this.bottom = this.terminalHeight; + this.lastCharacter = ' '; + this.userTabStop = [ ]; if (clearHistory) { for (var i = 0; i < 2; i++) { @@ -236,9 +236,34 @@ VT100.prototype.reset = function(clearHistory) { } this.enableAlternateScreen(false); + + var wasCompressed = false; + var styles = [ 'transform', + 'WebkitTransform', + 'MozTransform', + 'filter' ]; + for (var i = 0; i < styles.length; ++i) { + if (typeof this.console[0].style[styles[i]] != 'undefined') { + for (var j = 0; j < 1; ++j) { + wasCompressed |= this.console[j].style[styles[i]] != ''; + this.console[j].style[styles[i]] = ''; + } + this.cursor.style[styles[i]] = ''; + this.space.style[styles[i]] = ''; + if (styles[i] == 'filter') { + this.console[this.currentScreen].style.width = ''; + } + break; + } + } + this.scale = 1.0; + if (wasCompressed) { + this.resizer(); + } + this.gotoXY(0, 0); this.showCursor(); - this.isInverted = false; + this.isInverted = false; this.refreshInvertedState(); this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight, this.color, this.style); @@ -658,6 +683,7 @@ VT100.prototype.initializeElements = function(container) { this.numScrollbackLines = 0; this.top = 0; this.bottom = 0x7FFFFFFF; + this.scale = 1.0; this.resizer(); this.focusCursor(); this.input.focus(); @@ -833,7 +859,8 @@ VT100.prototype.resizer = function() { } // Reposition the reconnect button - this.reconnectBtn.style.left = (this.terminalWidth*this.cursorWidth - + this.reconnectBtn.style.left = (this.terminalWidth*this.cursorWidth/ + this.scale - this.reconnectBtn.clientWidth)/2 + 'px'; this.reconnectBtn.style.top = (this.terminalHeight*this.cursorHeight- this.reconnectBtn.clientHeight)/2 + 'px'; @@ -849,7 +876,8 @@ VT100.prototype.showCurrentSize = function() { this.curSizeBox.innerHTML = '' + this.terminalWidth + 'x' + this.terminalHeight; this.curSizeBox.style.left = - (this.terminalWidth*this.cursorWidth - + (this.terminalWidth*this.cursorWidth/ + this.scale - this.curSizeBox.clientWidth)/2 + 'px'; this.curSizeBox.style.top = (this.terminalHeight*this.cursorHeight - @@ -1119,7 +1147,7 @@ VT100.prototype.insertBlankLine = function(y, color, style) { VT100.prototype.updateWidth = function() { this.terminalWidth = Math.floor(this.console[this.currentScreen].offsetWidth/ - this.cursorWidth); + this.cursorWidth*this.scale); return this.terminalWidth; }; @@ -1415,11 +1443,12 @@ VT100.prototype.putString = function(x, y, text, color, style) { } } if (pixelX >= 0) { - this.cursor.style.left = (pixelX + (this.isIE ? 1 : 0)) + 'px'; + this.cursor.style.left = (pixelX + (this.isIE ? 1 : 0))/ + this.scale + 'px'; } else { this.setTextContent(this.space, this.spaces(this.cursorX)); - this.cursor.style.left = this.space.offsetWidth + - console.offsetLeft + 'px'; + this.cursor.style.left = (this.space.offsetWidth + + console.offsetLeft)/this.scale + 'px'; } this.cursorY = yIdx - this.numScrollbackLines; if (pixelY >= 0) { @@ -1529,9 +1558,34 @@ VT100.prototype.enableAlternateScreen = function(state) { } // Display new screen, and initialize state (the resizer does that for us). - this.currentScreen = state ? 1 : 0; - this.console[1-this.currentScreen].style.display = 'none'; - this.console[this.currentScreen].style.display = ''; + this.currentScreen = state ? 1 : 0; + this.console[1-this.currentScreen].style.display = 'none'; + this.console[this.currentScreen].style.display = ''; + + // Select appropriate character pitch. + var styles = [ 'transform', + 'WebkitTransform', + 'MozTransform', + 'filter' ]; + for (var i = 0; i < styles.length; ++i) { + if (typeof this.console[0].style[styles[i]] != 'undefined') { + if (state) { + // Upon enabling the alternate screen, we switch to 80 column mode. But + // upon returning to the regular screen, we restore the mode that was + // in effect previously. + this.console[1].style[styles[i]] = ''; + } + var style = + this.console[this.currentScreen].style[styles[i]]; + this.cursor.style[styles[i]] = style; + this.space.style[styles[i]] = style; + this.scale = style == '' ? 1.0:1.65; + if (styles[i] == 'filter') { + this.console[this.currentScreen].style.width = style == '' ? '165%':''; + } + break; + } + } this.resizer(); // If we switched to the alternate screen, reset it completely. Otherwise, @@ -1901,7 +1955,7 @@ VT100.prototype.toggleBell = function() { }; VT100.prototype.about = function() { - alert("VT100 Terminal Emulator " + "2.10 (revision 189)" + + alert("VT100 Terminal Emulator " + "2.10 (revision 190)" + "\nCopyright 2008-2009 by Markus Gutschke\n" + "For more information check http://shellinabox.com"); }; @@ -2814,12 +2868,50 @@ VT100.prototype.restoreCursor = function() { this.savedY[this.currentScreen]); }; +VT100.prototype.set80_132Mode = function(state) { + var transform = undefined; + var styles = [ 'transform', + 'WebkitTransform', + 'MozTransform', + 'filter' + ]; + for (var i = 0; i < styles.length; ++i) { + if (typeof this.console[0].style[styles[i]] != 'undefined') { + transform = styles[i]; + break; + } + } + + if (transform) { + if ((this.console[this.currentScreen].style[transform] != '') == state) { + return; + } + var style = + state ? transform == 'filter' + ? 'progid:DXImageTransform.Microsoft.Matrix(' + + 'M11=0.606060606060606060606,M12=0,M21=0,M22=1,' + + "sizingMethod='auto expand')" + : 'translateX(-50%) ' + + 'scaleX(0.606060606060606060606) ' + + 'translateX(50%)' + : ''; + this.console[this.currentScreen].style[transform] = style; + this.cursor.style[transform] = style; + this.space.style[transform] = style; + this.scale = state ? 1.65 : 1.0; + if (transform == 'filter') { + this.console[this.currentScreen].style.width = state ? '165%' : ''; + } + this.resizer(); + } +}; + VT100.prototype.setMode = function(state) { for (var i = 0; i <= this.npar; i++) { if (this.isQuestionMark) { switch (this.par[i]) { case 1: this.cursorKeyMode = state; break; - case 3: /* Toggling between 80/132 mode is not implemented */ break; + case 3: this.set80_132Mode(state); break; case 5: this.isInverted = state; this.refreshInvertedState(); break; case 6: this.offsetMode = state; break; case 7: this.autoWrapMode = state; break; diff --git a/shellinabox/shell_in_a_box.js b/shellinabox/shell_in_a_box.js index 48ff6bd..28e956f 100644 --- a/shellinabox/shell_in_a_box.js +++ b/shellinabox/shell_in_a_box.js @@ -358,7 +358,7 @@ ShellInABox.prototype.extendContextMenu = function(entries, actions) { }; ShellInABox.prototype.about = function() { - alert("Shell In A Box version " + "2.10 (revision 189)" + + alert("Shell In A Box version " + "2.10 (revision 190)" + "\nCopyright 2008-2009 by Markus Gutschke\n" + "For more information check http://shellinabox.com" + (typeof serverSupportsSSL != 'undefined' && serverSupportsSSL ? diff --git a/shellinabox/vt100.js b/shellinabox/vt100.js index b627530..db7d99b 100644 --- a/shellinabox/vt100.js +++ b/shellinabox/vt100.js @@ -193,39 +193,39 @@ function VT100(container) { } VT100.prototype.reset = function(clearHistory) { - this.isEsc = 0 /* ESnormal */; - this.needWrap = false; - this.autoWrapMode = true; - this.dispCtrl = false; - this.toggleMeta = false; - this.insertMode = false; - this.applKeyMode = false; - this.cursorKeyMode = false; - this.crLfMode = false; - this.offsetMode = false; - this.mouseReporting = false; - this.printing = false; + this.isEsc = 0 /* ESnormal */; + this.needWrap = false; + this.autoWrapMode = true; + this.dispCtrl = false; + this.toggleMeta = false; + this.insertMode = false; + this.applKeyMode = false; + this.cursorKeyMode = false; + this.crLfMode = false; + this.offsetMode = false; + this.mouseReporting = false; + this.printing = false; if (typeof this.printWin != 'undefined' && this.printWin && !this.printWin.closed) { this.printWin.close(); } - this.printWin = null; - this.utfEnabled = this.utfPreferred; - this.utfCount = 0; - this.utfChar = 0; - this.color = 'ansi0 bgAnsi15'; - this.style = ''; - this.attr = 0x00F0 /* ATTR_DEFAULT */; - this.useGMap = 0; - this.GMap = [ this.Latin1Map, - this.VT100GraphicsMap, - this.CodePage437Map, - this.DirectToFontMap ]; - this.translate = this.GMap[this.useGMap]; - this.top = 0; - this.bottom = this.terminalHeight; - this.lastCharacter = ' '; - this.userTabStop = [ ]; + this.printWin = null; + this.utfEnabled = this.utfPreferred; + this.utfCount = 0; + this.utfChar = 0; + this.color = 'ansi0 bgAnsi15'; + this.style = ''; + this.attr = 0x00F0 /* ATTR_DEFAULT */; + this.useGMap = 0; + this.GMap = [ this.Latin1Map, + this.VT100GraphicsMap, + this.CodePage437Map, + this.DirectToFontMap]; + this.translate = this.GMap[this.useGMap]; + this.top = 0; + this.bottom = this.terminalHeight; + this.lastCharacter = ' '; + this.userTabStop = [ ]; if (clearHistory) { for (var i = 0; i < 2; i++) { @@ -236,9 +236,34 @@ VT100.prototype.reset = function(clearHistory) { } this.enableAlternateScreen(false); + + var wasCompressed = false; + var styles = [ 'transform', + 'WebkitTransform', + 'MozTransform', + 'filter' ]; + for (var i = 0; i < styles.length; ++i) { + if (typeof this.console[0].style[styles[i]] != 'undefined') { + for (var j = 0; j < 1; ++j) { + wasCompressed |= this.console[j].style[styles[i]] != ''; + this.console[j].style[styles[i]] = ''; + } + this.cursor.style[styles[i]] = ''; + this.space.style[styles[i]] = ''; + if (styles[i] == 'filter') { + this.console[this.currentScreen].style.width = ''; + } + break; + } + } + this.scale = 1.0; + if (wasCompressed) { + this.resizer(); + } + this.gotoXY(0, 0); this.showCursor(); - this.isInverted = false; + this.isInverted = false; this.refreshInvertedState(); this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight, this.color, this.style); @@ -658,6 +683,7 @@ VT100.prototype.initializeElements = function(container) { this.numScrollbackLines = 0; this.top = 0; this.bottom = 0x7FFFFFFF; + this.scale = 1.0; this.resizer(); this.focusCursor(); this.input.focus(); @@ -833,7 +859,8 @@ VT100.prototype.resizer = function() { } // Reposition the reconnect button - this.reconnectBtn.style.left = (this.terminalWidth*this.cursorWidth - + this.reconnectBtn.style.left = (this.terminalWidth*this.cursorWidth/ + this.scale - this.reconnectBtn.clientWidth)/2 + 'px'; this.reconnectBtn.style.top = (this.terminalHeight*this.cursorHeight- this.reconnectBtn.clientHeight)/2 + 'px'; @@ -849,7 +876,8 @@ VT100.prototype.showCurrentSize = function() { this.curSizeBox.innerHTML = '' + this.terminalWidth + 'x' + this.terminalHeight; this.curSizeBox.style.left = - (this.terminalWidth*this.cursorWidth - + (this.terminalWidth*this.cursorWidth/ + this.scale - this.curSizeBox.clientWidth)/2 + 'px'; this.curSizeBox.style.top = (this.terminalHeight*this.cursorHeight - @@ -1119,7 +1147,7 @@ VT100.prototype.insertBlankLine = function(y, color, style) { VT100.prototype.updateWidth = function() { this.terminalWidth = Math.floor(this.console[this.currentScreen].offsetWidth/ - this.cursorWidth); + this.cursorWidth*this.scale); return this.terminalWidth; }; @@ -1415,11 +1443,12 @@ VT100.prototype.putString = function(x, y, text, color, style) { } } if (pixelX >= 0) { - this.cursor.style.left = (pixelX + (this.isIE ? 1 : 0)) + 'px'; + this.cursor.style.left = (pixelX + (this.isIE ? 1 : 0))/ + this.scale + 'px'; } else { this.setTextContent(this.space, this.spaces(this.cursorX)); - this.cursor.style.left = this.space.offsetWidth + - console.offsetLeft + 'px'; + this.cursor.style.left = (this.space.offsetWidth + + console.offsetLeft)/this.scale + 'px'; } this.cursorY = yIdx - this.numScrollbackLines; if (pixelY >= 0) { @@ -1529,9 +1558,34 @@ VT100.prototype.enableAlternateScreen = function(state) { } // Display new screen, and initialize state (the resizer does that for us). - this.currentScreen = state ? 1 : 0; - this.console[1-this.currentScreen].style.display = 'none'; - this.console[this.currentScreen].style.display = ''; + this.currentScreen = state ? 1 : 0; + this.console[1-this.currentScreen].style.display = 'none'; + this.console[this.currentScreen].style.display = ''; + + // Select appropriate character pitch. + var styles = [ 'transform', + 'WebkitTransform', + 'MozTransform', + 'filter' ]; + for (var i = 0; i < styles.length; ++i) { + if (typeof this.console[0].style[styles[i]] != 'undefined') { + if (state) { + // Upon enabling the alternate screen, we switch to 80 column mode. But + // upon returning to the regular screen, we restore the mode that was + // in effect previously. + this.console[1].style[styles[i]] = ''; + } + var style = + this.console[this.currentScreen].style[styles[i]]; + this.cursor.style[styles[i]] = style; + this.space.style[styles[i]] = style; + this.scale = style == '' ? 1.0:1.65; + if (styles[i] == 'filter') { + this.console[this.currentScreen].style.width = style == '' ? '165%':''; + } + break; + } + } this.resizer(); // If we switched to the alternate screen, reset it completely. Otherwise, @@ -1901,7 +1955,7 @@ VT100.prototype.toggleBell = function() { }; VT100.prototype.about = function() { - alert("VT100 Terminal Emulator " + "2.10 (revision 189)" + + alert("VT100 Terminal Emulator " + "2.10 (revision 190)" + "\nCopyright 2008-2009 by Markus Gutschke\n" + "For more information check http://shellinabox.com"); }; @@ -2814,12 +2868,50 @@ VT100.prototype.restoreCursor = function() { this.savedY[this.currentScreen]); }; +VT100.prototype.set80_132Mode = function(state) { + var transform = undefined; + var styles = [ 'transform', + 'WebkitTransform', + 'MozTransform', + 'filter' + ]; + for (var i = 0; i < styles.length; ++i) { + if (typeof this.console[0].style[styles[i]] != 'undefined') { + transform = styles[i]; + break; + } + } + + if (transform) { + if ((this.console[this.currentScreen].style[transform] != '') == state) { + return; + } + var style = + state ? transform == 'filter' + ? 'progid:DXImageTransform.Microsoft.Matrix(' + + 'M11=0.606060606060606060606,M12=0,M21=0,M22=1,' + + "sizingMethod='auto expand')" + : 'translateX(-50%) ' + + 'scaleX(0.606060606060606060606) ' + + 'translateX(50%)' + : ''; + this.console[this.currentScreen].style[transform] = style; + this.cursor.style[transform] = style; + this.space.style[transform] = style; + this.scale = state ? 1.65 : 1.0; + if (transform == 'filter') { + this.console[this.currentScreen].style.width = state ? '165%' : ''; + } + this.resizer(); + } +}; + VT100.prototype.setMode = function(state) { for (var i = 0; i <= this.npar; i++) { if (this.isQuestionMark) { switch (this.par[i]) { case 1: this.cursorKeyMode = state; break; - case 3: /* Toggling between 80/132 mode is not implemented */ break; + case 3: this.set80_132Mode(state); break; case 5: this.isInverted = state; this.refreshInvertedState(); break; case 6: this.offsetMode = state; break; case 7: this.autoWrapMode = state; break; diff --git a/shellinabox/vt100.jspp b/shellinabox/vt100.jspp index 615a6f4..bbbadca 100644 --- a/shellinabox/vt100.jspp +++ b/shellinabox/vt100.jspp @@ -193,39 +193,39 @@ function VT100(container) { } VT100.prototype.reset = function(clearHistory) { - this.isEsc = ESnormal; - this.needWrap = false; - this.autoWrapMode = true; - this.dispCtrl = false; - this.toggleMeta = false; - this.insertMode = false; - this.applKeyMode = false; - this.cursorKeyMode = false; - this.crLfMode = false; - this.offsetMode = false; - this.mouseReporting = false; - this.printing = false; + this.isEsc = ESnormal; + this.needWrap = false; + this.autoWrapMode = true; + this.dispCtrl = false; + this.toggleMeta = false; + this.insertMode = false; + this.applKeyMode = false; + this.cursorKeyMode = false; + this.crLfMode = false; + this.offsetMode = false; + this.mouseReporting = false; + this.printing = false; if (typeof this.printWin != 'undefined' && this.printWin && !this.printWin.closed) { this.printWin.close(); } - this.printWin = null; - this.utfEnabled = this.utfPreferred; - this.utfCount = 0; - this.utfChar = 0; - this.color = 'ansi0 bgAnsi15'; - this.style = ''; - this.attr = ATTR_DEFAULT; - this.useGMap = 0; - this.GMap = [ this.Latin1Map, - this.VT100GraphicsMap, - this.CodePage437Map, - this.DirectToFontMap ]; - this.translate = this.GMap[this.useGMap]; - this.top = 0; - this.bottom = this.terminalHeight; - this.lastCharacter = ' '; - this.userTabStop = [ ]; + this.printWin = null; + this.utfEnabled = this.utfPreferred; + this.utfCount = 0; + this.utfChar = 0; + this.color = 'ansi0 bgAnsi15'; + this.style = ''; + this.attr = ATTR_DEFAULT; + this.useGMap = 0; + this.GMap = [ this.Latin1Map, + this.VT100GraphicsMap, + this.CodePage437Map, + this.DirectToFontMap]; + this.translate = this.GMap[this.useGMap]; + this.top = 0; + this.bottom = this.terminalHeight; + this.lastCharacter = ' '; + this.userTabStop = [ ]; if (clearHistory) { for (var i = 0; i < 2; i++) { @@ -236,9 +236,34 @@ VT100.prototype.reset = function(clearHistory) { } this.enableAlternateScreen(false); + + var wasCompressed = false; + var styles = [ 'transform', + 'WebkitTransform', + 'MozTransform', + 'filter' ]; + for (var i = 0; i < styles.length; ++i) { + if (typeof this.console[0].style[styles[i]] != 'undefined') { + for (var j = 0; j < 1; ++j) { + wasCompressed |= this.console[j].style[styles[i]] != ''; + this.console[j].style[styles[i]] = ''; + } + this.cursor.style[styles[i]] = ''; + this.space.style[styles[i]] = ''; + if (styles[i] == 'filter') { + this.console[this.currentScreen].style.width = ''; + } + break; + } + } + this.scale = 1.0; + if (wasCompressed) { + this.resizer(); + } + this.gotoXY(0, 0); this.showCursor(); - this.isInverted = false; + this.isInverted = false; this.refreshInvertedState(); this.clearRegion(0, 0, this.terminalWidth, this.terminalHeight, this.color, this.style); @@ -658,6 +683,7 @@ VT100.prototype.initializeElements = function(container) { this.numScrollbackLines = 0; this.top = 0; this.bottom = 0x7FFFFFFF; + this.scale = 1.0; this.resizer(); this.focusCursor(); this.input.focus(); @@ -833,7 +859,8 @@ VT100.prototype.resizer = function() { } // Reposition the reconnect button - this.reconnectBtn.style.left = (this.terminalWidth*this.cursorWidth - + this.reconnectBtn.style.left = (this.terminalWidth*this.cursorWidth/ + this.scale - this.reconnectBtn.clientWidth)/2 + 'px'; this.reconnectBtn.style.top = (this.terminalHeight*this.cursorHeight- this.reconnectBtn.clientHeight)/2 + 'px'; @@ -849,7 +876,8 @@ VT100.prototype.showCurrentSize = function() { this.curSizeBox.innerHTML = '' + this.terminalWidth + 'x' + this.terminalHeight; this.curSizeBox.style.left = - (this.terminalWidth*this.cursorWidth - + (this.terminalWidth*this.cursorWidth/ + this.scale - this.curSizeBox.clientWidth)/2 + 'px'; this.curSizeBox.style.top = (this.terminalHeight*this.cursorHeight - @@ -1119,7 +1147,7 @@ VT100.prototype.insertBlankLine = function(y, color, style) { VT100.prototype.updateWidth = function() { this.terminalWidth = Math.floor(this.console[this.currentScreen].offsetWidth/ - this.cursorWidth); + this.cursorWidth*this.scale); return this.terminalWidth; }; @@ -1415,11 +1443,12 @@ VT100.prototype.putString = function(x, y, text, color, style) { } } if (pixelX >= 0) { - this.cursor.style.left = (pixelX + (this.isIE ? 1 : 0)) + 'px'; + this.cursor.style.left = (pixelX + (this.isIE ? 1 : 0))/ + this.scale + 'px'; } else { this.setTextContent(this.space, this.spaces(this.cursorX)); - this.cursor.style.left = this.space.offsetWidth + - console.offsetLeft + 'px'; + this.cursor.style.left = (this.space.offsetWidth + + console.offsetLeft)/this.scale + 'px'; } this.cursorY = yIdx - this.numScrollbackLines; if (pixelY >= 0) { @@ -1529,9 +1558,34 @@ VT100.prototype.enableAlternateScreen = function(state) { } // Display new screen, and initialize state (the resizer does that for us). - this.currentScreen = state ? 1 : 0; - this.console[1-this.currentScreen].style.display = 'none'; - this.console[this.currentScreen].style.display = ''; + this.currentScreen = state ? 1 : 0; + this.console[1-this.currentScreen].style.display = 'none'; + this.console[this.currentScreen].style.display = ''; + + // Select appropriate character pitch. + var styles = [ 'transform', + 'WebkitTransform', + 'MozTransform', + 'filter' ]; + for (var i = 0; i < styles.length; ++i) { + if (typeof this.console[0].style[styles[i]] != 'undefined') { + if (state) { + // Upon enabling the alternate screen, we switch to 80 column mode. But + // upon returning to the regular screen, we restore the mode that was + // in effect previously. + this.console[1].style[styles[i]] = ''; + } + var style = + this.console[this.currentScreen].style[styles[i]]; + this.cursor.style[styles[i]] = style; + this.space.style[styles[i]] = style; + this.scale = style == '' ? 1.0:1.65; + if (styles[i] == 'filter') { + this.console[this.currentScreen].style.width = style == '' ? '165%':''; + } + break; + } + } this.resizer(); // If we switched to the alternate screen, reset it completely. Otherwise, @@ -2814,12 +2868,50 @@ VT100.prototype.restoreCursor = function() { this.savedY[this.currentScreen]); }; +VT100.prototype.set80_132Mode = function(state) { + var transform = undefined; + var styles = [ 'transform', + 'WebkitTransform', + 'MozTransform', + 'filter' + ]; + for (var i = 0; i < styles.length; ++i) { + if (typeof this.console[0].style[styles[i]] != 'undefined') { + transform = styles[i]; + break; + } + } + + if (transform) { + if ((this.console[this.currentScreen].style[transform] != '') == state) { + return; + } + var style = + state ? transform == 'filter' + ? 'progid:DXImageTransform.Microsoft.Matrix(' + + 'M11=0.606060606060606060606,M12=0,M21=0,M22=1,' + + "sizingMethod='auto expand')" + : 'translateX(-50%) ' + + 'scaleX(0.606060606060606060606) ' + + 'translateX(50%)' + : ''; + this.console[this.currentScreen].style[transform] = style; + this.cursor.style[transform] = style; + this.space.style[transform] = style; + this.scale = state ? 1.65 : 1.0; + if (transform == 'filter') { + this.console[this.currentScreen].style.width = state ? '165%' : ''; + } + this.resizer(); + } +}; + VT100.prototype.setMode = function(state) { for (var i = 0; i <= this.npar; i++) { if (this.isQuestionMark) { switch (this.par[i]) { case 1: this.cursorKeyMode = state; break; - case 3: /* Toggling between 80/132 mode is not implemented */ break; + case 3: this.set80_132Mode(state); break; case 5: this.isInverted = state; this.refreshInvertedState(); break; case 6: this.offsetMode = state; break; case 7: this.autoWrapMode = state; break;