Files
konsole/src/main.C
Lars Doelle 3fb1836e07 configuration adjustments
svn path=/trunk/kdebase/konsole/; revision=39677
2000-01-31 10:18:41 +00:00

1144 lines
36 KiB
C

/* -------------------------------------------------------------------------- */
/* */
/* [main.C] Konsole */
/* */
/* -------------------------------------------------------------------------- */
/* */
/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */
/* */
/* This file is part of Konsole, an X terminal. */
/* */
/* The material contained in here more or less directly orginates from */
/* kvt, which is copyright (c) 1996 by Matthias Ettrich <ettrich@kde.org> */
/* */
/* -------------------------------------------------------------------------- */
/*! \class Konsole
\brief Konsole's main class and program
The class Konsole handles the application level. Mainly, it is responsible
for the configuration, taken from several files, from the command line
and from the user. It hardly does anything interesting.
*/
/*WORKING ON:
- order the configuration steps properly.
- general default values
- session management OR saved configuration
- command line parameters (for initial session only)
* other runtime config (menu, resize, etc).
*/
/*FIXME:
- All the material in here badly sufferes from the fact that the
configuration can originate from many places, so all is duplicated
and falls out of service. Especially the command line is badly broken.
The sources are:
- command line
- menu
- configuration files
- other events (e.g. resizing)
We have to find a single-place method to maintain this.
Scedule: post kde 1.2
- Controling the widget is currently done by individual attributes.
This lead to quite some amount of flicker when a whole bunch of
attributes has to be set, e.g. in session swapping.
Scedule: post kde 1.2
- The schema file name in session config files is not location
transparent.
*/
/* TODO
- don't reread the pixmap every time
*/
#include"config.h"
#include <qdir.h>
#include <qevent.h>
#include <qdragobject.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <kcolordlg.h>
#include <kfontdialog.h>
#include <kglobal.h>
#include <kstddirs.h>
#include <kconfig.h>
#include <kurl.h>
#include <qpainter.h>
#include <kmenubar.h>
#include <kmessagebox.h>
#include <krootpixmap.h>
#include <kcmdlineargs.h>
#include <kimgio.h>
#include <qintdict.h>
#include <qptrdict.h>
#include <qmessagebox.h>
#include <locale.h>
#include <klocale.h>
#include <kwm.h>
#include <sys/wait.h>
#include <assert.h>
#include <kaboutdata.h>
#include "main.h"
#include "keytrans.h"
#define HERE printf("%s(%d): here\n",__FILE__,__LINE__)
#undef PACKAGE
#undef VERSION
#define PACKAGE "konsole"
#define VERSION "0.9.12"
static const char *description =
I18N_NOOP("X terminal for use with KDE.");
static KCmdLineOptions options[] =
{
{ "name <name>", I18N_NOOP("Set Window Class"), 0 },
{ "ls", I18N_NOOP("Start login shell"), 0 },
{ "nowelcome", I18N_NOOP("Suppress greeting"), 0 },
{ "nohist", I18N_NOOP("Do not save lines in scroll-back buffer"), 0 },
{ "vt_sz CCxLL", I18N_NOOP("Terminal size in columns x lines"), 0 },
{ "e <command>", I18N_NOOP("Execute 'command' instead of shell"), 0 },
//FIXME: WABA: We need a way to say that all options after -e should be treated as arguments.
{ "+[args]", I18N_NOOP("Arguments for 'command'"), 0 },
{ 0, 0, 0 }
};
template class QIntDict<TESession>;
template class QIntDict<KSimpleConfig>;
const char *fonts[] = {
"6x13", // FIXME: "fixed" used in favor of this
"5x7", // tiny font, never used
"6x10", // small font
"7x13", // medium
"9x15", // large
"10x20", // huge
"-misc-console-medium-r-normal--16-160-72-72-c-160-iso10646-1", // "Linux"
"-misc-fixed-medium-r-normal--15-140-75-75-c-90-iso10646-1", // "Unicode"
};
#define TOPFONT ((sizeof(fonts)/sizeof(char*))-1)
static QIntDict<TESession> no2session;
//static QPtrDict<void> session2no;
static QPtrDict<QObject> session2no;
static int session_no = 0;
static QIntDict<KSimpleConfig> no2command;
static int cmd_serial = 0;
Konsole::Konsole(const QString& name,
const char* _pgm, QStrList & _args,
int histon) : KTMainWindow(name), pgm(_pgm), args(_args)
{
se = 0L;
rootxpm = 0L;
menubar = menuBar();
b_scroll = histon;
b_fullscreen = FALSE;
// create terminal emulation framework ////////////////////////////////////
te = new TEWidget(this);
te->setMinimumSize(150,70); // allow resizing, cause resize in TEWidget
// Transparency handler ///////////////////////////////////////////////////
rootxpm = new KRootPixmap(te);
// create applications /////////////////////////////////////////////////////
setView(te,FALSE);
makeMenu();
makeStatusbar();
// Init DnD ////////////////////////////////////////////////////////////////
setAcceptDrops(true);
// load session commands ///////////////////////////////////////////////////
loadSessionCommands();
m_file->insertSeparator();
m_file->insertItem( i18n("&Quit"), kapp, SLOT(quit()));
// load schema /////////////////////////////////////////////////////////////
curr_schema = 0;
ColorSchema::loadAllSchemas();
//FIXME: sort
for (int i = 0; i < ColorSchema::count(); i++)
{ ColorSchema* s = ColorSchema::find(i);
assert( s );
m_schema->insertItem(s->title.data(),s->numb);
}
//FIXME: we should build a complete session before running it.
// set global options ///////////////////////////////////////////////////////
if (b_menuvis) menubar->show(); else menubar->hide();
te->setFrameStyle( b_framevis
? QFrame::WinPanel | QFrame::Sunken
: QFrame::NoFrame );
te->setScrollbarLocation(n_scroll);
//FIXME: call newSession here, somehow, instead the stuff below.
// construct initial session ///////////////////////////////////////////////
TESession* initial = new TESession(this,te,pgm,args,"xterm");
title = (args.count() && (kapp->caption() == PACKAGE))
? QString(args.at(0)) // program executed in the title bar
: kapp->caption(); // `konsole' or -caption
initial->setTitle(title);
//initial->setHistory(b_scroll); //FIXME: take from schema
setHistory(b_scroll); //FIXME: take from schema
addSession(initial);
// read and apply default values ///////////////////////////////////////////
readProperties(kapp->config());
// activate and run first session //////////////////////////////////////////
// WABA: Make sure all the xxxBars are in place so that
// we can resize our mainWidget to its target size.
updateRects();
runSession(initial);
}
/*!
sets application window to a size
based on columns X lines of the te
guest widget. Call with (0,0) for setting default size.
*/
void Konsole::setColLin(int columns, int lines)
{
if (columns==0 && lines==0)
{
if (defaultSize.isNull()) // not in config file : set default value
{
defaultSize = te->calcSize(80,24);
notifySize(24,80); // set menu items (strange arg order !)
}
te->resize(defaultSize);
}
else
{
QSize size = te->calcSize(columns, lines);
te->resize(size);
notifySize(lines,columns); // set menu items (strange arg order !)
}
adjustSize();
}
Konsole::~Konsole()
{
//FIXME: close all session properly and clean up
}
/* ------------------------------------------------------------------------- */
/* */
/* Drag & Drop */
/* */
/* ------------------------------------------------------------------------- */
void Konsole::dragEnterEvent(QDragEnterEvent* e)
{
e->accept(QTextDrag::canDecode(e) ||
QUriDrag::canDecode(e));
}
void Konsole::dropEvent(QDropEvent* event)
{
// The current behaviour when url(s) are dropped is
// * if there is only ONE url and if it's a LOCAL one, ask for paste or cd
// * in all other cases, just paste
// (for non-local ones, or for a list of URLs, 'cd' is nonsense)
QStrList strlist;
KURL *url;
int file_count = 0;
dropText = "";
bool bPopup = true;
if(QUriDrag::decode(event, strlist)) {
if (strlist.count()) {
for(const char* p = strlist.first(); p; p = strlist.next()) {
if(file_count++ > 0) {
dropText += " ";
bPopup = false; // more than one file, don't popup
}
url = new KURL( QString(p) );
if (url->isLocalFile()) {
dropText += url->path(); // local URL : remove protocol
}
else {
dropText += p;
bPopup = false; // a non-local file, don't popup
}
delete url;
p = strlist.next();
}
if (bPopup)
m_drop->popup(pos() + event->pos());
else
se->getEmulation()->sendString(dropText.latin1());
}
}
else if(QTextDrag::decode(event, dropText))
se->getEmulation()->sendString(dropText.latin1()); // Paste it
}
void Konsole::drop_menu_activated(int item)
{
switch (item)
{
case 0: // paste
se->getEmulation()->sendString(dropText.data());
// KWM::activate((Window)this->winId());
break;
case 1: // cd ...
se->getEmulation()->sendString("cd ");
KURL url( dropText );
se->getEmulation()->sendString(url.directory());
se->getEmulation()->sendString("\n");
// KWM::activate((Window)this->winId());
break;
}
}
/* ------------------------------------------------------------------------- */
/* */
/* */
/* ------------------------------------------------------------------------- */
void Konsole::configureRequest(TEWidget* te, int state, int x, int y)
{
//printf("Konsole::configureRequest(_,%d,%d)\n",x,y);
( (state & ShiftButton ) ? m_sessions :
(state & ControlButton) ? m_file :
m_options )
->popup(te->mapToGlobal(QPoint(x,y)));
}
/* ------------------------------------------------------------------------- */
/* */
/* */
/* ------------------------------------------------------------------------- */
void Konsole::makeStatusbar()
{
//statusbar = new KStatusBar(this);
//setStatusBar(statusbar);
}
/* ------------------------------------------------------------------------- */
/* */
/* */
/* ------------------------------------------------------------------------- */
void Konsole::makeMenu()
{
// options (taken from kvt) //////////////////////////////////////
//m_commands = new QPopupMenu;
//connect(m_commands, SIGNAL(activated(int)), SLOT(newSession(int)));
QPopupMenu* m_signals = new QPopupMenu;
m_signals->insertItem( i18n("STOP"), 17 ); // FIXME: comes with 3 values
m_signals->insertItem( i18n("CONT"), 18 ); // FIXME: comes with 3 values
m_signals->insertItem( i18n("HUP"), 1 );
m_signals->insertItem( i18n("INT"), 2 );
m_signals->insertItem( i18n("TERM"), 15 );
m_signals->insertItem( i18n("KILL"), 9 );
connect(m_signals, SIGNAL(activated(int)), SLOT(sendSignal(int)));
m_sessions = new QPopupMenu;
m_sessions->setCheckable(TRUE);
m_sessions->insertItem( i18n("Send Signal"), m_signals );
m_sessions->insertSeparator();
connect(m_sessions, SIGNAL(activated(int)), SLOT(activateSession(int)));
m_file = new QPopupMenu;
connect(m_file, SIGNAL(activated(int)), SLOT(newSession(int)));
m_font = new QPopupMenu;
m_font->setCheckable(TRUE);
m_font->insertItem( i18n("&Normal"), 0);
m_font->insertSeparator();
//m_font->insertItem( i18n("&Tiny"), 1);
m_font->insertItem( i18n("&Small"), 2);
m_font->insertItem( i18n("&Medium"), 3);
m_font->insertItem( i18n("&Large"), 4);
m_font->insertItem( i18n("&Huge"), 5);
m_font->insertSeparator();
m_font->insertItem( i18n("&Linux"), 6);
m_font->insertItem( i18n("&Unicode"),7);
m_font->insertSeparator();
m_font->insertItem( i18n("&Custom ..."), 1000); // for other fonts
connect(m_font, SIGNAL(activated(int)), SLOT(font_menu_activated(int)));
m_scrollbar = new QPopupMenu;
m_scrollbar->setCheckable(TRUE);
m_scrollbar->insertItem( i18n("&Hide"), TEWidget::SCRNONE);
m_scrollbar->insertItem( i18n("&Left"), TEWidget::SCRLEFT);
m_scrollbar->insertItem( i18n("&Right"), TEWidget::SCRRIGHT);
connect(m_scrollbar, SIGNAL(activated(int)), SLOT(scrollbar_menu_activated(int)));
m_size = new QPopupMenu;
m_size->setCheckable(TRUE);
m_size->insertItem( i18n("40x15 (&small)"), 0);
m_size->insertItem( i18n("80x24 (&vt100)"), 1);
m_size->insertItem( i18n("80x25 (&ibmpc)"), 2);
m_size->insertItem( i18n("80x40 (&xterm)"), 3);
m_size->insertItem( i18n("80x52 (ibmv&ga)"), 4);
connect(m_size, SIGNAL(activated(int)), SLOT(size_menu_activated(int)));
m_schema = new QPopupMenu;
m_schema->setCheckable(TRUE);
connect(m_schema, SIGNAL(activated(int)), SLOT(schema_menu_activated(int)));
QPopupMenu* m_keytab = new QPopupMenu;
m_keytab->setCheckable(TRUE);
m_keytab->insertItem( i18n("&xterm"), 1 );
m_keytab->setItemChecked(1,TRUE);
QPopupMenu* m_codec = new QPopupMenu;
m_codec->setCheckable(TRUE);
m_codec->insertItem( i18n("&locale"), 1 );
m_codec->setItemChecked(1,TRUE);
m_options = new QPopupMenu;
m_options->setCheckable(TRUE);
m_options->insertItem( i18n("&Menubar"), 1 );
m_options->insertItem( i18n("&Frame"), 2 );
m_options->insertItem( i18n("Scroll&bar"), m_scrollbar);
m_options->insertSeparator();
m_options->insertItem( i18n("&Fullscreen"), 5);
m_options->setItemChecked(5,b_fullscreen);
m_options->insertSeparator();
m_options->insertItem( i18n("&Size"), m_size);
m_options->insertItem( i18n("&Font"), m_font);
m_options->insertItem( i18n("&Schema"), m_schema);
m_options->insertSeparator();
m_options->insertItem( i18n("&History"), 3 );
m_options->insertSeparator();
m_options->insertItem( i18n("&Codec"), m_codec);
m_options->insertItem( i18n("&Keyboard"), m_keytab);
m_options->insertItem( i18n("BS sends &DEL"), 4 );
m_options->setItemChecked(4,b_bshack);
m_options->insertSeparator();
m_options->insertItem( i18n("&Save Options"), 8);
connect(m_options, SIGNAL(activated(int)), SLOT(opt_menu_activated(int)));
QString aboutAuthor = i18n("%1 version %2 - an X terminal\n"
"Copyright (c) 1997-2000 by\n"
"Lars Doelle <lars.doelle@on-line.de>\n"
"\n"
"This program is free software under the\n"
"terms of the GNU General Public License\n"
"and comes WITHOUT ANY WARRANTY.\n"
"See 'LICENSE.readme' for details.").arg(PACKAGE).arg(VERSION);
QPopupMenu* m_help = helpMenu(aboutAuthor, false);
m_help->insertItem( i18n("&Technical Reference ..."), this, SLOT(tecRef()),
0, -1, 1);
m_drop = new QPopupMenu;
m_drop->insertItem( i18n("Paste"), 0);
m_drop->insertItem( i18n("cd"), 1);
connect(m_drop, SIGNAL(activated(int)), SLOT(drop_menu_activated(int)));
m_options->installEventFilter( this );
// For those who would like to add shortcuts here, be aware that
// ALT-key combinations are heavily used by many programs. Thus,
// activating shortcuts here means deactivating them in the other
// programs.
menubar->insertItem(i18n("File") , m_file);
//menubar->insertItem(i18n("New"), m_commands);
menubar->insertItem(i18n("Sessions"), m_sessions);
menubar->insertItem(i18n("Options"), m_options);
menubar->insertSeparator();
menubar->insertItem(i18n("Help"), m_help);
}
/* ------------------------------------------------------------------------- */
/* */
/* Configuration */
/* */
/* ------------------------------------------------------------------------- */
void Konsole::saveProperties(KConfig* config)
{
config->setGroup("options"); // bad! will no allow us to support multi windows
config->writeEntry("menubar visible",b_menuvis);
config->writeEntry("history",b_scroll);
config->writeEntry("has frame",b_framevis);
config->writeEntry("BS hack",b_bshack);
config->writeEntry("Fullscreen",b_fullscreen);
config->writeEntry("font",n_font);
config->writeEntry("defaultfont", defaultFont);
config->writeEntry("schema",s_schema);
config->writeEntry("scrollbar",n_scroll);
if (args.count() > 0) config->writeEntry("konsolearguments", args);
config->writeEntry("class",name());
config->writeEntry("defaultheight", height()); // for "save options". Not used by SM.
config->writeEntry("defaultwidth", width()); // for "save options". Not used by SM.
//config->writeEntry("kmenubar", //FIXME:Float
// menubar->menuBarPos() == KMenuBar::Bottom ? "bottom" : "top");
// geometry (placement) done by KTMainWindow
config->sync();
}
// Called by constructor (with config = kapp->config())
// and by session-management (with config = sessionconfig).
// So it has to apply the settings when reading them.
void Konsole::readProperties(KConfig* config)
{
config->setGroup("options"); // bad! will no allow us to support multi windows
/*FIXME: (merging) state of material below unclear.*/
b_menuvis = config->readBoolEntry("menubar visible",TRUE);
b_framevis = config->readBoolEntry("has frame",TRUE);
b_scroll = config->readBoolEntry("history",TRUE);
b_bshack = config->readBoolEntry("BS hack",TRUE);
b_fullscreen = config->readBoolEntry("Fullscreen",FALSE);
n_font = QMIN(config->readUnsignedNumEntry("font",3),TOPFONT);
n_scroll = QMIN(config->readUnsignedNumEntry("scrollbar",TEWidget::SCRRIGHT),2);
s_schema = config->readEntry("schema","");
// Global options ///////////////////////
setMenuVisible(config->readBoolEntry("menubar visible",TRUE));
setFrameVisible(config->readBoolEntry("has frame",TRUE));
scrollbar_menu_activated(QMIN(config->readUnsignedNumEntry("scrollbar",TEWidget::SCRRIGHT),2));
// not necessary for SM (KTMainWindow does it after), but useful for default settings
/*FIXME: (merging) state of material below unclear*/
// Commented out; kmenubar not movable any more (sven)
// if (menubar->menuBarPos() != KMenuBar::Floating)
// { QString entry = config->readEntry("kmenubar");
// if (!entry.isEmpty() && entry == "floating")
// {
// menubar->setMenuBarPos(KMenuBar::Floating);
// QString geo = config->readEntry("kmenubargeometry");
// if (!geo.isEmpty()) menubar->setGeometry(KWM::setProperties(menubar->winId(), geo));
// }
// else if (!entry.isEmpty() && entry == "top") menubar->setMenuBarPos(KMenuBar::Top);
// else if (!entry.isEmpty() && entry == "bottom") menubar->setMenuBarPos(KMenuBar::Bottom);
// }
// (geometry stuff removed) done by KTMainWindow for SM, and not needed otherwise
// Options that should be applied to all sessions /////////////
// (1) set menu items and Konsole members
setBsHack(config->readBoolEntry("BS hack",TRUE));
QFont tmpFont("fixed");
defaultFont = config->readFontEntry("defaultfont", &tmpFont);
setFont(QMIN(config->readUnsignedNumEntry("font",3),TOPFONT)); // sets n_font and menu item
setSchema(config->readEntry("schema",""));
// (2) apply to sessions (currently only the 1st one)
TESession* s = no2session.find(1);
if (s) {
s->setFontNo(n_font);
s->setSchemaNo(ColorSchema::find(s_schema)->numb);
s->setHistory(b_scroll);
if (b_bshack)
s->getEmulation()->setMode(MODE_BsHack);
else
s->getEmulation()->resetMode(MODE_BsHack);
} else { fprintf(stderr,"session 1 not found\n"); } // oops
// Default values for startup, changed by "save options". Not used by SM.
defaultSize.setWidth ( config->readNumEntry("defaultwidth", 0) );
defaultSize.setHeight( config->readNumEntry("defaultheight", 0) );
}
/* ------------------------------------------------------------------------- */
/* */
/* */
/* ------------------------------------------------------------------------- */
void Konsole::pixmap_menu_activated(int item)
{
if (item <= 1) pmPath = "";
QPixmap pm(pmPath.data());
if (pm.isNull()) {
pmPath = "";
item = 1;
te->setBackgroundColor(te->getDefaultBackColor());
return;
}
// FIXME: respect scrollbar (instead of te->size)
n_render= item;
switch (item)
{
case 1: // none
case 2: // tile
te->setBackgroundPixmap(pm);
break;
case 3: // center
{ QPixmap bgPixmap;
bgPixmap.resize(te->size());
bgPixmap.fill(te->getDefaultBackColor());
bitBlt( &bgPixmap, ( te->size().width() - pm.width() ) / 2,
( te->size().height() - pm.height() ) / 2,
&pm, 0, 0,
pm.width(), pm.height() );
te->setBackgroundPixmap(bgPixmap);
}
break;
case 4: // full
{
float sx = (float)te->size().width() / pm.width();
float sy = (float)te->size().height() / pm.height();
QWMatrix matrix;
matrix.scale( sx, sy );
te->setBackgroundPixmap(pm.xForm( matrix ));
}
break;
default: // oops
n_render = 1;
}
}
void Konsole::scrollbar_menu_activated(int item)
{
m_scrollbar->setItemChecked(n_scroll,FALSE);
m_scrollbar->setItemChecked(item, TRUE);
n_scroll = item;
te->setScrollbarLocation(item);
}
void Konsole::font_menu_activated(int item)
{
assert(se);
if (item == 1000)
{
KFontDialog::getFont(defaultFont, true);
item = 0;
}
setFont(item);
activateSession((int)session2no.find(se)); // for attribute change
}
void Konsole::schema_menu_activated(int item)
{
assert(se);
//FIXME: save schema name
setSchema(item);
activateSession((int)session2no.find(se)); // for attribute change
}
void Konsole::setFont(int fontno)
{
QFont f;
if (fontno == 0)
f = defaultFont;
else
if (fonts[fontno][0] == '-')
f.setRawName( fonts[fontno] );
else
{
f.setFamily(fonts[fontno]);
f.setRawMode( TRUE );
}
if ( !f.exactMatch() && fontno != 0)
{
QString msg = i18n("Font `%1' not found.\nCheck README.linux.console for help.").arg(fonts[fontno]);
KMessageBox::error(this, msg);
}
else
{
te->setVTFont(f);
}
m_font->setItemChecked(n_font,FALSE);
m_font->setItemChecked(fontno, TRUE);
n_font = fontno;
if (se) se->setFontNo(fontno);
}
void Konsole::setMenuVisible(bool visible)
{
b_menuvis = visible;
m_options->setItemChecked(1,b_menuvis);
if (b_menuvis) menubar->show(); else menubar->hide();
updateRects();
}
void Konsole::setFrameVisible(bool visible)
{
b_framevis = visible;
m_options->setItemChecked(2,b_framevis);
te->setFrameStyle( b_framevis
? QFrame::WinPanel | QFrame::Sunken
: QFrame::NoFrame );
}
void Konsole::setHistory(bool on)
{
HERE; printf("setHistory: %s, having%s session.\n",on?"on":"off",se?"":" no");
b_scroll = on;
m_options->setItemChecked(3,b_scroll);
if (se) se->setHistory( b_scroll );
}
void Konsole::setBsHack(bool bshack)
{
b_bshack = bshack;
m_options->setItemChecked(4,b_bshack);
//FIXME: solve typing issue below
if (se)
if (b_bshack)
((TEmuVt102*)se->getEmulation())->setMode(MODE_BsHack);
else
((TEmuVt102*)se->getEmulation())->resetMode(MODE_BsHack);
}
void Konsole::opt_menu_activated(int item)
{
switch( item )
{
case 1: setMenuVisible(!b_menuvis);
if (!b_menuvis)
{
setCaption("Use the right mouse button to bring back the menu");
QTimer::singleShot(5000,this,SLOT(setHeader()));
}
break;
case 2: setFrameVisible(!b_framevis);
break;
case 3: setHistory(!b_scroll);
break;
case 4: setBsHack(!b_bshack);
break;
case 5: setFullScreen(!b_fullscreen);
break;
case 8: saveProperties(kapp->config());
break;
}
}
// --| color selection |-------------------------------------------------------
void Konsole::changeColumns(int columns)
{
setColLin(columns,24); // VT100, FIXME: keep lines?
te->update();
}
void Konsole::size_menu_activated(int item)
{
switch (item)
{
case 0: setColLin(40,15); break;
case 1: setColLin(80,24); break;
case 2: setColLin(80,25); break;
case 3: setColLin(80,40); break;
case 4: setColLin(80,52); break;
}
}
void Konsole::notifySize(int lines, int columns)
{
// printf("notifySize(%d,%d)\n",lines,columns);
/*
if (lines != lincol.height() || columns != lincol.width())
{ char buf[100];
sprintf(buf,i18n("(%d columns x %d lines)"),columns,lines);
setCaption(buf);
QTimer::singleShot(2000,this,SLOT(setHeader()));
}
*/
m_size->setItemChecked(0,columns==40&&lines==15);
m_size->setItemChecked(1,columns==80&&lines==24);
m_size->setItemChecked(2,columns==80&&lines==25);
m_size->setItemChecked(3,columns==80&&lines==40);
m_size->setItemChecked(4,columns==80&&lines==52);
if (n_render >= 3) pixmap_menu_activated(n_render);
}
void Konsole::setHeader()
{
setCaption(title);
}
void Konsole::changeTitle(int, const QString& s)
{
title = s; setHeader();
}
void Konsole::setFullScreen(bool on)
{
if (on == b_fullscreen) return;
if (on)
{
_saveGeometry = geometry();
setGeometry(kapp->desktop()->geometry());
}
else
{
setGeometry(_saveGeometry);
}
b_fullscreen = on;
m_options->setItemChecked(5,b_fullscreen);
}
// --| help |------------------------------------------------------------------
void Konsole::tecRef()
{
kapp->invokeHTMLHelp(PACKAGE "/techref.html","");
}
/* --| sessions |------------------------------------------------------------ */
//FIXME: activating sessions creates a lot flicker in the moment.
// it comes from setting the attributes of a session individually.
// ONE setImage call should actually be enough to match all cases.
// These can be quite different:
// - The screen size might have changed while the session was
// detached. A propagation of the resize should in this case
// make the drawEvent.
// - font, background image and color palette should be set in one go.
void Konsole::sendSignal(int sn)
{
if (se) se->kill(sn);
}
void Konsole::activateSession(int sn)
{
TESession* s = no2session.find(sn);
if (se)
{
se->setConnect(FALSE);
int no = (int)session2no.find(se);
m_sessions->setItemChecked(no,FALSE);
}
se = s;
if (!s) { fprintf(stderr,"session not found\n"); return; } // oops
m_sessions->setItemChecked(sn,TRUE);
if (s->schemaNo()!=curr_schema) {
setSchema(s->schemaNo()); //FIXME: creates flicker? Do only if differs
//Set Font. Now setConnect should do the appropriate action.
//if the size has changed, a resize event (noticable to the application)
//should happen. Else, we could even start the application
s->setConnect(TRUE); // does a bulkShow (setImage)
setFont(s->fontNo()); //FIXME: creates flicker?
//FIXME: check here if we're still alife.
// if not, quit, otherwise,
// start propagating quit.
title = s->Title(); // take title from current session
} else {
s->setConnect(TRUE);
}
setHeader();
}
void Konsole::runSession(TESession* s)
{
int session_no = (int)session2no.find(s);
activateSession(session_no);
// give some time to get through the
// resize events before starting up.
QTimer::singleShot(100,s,SLOT(run()));
}
void Konsole::addSession(TESession* s)
{
session_no += 1;
no2session.insert(session_no,s);
session2no.insert(s,(QObject*)session_no);
m_sessions->insertItem(s->Title(), session_no);
}
void Konsole::newSession(int i)
{
const char* shell = getenv("SHELL");
if (shell == NULL || *shell == '\0') shell = "/bin/sh";
KSimpleConfig* co = no2command.find(i);
if (!co) return; // oops
assert( se ); //FIXME: careful here.
QString cmd = co->readEntry("Exec"); // not null
QString nam = co->readEntry("Name"); // not null
QString emu = co->readEntry("Term");
QString sch = co->readEntry("Schema");
QString txt = co->readEntry("Comment"); // not null
int fno = QMIN(co->readUnsignedNumEntry("Font",se->fontNo()),TOPFONT);
ColorSchema* schema = sch.isEmpty()
? (ColorSchema*)NULL
: ColorSchema::find(sch);
//FIXME: schema names here are absolut. Wrt. loadAllSchemas,
// relative pathes should be allowed, too.
int schmno = schema?schema->numb:se->schemaNo();
if (emu.isEmpty()) emu = se->emuName();
QStrList args;
args.append(shell);
args.append("-c");
args.append(cmd);
TESession* s = new TESession(this,te,shell,args,emu.data());
s->setFontNo(fno);
s->setSchemaNo(schmno);
s->setTitle(txt.data());
//s->setHistory(b_scroll); //FIXME: take from schema
setHistory(b_scroll); //FIXME: take from schema
addSession(s);
runSession(s); // activate and run
}
//FIXME: If a child dies during session swap,
// this routine might be called before
// session swap is completed.
void Konsole::doneSession(TESession* s, int )
{
//printf("%s(%d): Exited:%d ExitStatus:%d\n",__FILE__,__LINE__,WIFEXITED(status),WEXITSTATUS(status));
#if 0 // die silently
if (!WIFEXITED((status)) || WEXITSTATUS((status)))
{
//FIXME: "Title" is not a precise locator for the message.
// The command would be better.
QString str = i18n("`%1' terminated abnormally.").arg(s->Title());
if (WIFEXITED((status)))
{char rcs[100]; sprintf(rcs,"%d.\n",WEXITSTATUS((status)));
str = str + i18n("\nReturn code = ") + rcs;
}
KMessageBox::sorry(this, str);
}
#endif
int no = (int)session2no.find(s);
if (!no) return; // oops
no2session.remove(no);
session2no.remove(s);
m_sessions->removeItem(no);
s->setConnect(FALSE);
// This slot (doneSession) is activated from the TEPty when receiving a
// SIGCHLD. A lot is done during the signal handler. Apparently deleting
// the TEPty additionally is sometimes too much, causing something
// to get messed up in rare cases. The following causes delete not to
// be called from within the signal handler.
QTimer::singleShot(100,s,SLOT(terminate()));
if (s == se)
{ // pick a new session
se = NULL;
QIntDictIterator<TESession> it( no2session );
if ( it.current() )
activateSession(it.currentKey());
else
kapp->quit();
}
}
// --| Session support |-------------------------------------------------------
void Konsole::addSessionCommand(const char* path)
{
KSimpleConfig* co = new KSimpleConfig(path,TRUE);
co->setDesktopGroup();
QString typ = co->readEntry("Type");
QString txt = co->readEntry("Comment");
QString cmd = co->readEntry("Exec");
QString nam = co->readEntry("Name");
if (typ.isEmpty() || txt.isEmpty() || cmd.isEmpty() || nam.isEmpty() ||
strcmp(typ.data(),"KonsoleApplication"))
{
delete co; return; // ignore
}
m_file->insertItem(txt, ++cmd_serial);
no2command.insert(cmd_serial,co);
}
void Konsole::loadSessionCommands()
{
QStringList lst = KGlobal::dirs()->findAllResources("appdata", "*.desktop", false, true);
for(QStringList::Iterator it = lst.begin(); it != lst.end(); ++it )
addSessionCommand(*it);
}
// --| Schema support |-------------------------------------------------------
void Konsole::setSchema(int numb)
{
ColorSchema* s = ColorSchema::find(numb);
if (s) setSchema(s);
}
void Konsole::setSchema(const char* path)
{
ColorSchema* s = ColorSchema::find(path);
if (s) setSchema(s);
}
void Konsole::setSchema(const ColorSchema* s)
{
if (!s) return;
m_schema->setItemChecked(curr_schema,FALSE);
m_schema->setItemChecked(s->numb,TRUE);
s_schema = s->path;
curr_schema = s->numb;
pmPath = s->imagepath;
te->setColorTable(s->table); //FIXME: set twice here to work around a bug
if (s->usetransparency) {
//FIXME: what is this?
// rootxpm->checkAvailable(true);
rootxpm->setFadeEffect(s->tr_x, QColor(s->tr_r, s->tr_g, s->tr_b));
rootxpm->start();
} else {
rootxpm->stop();
pixmap_menu_activated(s->alignment);
}
te->setColorTable(s->table);
if (se) se->setSchemaNo(s->numb);
}
/* --| main |---------------------------------------------------------------- */
int main(int argc, char* argv[])
{
setuid(getuid()); setgid(getgid()); // drop privileges
// deal with shell/command ////////////////////////////
bool login_shell = false;
bool welcome = true;
bool histon = true;
const char* wname = PACKAGE;
KAboutData aboutData( PACKAGE, I18N_NOOP("Konsole"),
VERSION, description, KAboutData::License_GPL,
"(c) 1997-2000, Lars Doelle");
aboutData.addAuthor("Lars Doelle",0, "lars.doelle@on-line.de");
KCmdLineArgs::init( argc, argv, &aboutData );
KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
setlocale( LC_ALL, "" );
KApplication a;
kimgioRegister(); // add io for additional image formats
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
QStrList eargs;
const char* shell = getenv("SHELL");
if (shell == NULL || *shell == '\0') shell = "/bin/sh";
if (args->getOption("e").isEmpty())
{
char* t = strrchr(shell,'/');
if (args->isSet("ls") && t) // see sh(1)
{
t = strdup(t); *t = '-';
eargs.append(t);
}
else
eargs.append(shell);
}
else
{
if (args->isSet("ls"))
KCmdLineArgs::usage(i18n("You can't use BOTH -ls and -e.\n"));
shell = args->getOption("e");
eargs.clear();
eargs.append(shell);
for(int i=0; i < args->count(); i++)
eargs.append( args->arg(i) );
}
QCString sz = "";
sz = args->getOption("vt_sz");
histon = args->isSet("hist");
wname = args->getOption("name");
login_shell = args->isSet("ls");
welcome = args->isSet("welcome");
//FIXME: more: font, menu, scrollbar, schema, session ...
args->clear();
int c = 0, l = 0;
if ( !sz.isEmpty() )
{
char *ls = (char*)strchr( sz.data(), 'x' );
if ( ls != NULL )
{
*ls='\0';
ls++;
c=atoi(sz.data());
l=atoi(ls);
}
else
{
KCmdLineArgs::usage(i18n("expected --vt_sz <#columns>x<#lines> ie. 80x40\n"));
}
}
// ///////////////////////////////////////////////
putenv("COLORTERM="); // to trigger mc's color detection
if (a.isRestored())
{
KConfig * sessionconfig = a.sessionConfig();
sessionconfig->setGroup("options");
sessionconfig->readListEntry("konsolearguments", eargs);
wname = sessionconfig->readEntry("class",wname).data();
RESTORE( Konsole(wname,shell,eargs,histon) )
}
else
{
Konsole* m = new Konsole(wname,shell,eargs,histon);
m->setColLin(c,l); // will use default height and width if called with (0,0)
if (welcome)
{
m->setCaption(i18n("Welcome to the console"));
QTimer::singleShot(5000,m,SLOT(setHeader()));
}
m->show();
}
return a.exec();
}
#include "main.moc"