# HG changeset patch # User John "Elwin" Edwards # Date 1336595885 25200 # Node ID 826a7ced69f894a4585000fb2cf2ae333a01bbea # Parent ad0a31e5200742e3b090f381cf710379becbab43 Make the emulator screen resizable. diff -r ad0a31e52007 -r 826a7ced69f8 rlgterm.js --- a/rlgterm.js Mon May 07 16:08:59 2012 -0700 +++ b/rlgterm.js Wed May 09 13:38:05 2012 -0700 @@ -405,7 +405,7 @@ nsize = 48; } document.getElementById("term").style.fontSize = nsize.toString() + "px"; - termemu.resize(); + termemu.fixsize(); debug(1, "Changing font size to " + nsize.toString()); return; } diff -r ad0a31e52007 -r 826a7ced69f8 shterm.js --- a/shterm.js Mon May 07 16:08:59 2012 -0700 +++ b/shterm.js Wed May 09 13:38:05 2012 -0700 @@ -270,7 +270,7 @@ function setup() { keyHexCodes.init(); - termemu.init("termwrap", 25, 80); + termemu.init("termwrap", 24, 80); setTitle("Not connected."); return; } @@ -295,7 +295,7 @@ return; } -function login() { +function login(h, w) { if (termemu.alive) return; var req = new XMLHttpRequest(); @@ -304,6 +304,8 @@ var datalines = req.responseText.split("\n"); if (datalines[0] == 'l1') { /* Success */ + // FIXME extract the size from the response instead of hardcoding + termemu.resize(25, 80); termemu.alive = true; setTitle("Logged in"); debug(1, "Logged in with id " + datalines[1]); @@ -314,7 +316,7 @@ } }; req.open('POST', '/login', true); - req.send("login=login"); + req.send("login=login&h=" + String(h) + "&w=" + String(w)); return; } @@ -388,7 +390,7 @@ nsize = 48; } document.getElementById("term").style.fontSize = nsize.toString() + "px"; - termemu.resize(); + termemu.fixsize(); debug(1, "Changing font size to " + nsize.toString()); return; } diff -r ad0a31e52007 -r 826a7ced69f8 termemu.js --- a/termemu.js Mon May 07 16:08:59 2012 -0700 +++ b/termemu.js Wed May 09 13:38:05 2012 -0700 @@ -54,6 +54,7 @@ // An object representing the terminal emulator. var termemu = { sessid: null, // Session key assigned by the server + alive: false, /* Some elements of the page. */ inwrap: null, // A non-table div wrapping the screen view: null, // The div holding the terminal screen @@ -192,14 +193,67 @@ /* Attach them. */ this.view = termdiv; this.screen = this.normbuf; - this.resize(); + this.fixsize(); this.cmove(0, 0); }, + resize: function (h, w) { + if (this.screen == null) + return; + if (!(h > 0 && h < 256)) + h = this.h; + if (!(w > 0 && w < 256)) + w = this.w; + /* First give all the rows the right number of cells. */ + var allrows = Array().concat(this.histbuf.childNodes, + this.normbuf.childNodes, + this.altbuf.childNodes); + for (var i = 0; i < allrows.length; i++) { + var row = allrows[i]; + for (var j = Math.min(w, this.w); j < Math.max(w, this.w); j++) { + if (w < this.w) + row.removeChild(row.childNodes.lastChild); + else + row.appendChild(this.makeCell(' ')); + } + } + this.w = w; + /* Now the rows. */ + /* Resizing altbuf isn't always necessary. */ + /* TODO resize and scrolling region interact in complicated ways that I + * don't want to reverse-engineer. For the moment, just don't do that. + */ + if (h > this.h) { + for (var i = this.h; i < h; i++) { + this.normbuf.appendChild(this.makeRow()); + this.altbuf.appendChild(this.makeRow()); + } + } + else if (h < this.h) { + for (var i = h; i < this.h; i++) { + this.histbuf.appendChild(this.normbuf.firstChild); + if (this.altbuf.firstChild) + this.altbuf.removeChild(this.altbuf.firstChild); + } + } + /* Keep it on the bottom */ + if (this.scrB == this.h - 1) + this.scrB = h - 1; + else if (this.scrB >= h) + this.scrB = h - 1; + if (this.scrT >= h - 1) + this.scrT = 0; + this.h = h; + this.fixsize(); + /* If the cursor is now offscreen, cmove()'s sanity checks will fix it. */ + this.cmove(null, null); + debug(1, "Size is now " + this.w + "x" + this.h); + return; + }, valign: function () { if (this.screen == this.normbuf) this.inwrap.scrollTop = this.histbuf.clientHeight; }, - resize: function () { + fixsize: function () { var owrap = document.getElementById("termwrap"); /* Set the height up properly. */ this.inwrap.style.height = this.screen.scrollHeight.toString() + "px"; @@ -215,7 +269,9 @@ flipCursor: function () { /* Swaps the text and background colors of the active location. */ /* This will change when other cursor styles are supported. */ - if (this.c.x != null && this.c.y != null) { + /* Check: the cursor might be offscreen if it was resized. */ + if (this.c.x != null && this.c.y != null && this.c.x >= 0 && + this.c.x < this.w && this.c.y >= 0 && this.c.y < this.h) { var oldcell = this.screen.childNodes[this.c.y].childNodes[this.c.x]; var tempswap = oldcell.style.color; oldcell.style.color = oldcell.style.backgroundColor; diff -r ad0a31e52007 -r 826a7ced69f8 webtty.js --- a/webtty.js Mon May 07 16:08:59 2012 -0700 +++ b/webtty.js Wed May 09 13:38:05 2012 -0700 @@ -14,13 +14,23 @@ /* Constructor for TermSessions. Note that it opens the terminal and * adds itself to the sessions dict. */ -function TermSession(sessid) { +function TermSession(sessid, h, w) { + /* Set up the sizes. */ + w = Math.floor(Number(w)); + if (!(w > 0 && w < 256)) + w = 80; + this.w = w; + h = Math.floor(Number(h)); + if (!(h > 0 && h < 256)) + h = 25; + this.h = h; + /* Customize the environment. */ var childenv = {}; for (var key in process.env) { if (!(key in env_dontuse)) childenv[key] = process.env[key]; } - childenv["PTYHELPER"] = "25x80"; + childenv["PTYHELPER"] = String(this.h) + "x" + String(this.w); // Should setsid get set? var spawnopts = {"env": childenv, "cwd": process.env["HOME"]}; this.child = child_process.spawn(ptyhelp, ["bash"], spawnopts); @@ -154,10 +164,25 @@ function login(req, res, formdata) { var resheaders = {'Content-Type': 'text/plain'}; var sessid = randkey(); - var nsession = new TermSession(sessid); + /* The TermSession constructor will check these thoroughly too, but + * you can't be too suspicious of client-supplied data. */ + var w = 80; + var h = 25; + var t; + if ("w" in formdata) { + t = Math.floor(Number(formdata["w"])); + if (t > 0 && t < 256) + w = t; + } + if ("h" in formdata) { + t = Math.floor(Number(formdata["h"])); + if (t > 0 && t < 256) + h = t; + } + var nsession = new TermSession(sessid, h, w); resheaders["Set-Cookie"] = "ID=" + sessid; res.writeHead(200, resheaders); - res.write("l1\n" + sessid + "\n"); + res.write("l1\n" + sessid + "\n" + String(h) + "x" + String(w) + "\n"); res.end(); console.log("Started new session with key " + sessid + ", pid " + nsession.child.pid); return;