You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1133 lines
34 KiB

/* ---------------------------------------------------------------------- */
/* */
/* [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.
*/
/*TODO:
- allow to set coded
- officially declare this file to be hacked to death.
konsole/kwin session management, parts stuff, config, menues
are all in bad need for a complete rewrite.
*/
/*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 better maintain this.
- In general, the material contained in here and in session.C
should be rebalanced. Much more material now comes from configuration
files and the overall routines should better respect this.
- Font+Size list should go to a configuration file, too.
- 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.
*/
#include"config.h"
#include <qdir.h>
#include <qevent.h>
#include <qdragobject.h>
#include <qobjectlist.h>
#include <ktoolbarbutton.h>
#include <stdio.h>
#include <stdlib.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 <kaction.h>
#include <kstdaction.h>
#include <klineeditdlg.h>
#include <kdebug.h>
#include <qfontmetrics.h>
#include <klocale.h>
#include <sys/wait.h>
#include <assert.h>
#include <kiconloader.h>
#include "konsole.h"
#include "keytrans.h"
#define HERE printf("%s(%d): here\n",__FILE__,__LINE__)
template class QPtrDict<TESession>;
template class QIntDict<KSimpleConfig>;
template class QPtrDict<KRadioAction>;
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)
Konsole::Konsole(const char* name,
const char* _pgm, QStrList & _args,
int histon) : KMainWindow(0, name), pgm(_pgm), args(_args)
{
session_no = 0;
cmd_serial = 0;
se = 0L;
rootxpm = 0L;
menubar = menuBar();
b_scroll = histon;
b_fullscreen = FALSE;
n_keytab = 0;
// 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 /////////////////////////////////////////////////////
setCentralWidget(te);
makeMenu();
setDockEnabled( toolBar(), QMainWindow::Left, FALSE );
setDockEnabled( toolBar(), QMainWindow::Right, FALSE );
toolBar()->setFullSize( TRUE );
// toolBar()->setIconText( KToolBar::IconTextRight);
// 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,s->numb);
}
// load keymaps ////////////////////////////////////////////////////////////
KeyTrans::loadAll();
//FIXME: sort
for (int i = 0; i < KeyTrans::count(); i++)
{ KeyTrans* s = KeyTrans::find(i);
assert( s );
m_keytab->insertItem(s->hdr,s->numb);
}
m_keytab->setItemChecked(0,TRUE);
// set global options ///////////////////////////////////////////////////////
menubar->show();
// construct initial session ///////////////////////////////////////////////
//FIXME: call newSession here, somehow, instead the stuff below.
// Please do it ! It forces to duplicate code... (David)
TESession* initial = new TESession(this,te,pgm,args,"xterm");
connect( initial,SIGNAL(done(TESession*,int)),
this,SLOT(doneSession(TESession*,int)) );
connect( te, SIGNAL(configureRequest(TEWidget*, int, int, int)),
this, SLOT(configureRequest(TEWidget*,int,int,int)) );
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(KGlobal::config());
// activate and run first session //////////////////////////////////////////
runSession(initial);
// apply keytab
keytab_menu_activated(n_keytab);
setColLin(0,0);
}
Konsole::~Konsole()
{
//FIXME: close all session properly and clean up
}
/* ------------------------------------------------------------------------- */
/* Make menu */
/* ------------------------------------------------------------------------- */
void Konsole::makeMenu()
{
// options (taken from kvt) //////////////////////////////////////
m_file = new QPopupMenu(this);
connect(m_file, SIGNAL(activated(int)), SLOT(newSession(int)));
m_toolbarSessionsCommands = new QPopupMenu(this);
connect(m_toolbarSessionsCommands, SIGNAL(activated(int)), SLOT(newSession(int)));
KAction *newsession = KStdAction::openNew(this , SLOT(newSessionSelect()));
newsession->plug(toolBar());
toolBar()->insertLineSeparator();
QPopupMenu* m_signals = new QPopupMenu(this);
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(this);
m_sessions->setCheckable(TRUE);
m_sessions->insertItem( i18n("Send Signal"), m_signals );
KAction *renameSession = new KAction(i18n("Rename session..."), 0, this,
SLOT(slotRenameSession()), this);
renameSession->plug(m_sessions);
m_sessions->insertSeparator();
m_schema = new QPopupMenu(this);
m_schema->setCheckable(TRUE);
connect(m_schema, SIGNAL(activated(int)), SLOT(schema_menu_activated(int)));
m_keytab = new QPopupMenu;
m_keytab->setCheckable(TRUE);
connect(m_keytab, SIGNAL(activated(int)), SLOT(keytab_menu_activated(int)));
m_codec = new QPopupMenu;
m_codec->setCheckable(TRUE);
m_codec->insertItem( i18n("&locale"), 1 );
m_codec->setItemChecked(1,TRUE);
m_options = new QPopupMenu(this);
// insert the rename schema here too, because they will not find it
// on shift right click
renameSession->plug(m_options);
m_options->insertSeparator();
// Menubar on/off
showMenubar = KStdAction::showMenubar(this, SLOT(slotToggleMenubar()));
showMenubar->plug(m_options);
// Toolbar on/off
showToolbar = KStdAction::showToolbar(this, SLOT(slotToggleToolbar()));
showToolbar->plug(m_options);
// Frame on/off
showFrame = new KToggleAction(i18n("Show &frame"), 0,
this, SLOT(slotToggleFrame()), this);
showFrame->plug(m_options);
// Scrollbar
selectScrollbar = new KSelectAction(i18n("Scrollbar"), 0, this,
SLOT(slotSelectScrollbar()), this);
QStringList scrollitems;
scrollitems << i18n("&Hide") << i18n("&Left") << i18n("Right");
selectScrollbar->setItems(scrollitems);
selectScrollbar->plug(m_options);
// Fullscreen
m_options->insertSeparator();
m_options->insertItem( i18n("&Fullscreen"), 5);
m_options->setItemChecked(5,b_fullscreen);
m_options->insertSeparator();
// Select size
selectSize = new KSelectAction(i18n("Size"), 0, this,
SLOT(slotSelectSize()), this);
QStringList sizeitems;
sizeitems << i18n("40x15 (&small)")
<< i18n("80x24 (&vt100)")
<< i18n("80x25 (&ibmpc)")
<< i18n("80x40 (&xterm)")
<< i18n("80x52 (ibmv&ga)");
selectSize->setItems(sizeitems);
selectSize->plug(m_options);
// Select font
selectFont = new KSelectAction(i18n("Fonts"), 0, this,
SLOT(slotSelectFont()), this);
QStringList it;
it << i18n("&Normal")
<< i18n("&Tiny")
<< i18n("&Small")
<< i18n("&Medium")
<< i18n("&Large")
<< i18n("&Huge")
<< ""
<< i18n("&Linux")
<< i18n("&Unicode")
<< ""
<< i18n("&Custom...");
selectFont->setItems(it);
selectFont->plug(m_options);
// Schema
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->insertSeparator();
m_options->insertItem( i18n("&Save Options"), 8);
connect(m_options, SIGNAL(activated(int)), SLOT(opt_menu_activated(int)));
// Help and about menu
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_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("Sessions"), m_sessions);
menubar->insertItem(i18n("Options"), m_options);
menubar->insertSeparator();
menubar->insertItem(i18n("Help"), m_help);
}
/**
This function calculates the size of the external widget
needed for the internal widget to be
*/
QSize Konsole::calcSize(int columns, int lines) {
QSize size = te->calcSize(columns, lines);
if (b_toolbarvis) {
if ((toolBar()->barPos()==KToolBar::Top) ||
(toolBar()->barPos()==KToolBar::Bottom)) {
int height = toolBar()->size().height();
// The height of the toolbar is 1 during startup.
if (height == 1)
height = n_toolbarheight;
size += QSize(0, height);
}
if ((toolBar()->barPos()==KToolBar::Left) ||
(toolBar()->barPos()==KToolBar::Right)) {
size += QSize(toolBar()->size().width(), 0);
}
}
if (b_menuvis) {
size += QSize(0,menuBar()->size().height());
}
return size;
}
/**
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 = calcSize(80,24);
notifySize(24,80); // set menu items (strange arg order !)
}
resize(defaultSize);
} else {
resize(calcSize(columns, lines));
notifySize(lines,columns); // set menu items (strange arg order !)
}
}
/* ------------------------------------------------------------------------- */
/* */
/* */
/* ------------------------------------------------------------------------- */
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)));
}
/* ------------------------------------------------------------------------- */
/* */
/* Configuration */
/* */
/* ------------------------------------------------------------------------- */
void Konsole::saveGlobalProperties(KConfig* config)
{
config->setGroup("global options");
config->writeEntry("working directory", QDir::currentDirPath());
}
void Konsole::readGlobalProperties(KConfig* config)
{
config->setGroup("global options");
QDir::setCurrent(config->readEntry("working directory", QDir::currentDirPath()));
}
void Konsole::saveProperties(KConfig* config)
{
n_toolbarheight = toolBar()->size().height();
config->setGroup("options");
// bad! will no allow us to support multi windows
config->writeEntry("menubar visible",b_menuvis);
config->writeEntry("toolbar visible", b_toolbarvis);
config->writeEntry("toolbar height", n_toolbarheight);
config->writeEntry("history",b_scroll);
config->writeEntry("has frame",b_framevis);
config->writeEntry("Fullscreen",b_fullscreen);
config->writeEntry("font",n_font);
config->writeEntry("defaultfont", defaultFont);
config->writeEntry("schema",s_schema);
config->writeEntry("scrollbar",n_scroll);
config->writeEntry("keytab",n_keytab);
if (args.count() > 0) config->writeEntry("konsolearguments", args);
config->writeEntry("class",name());
config->writeEntry("defaultheight", te->height());
// for "save options". Not used by SM.
config->writeEntry("defaultwidth", te->width());
// for "save options". Not used by SM.
//config->writeEntry("kmenubar", //FIXME:Float
// menubar->menuBarPos() == KMenuBar::Bottom ? "bottom" : "top");
// geometry (placement) done by KMainWindow
config->sync();
}
// Called by constructor (with config = KGlobal::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_toolbarvis = config->readBoolEntry("toolbar visible",TRUE);
n_toolbarheight = config->readNumEntry("toolbar height",32); // Hack on hack...
b_scroll = config->readBoolEntry("history",TRUE);
setHistory(b_scroll);
int n2_keytab = config->readNumEntry("keytab",0);
keytab_menu_activated(n2_keytab); // act. the keytab for this session
b_fullscreen = FALSE; // config->readBoolEntry("Fullscreen",FALSE);
n_font = QMIN(config->readUnsignedNumEntry("font",3),TOPFONT);
n_scroll = QMIN(config->readUnsignedNumEntry("scrollbar",TEWidget::SCRRIGHT),2);
selectScrollbar->setCurrentItem(n_scroll);
slotSelectScrollbar();
s_schema = config->readEntry("schema","");
// Global options ///////////////////////
b_framevis = config->readBoolEntry("has frame",TRUE);
showFrame->setChecked( b_framevis );
slotToggleFrame();
// Options that should be applied to all sessions /////////////
// (1) set menu items and Konsole members
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);
QPtrDictIterator<TESession> it( action2session ); // iterator for dict
TESession* s = it.current();
if (s)
{
s->setFontNo(n_font);
s->setSchemaNo(ColorSchema::find(s_schema)->numb);
s->setHistory(b_scroll);
}
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) );
showToolbar->setChecked(b_toolbarvis);
slotToggleToolbar();
showMenubar->setChecked(b_menuvis);
slotToggleMenubar();
}
/* ------------------------------------------------------------------------- */
/* */
/* */
/* ------------------------------------------------------------------------- */
void Konsole::pixmap_menu_activated(int item)
{
if (item <= 1) pmPath = "";
QPixmap pm(pmPath);
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::slotSelectScrollbar() {
n_scroll = selectScrollbar->currentItem();
te->setScrollbarLocation(n_scroll);
activateSession(); // maybe helps in bg
}
void Konsole::slotSelectFont() {
assert(se);
int item = selectFont->currentItem();
//kdDebug() << "slotSelectFont " << item << endl;
if (item == 8) // this is the default
{
KFontDialog::getFont(defaultFont, true);
item = 0;
}
setFont(item);
activateSession(); // activates the current
}
void Konsole::schema_menu_activated(int item)
{
assert(se);
//FIXME: save schema name
setSchema(item);
activateSession(); // activates the current
}
void Konsole::keytab_menu_activated(int item)
{
// assert(se);
//HERE; printf("keytab: %d\n",item);
if (se) // not active at the beginning
se->setKeymapNo(item);
m_keytab->setItemChecked(n_keytab,FALSE);
m_keytab->setItemChecked(item,TRUE);
n_keytab = item;
}
void Konsole::setFont(int fontno)
{
int lines = te->Lines();
int cols = te->Columns();
QFontMetrics fm(te->font());
int pointSize = fm.height();
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);
return;
}
QFontMetrics fm2(f);
//kdDebug(0) << "pointSizeOld=" << pointSize << " new=" << fm2.height() << endl;
if(fm2.height() > pointSize) {
//kdDebug(0) << "enlarging" << endl;
te->setFontMetrics(f);
setColLin(cols, lines);
te->setVTFont(f);
if (se) se->setFontNo(fontno);
} else {
te->setFontMetrics(f);
te->setVTFont(f);
setColLin(cols, lines);
if (se) se->setFontNo(fontno);
}
n_font = fontno;
}
void Konsole::slotToggleMenubar() {
b_menuvis = showMenubar->isChecked();
if (b_menuvis)
menubar->show();
else
menubar->hide();
if (!b_menuvis) {
setCaption(i18n("Use the right mouse button to bring back the menu"));
QTimer::singleShot(5000,this,SLOT(setHeader()));
}
}
void Konsole::slotToggleToolbar() {
b_toolbarvis = showToolbar->isChecked();
if (b_toolbarvis)
toolBar()->show();
else
toolBar()->hide();
}
void Konsole::slotToggleFrame() {
b_framevis = showFrame->isChecked();
te->setFrameStyle( b_framevis
? ( QFrame::WinPanel | QFrame::Sunken )
: QFrame::NoFrame );
}
void Konsole::setHistory(bool on) {
b_scroll = on;
m_options->setItemChecked(3,b_scroll);
if (se) se->setHistory( b_scroll );
}
void Konsole::opt_menu_activated(int item)
{
switch( item ) {
case 3: setHistory(!b_scroll);
break;
case 5: setFullScreen(!b_fullscreen);
break;
case 8: saveProperties(KGlobal::config());
break;
}
}
// --| color selection |-------------------------------------------------------
void Konsole::changeColumns(int columns)
{
setColLin(columns,te->Lines());
te->update();
}
void Konsole::slotSelectSize() {
int item = selectSize->currentItem();
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)
{
selectSize->blockSignals(true);
selectSize->setCurrentItem(-1);
if (columns==40&&lines==15)
selectSize->setCurrentItem(0);
if (columns==80&&lines==24)
selectSize->setCurrentItem(1);
if (columns==80&&lines==25)
selectSize->setCurrentItem(2);
if (columns==80&&lines==40)
selectSize->setCurrentItem(3);
if (columns==80&&lines==52)
selectSize->setCurrentItem(4);
selectSize->blockSignals(false);
if (n_render >= 3) pixmap_menu_activated(n_render);
}
void Konsole::setHeader()
{
setCaption(title);
}
void Konsole::changeTitle(int, const QString& s)
{
title = s; setHeader();
}
/*
Konsole::showFullScreen() differes from QWidget::showFullScreen() in that
we do not want to stay on top, since we want to be able to start X11 clients
from a full screen konsole.
*/
void Konsole::showFullScreen()
{
if ( !isTopLevel() )
return;
if ( topData()->fullscreen ) {
show();
raise();
return;
}
if ( topData()->normalGeometry.width() < 0 )
topData()->normalGeometry = QRect( pos(), size() );
reparent( 0, WType_TopLevel | WStyle_Customize | WStyle_NoBorderEx, // | WStyle_StaysOnTop,
QPoint(0,0) );
topData()->fullscreen = 1;
resize( qApp->desktop()->size() );
raise();
show();
#if defined(_WS_X11_)
extern void qt_wait_for_window_manager( QWidget* w ); // defined in qwidget_x11.cpp
qt_wait_for_window_manager( this );
#endif
setActiveWindow();
}
void Konsole::setFullScreen(bool on)
{
if (on == b_fullscreen) return;
if (on) showFullScreen(); else showNormal();
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::runSession(TESession* s)
{
KRadioAction *ra = session2action.find(s);
ra->setChecked(true);
activateSession();
// 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;
// create an action for the session
QString title = i18n("%1 No %2").arg(s->Title()).arg(session_no);
// char buffer[30];
// int acc = CTRL+SHIFT+Key_0+session_no; // Lars: keys stolen by kwin.
KRadioAction *ra = new KRadioAction(title,
"openterm",
0,
this,
SLOT(activateSession()),
this);
// buffer);
ra->setExclusiveGroup("sessions");
ra->setChecked(true);
// key accelerator
// accel->connectItem(accel->insertItem(acc), ra, SLOT(activate()));
action2session.insert(ra, s);
session2action.insert(s,ra);
sessions.append(s);
ra->plug(m_sessions);
ra->plug(toolBar());
}
/**
Activates a session (from the menu or by pressing a button)
*/
void Konsole::activateSession()
{
TESession* s = NULL;
// finds the session based on which button was activated
QPtrDictIterator<TESession> it( action2session ); // iterator for dict
while ( it.current() )
{
KRadioAction *ra = (KRadioAction*)it.currentKey();
if (ra->isChecked()) { s = it.current(); break; }
++it;
}
if (s!=NULL) activateSession(s);
}
void Konsole::activateSession(TESession *s)
{
if (se)
{ se->setConnect(FALSE);
QObject::disconnect( se->getEmulation(),SIGNAL(prevSession()), this,SLOT(prevSession()) );
QObject::disconnect( se->getEmulation(),SIGNAL(nextSession()), this,SLOT(nextSession()) );
}
se = s;
session2action.find(se)->setChecked(true);
QTimer::singleShot(1,this,SLOT(allowPrevNext())); // hack, hack, hack
if (s->schemaNo()!=curr_schema) {
// the current schema has changed
setSchema(s->schemaNo());
s->setConnect(TRUE); // does a bulkShow (setImage)
setFont(s->fontNo()); //FIXME: creates flicker?
} else {
// the schema was not changed
ColorSchema* schema = ColorSchema::find(s->schemaNo());
if (schema->usetransparency) {
rootxpm->repaint(true); // this is a must, otherwise you loose the bg.
}
s->setConnect(TRUE);
}
title = s->Title(); // take title from current session
setHeader();
te->currentSession = se;
keytab_menu_activated(n_keytab); // act. the keytab for this session
}
void Konsole::allowPrevNext()
{
QObject::connect( se->getEmulation(),SIGNAL(prevSession()), this,SLOT(prevSession()) );
QObject::connect( se->getEmulation(),SIGNAL(nextSession()), this,SLOT(nextSession()) );
}
void Konsole::newSession()
{
uint i=1;
int session=0;
while ( (session==0) && (i<=no2command.count()) )
// antlarr: Why is first session session number 1 instead of number 0 ?
{
KSimpleConfig* co = no2command.find(i);
if ( co && co->readEntry("Exec").isEmpty() ) session=i;
i++;
}
if (session==0) session=1;
newSession(session);
}
void Konsole::newSessionSelect()
{
// Take into account the position of the toolBar to determine where we put the popup
if((toolBar()->barPos() == KToolBar::Top) || (toolBar()->barPos() == KToolBar::Left)) {
m_file->popup(te->mapToGlobal(QPoint(0,0)));
} else if(toolBar()->barPos() == KToolBar::Right) {
m_file->popup(te->mapToGlobal(QPoint(te->width()-m_file->sizeHint().width(), 0)));
} else {
m_file->popup(te->mapToGlobal(QPoint(0,te->height()-m_file->sizeHint().height())));
}
}
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");
QString nam = co->readEntry("Name"); // not null
QCString emu = co->readEntry("Term").ascii();
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);
if (!cmd.isEmpty())
{
args.append("-c");
args.append(QFile::encodeName(cmd));
}
TESession* s = new TESession(this,te,shell,args,emu);
connect( s,SIGNAL(done(TESession*,int)),
this,SLOT(doneSession(TESession*,int)) );
connect( te, SIGNAL(configureRequest(TEWidget*, int, int, int)),
this, SLOT(configureRequest(TEWidget*,int,int,int)) );
s->setFontNo(fno);
s->setSchemaNo(schmno);
s->setTitle(txt);
s->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
KRadioAction *ra = session2action.find(s);
ra->unplug(m_sessions);
ra->unplug(toolBar());
session2action.remove(s);
action2session.remove(ra);
sessions.remove(s);
delete ra; // will the toolbar die?
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 );
QPtrDictIterator<KRadioAction> it( session2action);
if ( it.current() ) {
it.current()->setChecked(true);
activateSession();
} else
kapp->quit();
}
}
/*! Cycle to previous session (if any) */
void Konsole::prevSession()
{
sessions.find(se); sessions.prev();
if (!sessions.current()) sessions.last();
if (sessions.current()) activateSession(sessions.current());
}
/*! Cycle to next session (if any) */
void Konsole::nextSession()
{
sessions.find(se); sessions.next();
if (!sessions.current()) sessions.first();
if (sessions.current()) activateSession(sessions.current());
}
// --| Session support |-------------------------------------------------------
void Konsole::addSessionCommand(const QString &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() || nam.isEmpty() ||
typ != "KonsoleApplication")
{
delete co; return; // ignore
}
m_file->insertItem(txt, ++cmd_serial);
m_toolbarSessionsCommands->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 QString & 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) {
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);
}
void Konsole::slotRenameSession() {
kdDebug() << "slotRenameSession\n";
KRadioAction *ra = session2action.find(se);
QString name = ra->text();
KLineEditDlg dlg(i18n("Session name"),name, this);
if (dlg.exec()) {
ra->setText(dlg.text());
ra->setIcon("openterm"); // I don't know why it is needed here
toolBar()->updateRects();
}
}
#include "konsole.moc"