summaryrefslogtreecommitdiffstats
path: root/konsole/konsole/session.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'konsole/konsole/session.cpp')
-rw-r--r--konsole/konsole/session.cpp838
1 files changed, 838 insertions, 0 deletions
diff --git a/konsole/konsole/session.cpp b/konsole/konsole/session.cpp
new file mode 100644
index 000000000..2310255a8
--- /dev/null
+++ b/konsole/konsole/session.cpp
@@ -0,0 +1,838 @@
+/*
+ This file is part of Konsole, an X terminal.
+ Copyright (C) 1997,1998 by Lars Doelle <lars.doelle@on-line.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+*/
+
+#include "session.h"
+#include "zmodem_dialog.h"
+
+#include <kdebug.h>
+#include <dcopclient.h>
+#include <kmessagebox.h>
+#include <knotifyclient.h>
+#include <klocale.h>
+#include <kprocio.h>
+#include <krun.h>
+#include <kshell.h>
+#include <kstandarddirs.h>
+
+#include <stdlib.h>
+#include <qfile.h>
+#include <qdir.h>
+#include <qregexp.h>
+#include <qtextedit.h>
+
+/*! \class TESession
+
+ Sessions are combinations of TEPTy and Emulations.
+
+ The stuff in here does not belong to the terminal emulation framework,
+ but to main.cpp. It serves it's duty by providing a single reference
+ to TEPTy/Emulation pairs. In fact, it is only there to demonstrate one
+ of the abilities of the framework - multible sessions.
+*/
+
+TESession::TESession(TEWidget* _te, const QString &_term, ulong _winId, const QString &_sessionId, const QString &_initial_cwd)
+ : DCOPObject( _sessionId.latin1() )
+ , sh(0)
+ , connected(true)
+ , monitorActivity(false)
+ , monitorSilence(false)
+ , notifiedActivity(false)
+ , masterMode(false)
+ , autoClose(true)
+ , wantedClose(false)
+ , schema_no(0)
+ , font_no(3)
+ , silence_seconds(10)
+ , add_to_utmp(true)
+ , xon_xoff(false)
+ , pgm(QString())
+ , args(QStrList())
+ , sessionId(_sessionId)
+ , cwd("")
+ , initial_cwd(_initial_cwd)
+ , zmodemBusy(false)
+ , zmodemProc(0)
+ , zmodemProgress(0)
+ , encoding_no(0)
+{
+ //kdDebug(1211)<<"TESession ctor() new TEPty"<<endl;
+ te = _te;
+ //kdDebug(1211)<<"TESession ctor() new TEmuVt102"<<endl;
+ em = new TEmuVt102(te);
+ font_h = te-> fontHeight();
+ font_w = te-> fontWidth();
+ QObject::connect(te,SIGNAL(changedContentSizeSignal(int,int)),
+ this,SLOT(onContentSizeChange(int,int)));
+ QObject::connect(te,SIGNAL(changedFontMetricSignal(int,int)),
+ this,SLOT(onFontMetricChange(int,int)));
+
+ term = _term;
+ winId = _winId;
+ iconName = "konsole";
+
+ setPty( new TEPty() );
+
+ connect( em, SIGNAL( changeTitle( int, const QString & ) ),
+ this, SLOT( setUserTitle( int, const QString & ) ) );
+ connect( em, SIGNAL( notifySessionState(int) ),
+ this, SLOT( notifySessionState(int) ) );
+ monitorTimer = new QTimer(this);
+ connect(monitorTimer, SIGNAL(timeout()), this, SLOT(monitorTimerDone()));
+
+ connect( em, SIGNAL( zmodemDetected() ), this, SLOT(slotZModemDetected()));
+
+ connect( em, SIGNAL( changeTabTextColor( int ) ),
+ this, SLOT( changeTabTextColor( int ) ) );
+
+ //kdDebug(1211)<<"TESession ctor() done"<<endl;
+}
+
+void TESession::setPty(TEPty *_sh)
+{
+ if ( sh ) {
+ delete sh;
+ }
+ sh = _sh;
+ connect( sh, SIGNAL( forkedChild() ),
+ this, SIGNAL( forkedChild() ));
+
+ //kdDebug(1211)<<"TESession ctor() sh->setSize()"<<endl;
+ sh->setSize(te->Lines(),te->Columns()); // not absolutely nessesary
+ sh->useUtf8(em->utf8());
+ //kdDebug(1211)<<"TESession ctor() connecting"<<endl;
+ connect( sh,SIGNAL(block_in(const char*,int)),this,SLOT(onRcvBlock(const char*,int)) );
+
+ connect( em,SIGNAL(sndBlock(const char*,int)),sh,SLOT(send_bytes(const char*,int)) );
+ connect( em,SIGNAL(lockPty(bool)),sh,SLOT(lockPty(bool)) );
+ connect( em,SIGNAL(useUtf8(bool)),sh,SLOT(useUtf8(bool)) );
+
+ connect( sh,SIGNAL(done(int)), this,SLOT(done(int)) );
+
+ if (!sh->error().isEmpty())
+ QTimer::singleShot(0, this, SLOT(ptyError()));
+}
+
+void TESession::ptyError()
+{
+ // FIXME: sh->error() is always empty
+ if ( sh->error().isEmpty() )
+ KMessageBox::error( te->topLevelWidget(),
+ i18n("Konsole is unable to open a PTY (pseudo teletype). It is likely that this is due to an incorrect configuration of the PTY devices. Konsole needs to have read/write access to the PTY devices."),
+ i18n("A Fatal Error Has Occurred") );
+ else
+ KMessageBox::error(te->topLevelWidget(), sh->error());
+ emit done(this);
+}
+
+void TESession::changeWidget(TEWidget* w)
+{
+ QObject::disconnect(te,SIGNAL(changedContentSizeSignal(int,int)),
+ this,SLOT(onContentSizeChange(int,int)));
+ QObject::disconnect(te,SIGNAL(changedFontMetricSignal(int,int)),
+ this,SLOT(onFontMetricChange(int,int)));
+ te=w;
+ em->changeGUI(w);
+ font_h = te->fontHeight();
+ font_w = te->fontWidth();
+ sh->setSize(te->Lines(),te->Columns()); // not absolutely nessesary
+
+ te->setDefaultBackColor(modifiedBackground);
+
+ QObject::connect(te,SIGNAL(changedContentSizeSignal(int,int)),
+ this,SLOT(onContentSizeChange(int,int)));
+ QObject::connect(te,SIGNAL(changedFontMetricSignal(int,int)),
+ this,SLOT(onFontMetricChange(int,int)));
+}
+
+void TESession::setProgram( const QString &_pgm, const QStrList &_args )
+{
+ pgm = _pgm;
+ args = _args;
+}
+
+void TESession::run()
+{
+ // Upon a KPty error, there is no description on what that error was...
+ // Check to see if the given program is executable.
+ QString exec = QFile::encodeName(pgm);
+ exec = KRun::binaryName(exec, false);
+ exec = KShell::tildeExpand(exec);
+ QString pexec = KGlobal::dirs()->findExe(exec);
+ if ( pexec.isEmpty() ) {
+ kdError()<<"can not execute "<<exec<<endl;
+ QTimer::singleShot(1, this, SLOT(done()));
+ return;
+ }
+
+ QString appId=kapp->dcopClient()->appId();
+
+ QString cwd_save = QDir::currentDirPath();
+ if (!initial_cwd.isEmpty())
+ QDir::setCurrent(initial_cwd);
+ sh->setXonXoff(xon_xoff);
+
+ int result = sh->run(QFile::encodeName(pgm), args, term.latin1(),
+ winId, add_to_utmp,
+ ("DCOPRef("+appId+",konsole)").latin1(),
+ ("DCOPRef("+appId+","+sessionId+")").latin1());
+ if (result < 0) { // Error in opening pseudo teletype
+ kdWarning()<<"Unable to open a pseudo teletype!"<<endl;
+ QTimer::singleShot(0, this, SLOT(ptyError()));
+ }
+ sh->setErase(em->getErase());
+
+ if (!initial_cwd.isEmpty())
+ QDir::setCurrent(cwd_save);
+ else
+ initial_cwd=cwd_save;
+
+ sh->setWriteable(false); // We are reachable via kwrited.
+}
+
+void TESession::changeTabTextColor( int color )
+{
+ emit changeTabTextColor( this, color );
+}
+
+void TESession::setUserTitle( int what, const QString &caption )
+{
+ // (btw: what=0 changes title and icon, what=1 only icon, what=2 only title
+ if ((what == 0) || (what == 2))
+ userTitle = caption;
+ if ((what == 0) || (what == 1))
+ iconText = caption;
+ if (what == 11) {
+ QString colorString = caption.section(';',0,0);
+ QColor backColor = QColor(colorString);
+ if (backColor.isValid()){// change color via \033]11;Color\007
+ if (backColor != modifiedBackground) {
+ modifiedBackground = backColor;
+ te->setDefaultBackColor(backColor);
+ }
+ }
+ }
+ if (what == 30)
+ renameSession(caption);
+ if (what == 31) {
+ cwd=caption;
+ cwd=cwd.replace( QRegExp("^~"), QDir::homeDirPath() );
+ emit openURLRequest(cwd);
+ }
+ if (what == 32) { // change icon via \033]32;Icon\007
+ iconName = caption;
+ te->update();
+ }
+
+ emit updateTitle(this);
+}
+
+QString TESession::fullTitle() const
+{
+ QString res = title;
+ if ( !userTitle.isEmpty() )
+ res = userTitle + " - " + res;
+ return res;
+}
+
+void TESession::monitorTimerDone()
+{
+ if (monitorSilence) {
+ KNotifyClient::event(winId, "Silence", i18n("Silence in session '%1'").arg(title));
+ emit notifySessionState(this,NOTIFYSILENCE);
+ }
+ notifiedActivity=false;
+}
+
+void TESession::notifySessionState(int state)
+{
+ if (state==NOTIFYBELL) {
+ te->Bell(em->isConnected(),i18n("Bell in session '%1'").arg(title));
+ } else if (state==NOTIFYACTIVITY) {
+ if (monitorSilence) {
+ monitorTimer->start(silence_seconds*1000,true);
+ }
+ if (!monitorActivity)
+ return;
+ if (!notifiedActivity) {
+ KNotifyClient::event(winId, "Activity", i18n("Activity in session '%1'").arg(title));
+ notifiedActivity=true;
+ monitorTimer->start(silence_seconds*1000,true);
+ }
+ }
+
+ emit notifySessionState(this, state);
+}
+
+void TESession::onContentSizeChange(int height, int width)
+{
+ // ensure that image is at least one line high by one column wide
+ const int columns = QMAX( width/font_w , 1 );
+ const int lines = QMAX( height/font_h , 1 );
+
+ em->onImageSizeChange( lines , columns );
+ sh->setSize( lines , columns );
+}
+
+void TESession::onFontMetricChange(int height, int width)
+{
+ //kdDebug(1211)<<"TESession::onFontMetricChange " << height << " " << width << endl;
+ if (connected) {
+ font_h = height;
+ font_w = width;
+ }
+}
+
+bool TESession::sendSignal(int signal)
+{
+ return sh->kill(signal);
+}
+
+bool TESession::closeSession()
+{
+ autoClose = true;
+ wantedClose = true;
+ if (!sh->isRunning() || !sendSignal(SIGHUP))
+ {
+ // Forced close.
+ QTimer::singleShot(1, this, SLOT(done()));
+ }
+ return true;
+}
+
+void TESession::feedSession(const QString &text)
+{
+ emit disableMasterModeConnections();
+ setListenToKeyPress(true);
+ te->emitText(text);
+ setListenToKeyPress(false);
+ emit enableMasterModeConnections();
+}
+
+void TESession::sendSession(const QString &text)
+{
+ QString newtext=text;
+ newtext.append("\r");
+ feedSession(newtext);
+}
+
+void TESession::renameSession(const QString &name)
+{
+ title=name;
+ emit renameSession(this,name);
+}
+
+TESession::~TESession()
+{
+ //kdDebug(1211) << "disconnnecting..." << endl;
+ QObject::disconnect( sh, SIGNAL( done(int) ),
+ this, SLOT( done(int) ) );
+ delete em;
+ delete sh;
+
+ delete zmodemProc;
+}
+
+void TESession::setConnect(bool c)
+{
+ connected=c;
+ em->setConnect(c);
+ setListenToKeyPress(c);
+}
+
+void TESession::setListenToKeyPress(bool l)
+{
+ em->setListenToKeyPress(l);
+}
+
+void TESession::done() {
+ emit processExited(sh);
+ emit done(this);
+}
+
+void TESession::done(int exitStatus)
+{
+ if (!autoClose)
+ {
+ userTitle = i18n("<Finished>");
+ emit updateTitle(this);
+ return;
+ }
+ if (!wantedClose && (exitStatus || sh->signalled()))
+ {
+ if (sh->normalExit())
+ KNotifyClient::event(winId, "Finished", i18n("Session '%1' exited with status %2.").arg(title).arg(exitStatus));
+ else if (sh->signalled())
+ {
+ if (sh->coreDumped())
+ KNotifyClient::event(winId, "Finished", i18n("Session '%1' exited with signal %2 and dumped core.").arg(title).arg(sh->exitSignal()));
+ else
+ KNotifyClient::event(winId, "Finished", i18n("Session '%1' exited with signal %2.").arg(title).arg(sh->exitSignal()));
+ }
+ else
+ KNotifyClient::event(winId, "Finished", i18n("Session '%1' exited unexpectedly.").arg(title));
+ }
+ emit processExited(sh);
+ emit done(this);
+}
+
+void TESession::terminate()
+{
+ delete this;
+}
+
+TEmulation* TESession::getEmulation()
+{
+ return em;
+}
+
+// following interfaces might be misplaced ///
+
+int TESession::schemaNo()
+{
+ return schema_no;
+}
+
+int TESession::encodingNo()
+{
+ return encoding_no;
+}
+
+int TESession::keymapNo()
+{
+ return em->keymapNo();
+}
+
+QString TESession::keymap()
+{
+ return em->keymap();
+}
+
+int TESession::fontNo()
+{
+ return font_no;
+}
+
+const QString & TESession::Term()
+{
+ return term;
+}
+
+const QString & TESession::SessionId()
+{
+ return sessionId;
+}
+
+void TESession::setSchemaNo(int sn)
+{
+ schema_no = sn;
+}
+
+void TESession::setEncodingNo(int index)
+{
+ encoding_no = index;
+}
+
+void TESession::setKeymapNo(int kn)
+{
+ em->setKeymap(kn);
+}
+
+void TESession::setKeymap(const QString &id)
+{
+ em->setKeymap(id);
+}
+
+void TESession::setFontNo(int fn)
+{
+ font_no = fn;
+}
+
+void TESession::setTitle(const QString& _title)
+{
+ title = _title;
+ //kdDebug(1211)<<"Session setTitle " << title <<endl;
+}
+
+const QString& TESession::Title()
+{
+ return title;
+}
+
+void TESession::setIconName(const QString& _iconName)
+{
+ iconName = _iconName;
+}
+
+void TESession::setIconText(const QString& _iconText)
+{
+ iconText = _iconText;
+ //kdDebug(1211)<<"Session setIconText " << iconText <<endl;
+}
+
+const QString& TESession::IconName()
+{
+ return iconName;
+}
+
+const QString& TESession::IconText()
+{
+ return iconText;
+}
+
+bool TESession::testAndSetStateIconName (const QString& newname)
+{
+ if (newname != stateIconName)
+ {
+ stateIconName = newname;
+ return true;
+ }
+ return false;
+}
+
+void TESession::setHistory(const HistoryType &hType)
+{
+ em->setHistory(hType);
+}
+
+const HistoryType& TESession::history()
+{
+ return em->history();
+}
+
+void TESession::clearHistory()
+{
+ if (history().isOn()) {
+ int histSize = history().getSize();
+ setHistory(HistoryTypeNone());
+ if (histSize)
+ setHistory(HistoryTypeBuffer(histSize));
+ else
+ setHistory(HistoryTypeFile());
+ }
+}
+
+QStrList TESession::getArgs()
+{
+ return args;
+}
+
+QString TESession::getPgm()
+{
+ return pgm;
+}
+
+QString TESession::getCwd()
+{
+#ifdef HAVE_PROC_CWD
+ if (cwd.isEmpty()) {
+ QFileInfo Cwd(QString("/proc/%1/cwd").arg(sh->pid()));
+ if(Cwd.isSymLink())
+ return Cwd.readLink();
+ }
+#endif /* HAVE_PROC_CWD */
+ return cwd;
+}
+
+bool TESession::isMonitorActivity() { return monitorActivity; }
+bool TESession::isMonitorSilence() { return monitorSilence; }
+bool TESession::isMasterMode() { return masterMode; }
+
+void TESession::setMonitorActivity(bool _monitor)
+{
+ monitorActivity=_monitor;
+ notifiedActivity=false;
+}
+
+void TESession::setMonitorSilence(bool _monitor)
+{
+ if (monitorSilence==_monitor)
+ return;
+
+ monitorSilence=_monitor;
+ if (monitorSilence)
+ monitorTimer->start(silence_seconds*1000,true);
+ else
+ monitorTimer->stop();
+}
+
+void TESession::setMonitorSilenceSeconds(int seconds)
+{
+ silence_seconds=seconds;
+ if (monitorSilence) {
+ monitorTimer->start(silence_seconds*1000,true);
+ }
+}
+
+void TESession::setMasterMode(bool _master)
+{
+ masterMode=_master;
+}
+
+void TESession::setAddToUtmp(bool set)
+{
+ add_to_utmp = set;
+}
+
+void TESession::setXonXoff(bool set)
+{
+ xon_xoff = set;
+}
+
+void TESession::slotZModemDetected()
+{
+ if (!zmodemBusy)
+ {
+ QTimer::singleShot(10, this, SLOT(emitZModemDetected()));
+ zmodemBusy = true;
+ }
+}
+
+void TESession::emitZModemDetected()
+{
+ emit zmodemDetected(this);
+}
+
+void TESession::cancelZModem()
+{
+ sh->send_bytes("\030\030\030\030", 4); // Abort
+ zmodemBusy = false;
+}
+
+void TESession::startZModem(const QString &zmodem, const QString &dir, const QStringList &list)
+{
+ zmodemBusy = true;
+ zmodemProc = new KProcIO;
+
+ (*zmodemProc) << zmodem << "-v";
+ for(QStringList::ConstIterator it = list.begin();
+ it != list.end();
+ ++it)
+ {
+ (*zmodemProc) << (*it);
+ }
+
+ if (!dir.isEmpty())
+ zmodemProc->setWorkingDirectory(dir);
+ zmodemProc->start(KProcIO::NotifyOnExit, false);
+
+ // Override the read-processing of KProcIO
+ disconnect(zmodemProc,SIGNAL (receivedStdout (KProcess *, char *, int)), 0, 0);
+ connect(zmodemProc,SIGNAL (receivedStdout (KProcess *, char *, int)),
+ this, SLOT(zmodemSendBlock(KProcess *, char *, int)));
+ connect(zmodemProc,SIGNAL (receivedStderr (KProcess *, char *, int)),
+ this, SLOT(zmodemStatus(KProcess *, char *, int)));
+ connect(zmodemProc,SIGNAL (processExited(KProcess *)),
+ this, SLOT(zmodemDone()));
+
+ disconnect( sh,SIGNAL(block_in(const char*,int)), this, SLOT(onRcvBlock(const char*,int)) );
+ connect( sh,SIGNAL(block_in(const char*,int)), this, SLOT(zmodemRcvBlock(const char*,int)) );
+ connect( sh,SIGNAL(buffer_empty()), this, SLOT(zmodemContinue()));
+
+ zmodemProgress = new ZModemDialog(te->topLevelWidget(), false,
+ i18n("ZModem Progress"));
+
+ connect(zmodemProgress, SIGNAL(user1Clicked()),
+ this, SLOT(zmodemDone()));
+
+ zmodemProgress->show();
+}
+
+void TESession::zmodemSendBlock(KProcess *, char *data, int len)
+{
+ sh->send_bytes(data, len);
+// qWarning("<-- %d bytes", len);
+ if (sh->buffer_full())
+ {
+ zmodemProc->suspend();
+// qWarning("ZModem suspend");
+ }
+}
+
+void TESession::zmodemContinue()
+{
+ zmodemProc->resume();
+// qWarning("ZModem resume");
+}
+
+void TESession::zmodemStatus(KProcess *, char *data, int len)
+{
+ QCString msg(data, len+1);
+ while(!msg.isEmpty())
+ {
+ int i = msg.find('\015');
+ int j = msg.find('\012');
+ QCString txt;
+ if ((i != -1) && ((j == -1) || (i < j)))
+ {
+ msg = msg.mid(i+1);
+ }
+ else if (j != -1)
+ {
+ txt = msg.left(j);
+ msg = msg.mid(j+1);
+ }
+ else
+ {
+ txt = msg;
+ msg.truncate(0);
+ }
+ if (!txt.isEmpty())
+ zmodemProgress->addProgressText(QString::fromLocal8Bit(txt));
+ }
+}
+
+void TESession::zmodemRcvBlock(const char *data, int len)
+{
+ QByteArray ba;
+ ba.duplicate(data, len);
+ zmodemProc->writeStdin(ba);
+// qWarning("--> %d bytes", len);
+}
+
+void TESession::zmodemDone()
+{
+ if (zmodemProc)
+ {
+ delete zmodemProc;
+ zmodemProc = 0;
+ zmodemBusy = false;
+
+ disconnect( sh,SIGNAL(block_in(const char*,int)), this ,SLOT(zmodemRcvBlock(const char*,int)) );
+ disconnect( sh,SIGNAL(buffer_empty()), this, SLOT(zmodemContinue()));
+ connect( sh,SIGNAL(block_in(const char*,int)), this, SLOT(onRcvBlock(const char*,int)) );
+
+ sh->send_bytes("\030\030\030\030", 4); // Abort
+ sh->send_bytes("\001\013\n", 3); // Try to get prompt back
+ zmodemProgress->done();
+ }
+}
+
+
+bool TESession::processDynamic(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &replyData)
+{
+ if (fullScripting)
+ {
+ if (fun == "feedSession(QString)")
+ {
+ QString arg0;
+ QDataStream arg( data, IO_ReadOnly );
+ arg >> arg0;
+ feedSession(arg0);
+ replyType = "void";
+ return true;
+ }
+ else if (fun == "sendSession(QString)")
+ {
+ QString arg0;
+ QDataStream arg( data, IO_ReadOnly );
+ arg >> arg0;
+ sendSession(arg0);
+ replyType = "void";
+ return true;
+ }
+ }
+ return SessionIface::processDynamic(fun, data, replyType, replyData);
+
+}
+
+QCStringList TESession::functionsDynamic()
+{
+ QCStringList funcs = SessionIface::functionsDynamic();
+ if (fullScripting)
+ {
+ funcs << "void feedSession(QString text)";
+ funcs << "void sendSession(QString text)";
+ }
+ return funcs;
+}
+
+
+void TESession::onRcvBlock( const char* buf, int len )
+{
+ em->onRcvBlock( buf, len );
+ emit receivedData( QString::fromLatin1( buf, len ) );
+}
+
+void TESession::print( QPainter &paint, bool friendly, bool exact )
+{
+ te->print(paint, friendly, exact);
+}
+
+QString TESession::schema()
+{
+ QString currentSchema;
+ emit getSessionSchema(this, currentSchema);
+ return currentSchema;
+}
+
+void TESession::setSchema(const QString &schema)
+{
+ emit setSessionSchema(this, schema);
+}
+
+QString TESession::font()
+{
+ return te->getVTFont().toString();
+}
+
+void TESession::setFont(const QString &font)
+{
+ QFont tmp;
+ if (tmp.fromString(font))
+ te->setVTFont(tmp);
+ else
+ kdWarning()<<"unknown font: "<<font<<endl;
+}
+
+QString TESession::encoding()
+{
+ return em->codec()->name();
+}
+
+void TESession::setEncoding(const QString &encoding)
+{
+ emit setSessionEncoding(this, encoding);
+}
+
+QString TESession::keytab()
+{
+ return keymap();
+}
+
+void TESession::setKeytab(const QString &keytab)
+{
+ setKeymap(keytab);
+ emit updateSessionConfig(this);
+}
+
+QSize TESession::size()
+{
+ return em->imageSize();
+}
+
+void TESession::setSize(QSize size)
+{
+ if ((size.width() <= 1) || (size.height() <= 1))
+ return;
+
+ emit resizeSession(this, size);
+}
+
+#include "session.moc"