summaryrefslogtreecommitdiff
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/apps/opie-console/emulation_layer.cpp~373
-rw-r--r--noncore/apps/opie-console/widget.cpp~1291
2 files changed, 0 insertions, 1664 deletions
diff --git a/noncore/apps/opie-console/emulation_layer.cpp~ b/noncore/apps/opie-console/emulation_layer.cpp~
deleted file mode 100644
index e65fd4b..0000000
--- a/noncore/apps/opie-console/emulation_layer.cpp~
+++ b/dev/null
@@ -1,373 +0,0 @@
1/* -------------------------------------------------------------------------- */
2/* */
3/* [TEmulation.cpp] Terminal Emulation Decoder */
4/* */
5/* -------------------------------------------------------------------------- */
6/* */
7/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */
8/* */
9/* This file is part of Konsole - an X terminal for KDE */
10/* */
11/* -------------------------------------------------------------------------- */
12 /* */
13/* Ported Konsole to Qt/Embedded */
14 /* */
15/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */
16 /* */
17/* -------------------------------------------------------------------------- */
18/* ------------------------------------------------------------------------- */
19 /* */
20/* Modified to suit opie-console */
21 /* */
22/* Copyright (C) 2002 by opie developers <opie@handhelds.org> */
23 /* */
24/* ------------------------------------------------------------------------- */
25
26/*! \class TEmulation
27
28 \brief Mediator between TEWidget and TEScreen.
29
30 This class is responsible to scan the escapes sequences of the terminal
31 emulation and to map it to their corresponding semantic complements.
32 Thus this module knows mainly about decoding escapes sequences and
33 is a stateless device w.r.t. the semantics.
34
35 It is also responsible to refresh the TEWidget by certain rules.
36
37 \sa TEWidget \sa TEScreen
38
39 \par A note on refreshing
40
41 Although the modifications to the current screen image could immediately
42 be propagated via `TEWidget' to the graphical surface, we have chosen
43 another way here.
44
45 The reason for doing so is twofold.
46
47 First, experiments show that directly displaying the operation results
48 in slowing down the overall performance of emulations. Displaying
49 individual characters using X11 creates a lot of overhead.
50
51 Second, by using the following refreshing method, the screen operations
52 can be completely separated from the displaying. This greatly simplifies
53 the programmer's task of coding and maintaining the screen operations,
54 since one need not worry about differential modifications on the
55 display affecting the operation of concern.
56
57 We use a refreshing algorithm here that has been adoped from rxvt/kvt.
58
59 By this, refreshing is driven by a timer, which is (re)started whenever
60 a new bunch of data to be interpreted by the emulation arives at `onRcvBlock'.
61 As soon as no more data arrive for `BULK_TIMEOUT' milliseconds, we trigger
62 refresh. This rule suits both bulk display operation as done by curses as
63 well as individual characters typed.
64 (BULK_TIMEOUT < 1000 / max characters received from keyboard per second).
65
66 Additionally, we trigger refreshing by newlines comming in to make visual
67 snapshots of lists as produced by `cat', `ls' and likely programs, thereby
68 producing the illusion of a permanent and immediate display operation.
69
70 As a sort of catch-all needed for cases where none of the above
71 conditions catch, the screen refresh is also triggered by a count
72 of incoming bulks (`bulk_incnt').
73*/
74
75/* FIXME
76 - evtl. the bulk operations could be made more transparent.
77*/
78
79#include "emulation_layer.h"
80#include "widget.h"
81#include "TEScreen.h"
82#include <stdio.h>
83#include <stdlib.h>
84#include <unistd.h>
85#include <qkeycode.h>
86
87
88/* ------------------------------------------------------------------------- */
89/* */
90/* EmulationLayer */
91/* */
92/* ------------------------------------------------------------------------- */
93
94#define CNTL(c) ((c)-'@')
95
96/*!
97*/
98
99EmulationLayer::EmulationLayer(TEWidget* gui)
100: decoder((QTextDecoder*)NULL)
101{
102 this->gui = gui;
103
104 screen[0] = new TEScreen(gui->Lines(),gui->Columns());
105 screen[1] = new TEScreen(gui->Lines(),gui->Columns());
106 scr = screen[0];
107
108 bulk_nlcnt = 0; // reset bulk newline counter
109 bulk_incnt = 0; // reset bulk counter
110 connected = FALSE;
111
112 QObject::connect(&bulk_timer, SIGNAL(timeout()), this, SLOT(showBulk()) );
113 QObject::connect(gui,SIGNAL(changedImageSizeSignal(int,int)),
114 this,SLOT(onImageSizeChange(int,int)));
115 QObject::connect(gui,SIGNAL(changedHistoryCursor(int)),
116 this,SLOT(onHistoryCursorChange(int)));
117 QObject::connect(gui,SIGNAL(keyPressedSignal(QKeyEvent*)),
118 this,SLOT(onKeyPress(QKeyEvent*)));
119 QObject::connect(gui,SIGNAL(beginSelectionSignal(const int,const int)),
120 this,SLOT(onSelectionBegin(const int,const int)) );
121 QObject::connect(gui,SIGNAL(extendSelectionSignal(const int,const int)),
122 this,SLOT(onSelectionExtend(const int,const int)) );
123 QObject::connect(gui,SIGNAL(endSelectionSignal(const BOOL)),
124 this,SLOT(setSelection(const BOOL)) );
125 QObject::connect(gui,SIGNAL(clearSelectionSignal()),
126 this,SLOT(clearSelection()) );
127}
128
129/*!
130*/
131
132EmulationLayer::~EmulationLayer()
133{
134 delete screen[0];
135 delete screen[1];
136 bulk_timer.stop();
137}
138
139/*! change between primary and alternate screen
140*/
141
142void EmulationLayer::setScreen(int n)
143{
144 scr = screen[n&1];
145}
146
147void EmulationLayer::setHistory(bool on)
148{
149 screen[0]->setScroll(on);
150 if (!connected) return;
151 showBulk();
152}
153
154bool EmulationLayer::history()
155{
156 return screen[0]->hasScroll();
157}
158
159void EmulationLayer::setCodec(int c)
160{
161 //FIXME: check whether we have to free codec
162 codec = c ? QTextCodec::codecForName("utf8")
163 : QTextCodec::codecForLocale();
164 if (decoder) delete decoder;
165 decoder = codec->makeDecoder();
166}
167
168void EmulationLayer::setKeytrans(int no)
169{
170 keytrans = KeyTrans::find(no);
171}
172
173void EmulationLayer::setKeytrans(const char * no)
174{
175 keytrans = KeyTrans::find(no);
176}
177
178// Interpreting Codes ---------------------------------------------------------
179
180/*
181 This section deals with decoding the incoming character stream.
182 Decoding means here, that the stream is first seperated into `tokens'
183 which are then mapped to a `meaning' provided as operations by the
184 `Screen' class.
185*/
186
187/*!
188*/
189
190void EmulationLayer::onRcvChar(int c)
191// process application unicode input to terminal
192// this is a trivial scanner
193{
194 c &= 0xff;
195 switch (c)
196 {
197 case '\b' : scr->BackSpace(); break;
198 case '\t' : scr->Tabulate(); break;
199 case '\n' : scr->NewLine(); break;
200 case '\r' : scr->Return(); break;
201 case 0x07 : gui->Bell(); break;
202 default : scr->ShowCharacter(c); break;
203 };
204}
205
206/* ------------------------------------------------------------------------- */
207/* */
208/* Keyboard Handling */
209/* */
210/* ------------------------------------------------------------------------- */
211
212/*!
213*/
214
215void EmulationLayer::onKeyPress( QKeyEvent* ev )
216{
217 if (!connected) return; // someone else gets the keys
218 if (scr->getHistCursor() != scr->getHistLines());
219 scr->setHistCursor(scr->getHistLines());
220 if (!ev->text().isEmpty())
221 { // A block of text
222 // Note that the text is proper unicode.
223 // We should do a conversion here, but since this
224 // routine will never be used, we simply emit plain ascii.
225 sendString( ev->text().ascii() ); //,ev->text().length());
226 }
227 else if (ev->ascii()>0)
228 {
229 QByteArray c = QByteArray( 1 );
230 c.at( 0 ) = ev->ascii();
231 // ibot: qbytearray is emited not char*
232 emit sndBlock( (QByteArray) c );
233 }
234}
235
236// Unblocking, Byte to Unicode translation --------------------------------- --
237
238/*
239 We are doing code conversion from locale to unicode first.
240*/
241
242void EmulationLayer::onRcvBlock(const QByteArray &s )
243{
244 bulkStart();
245 bulk_incnt += 1;
246 for (int i = 0; i < s.size(); i++)
247 {
248 //TODO: ibot: maybe decoding qbytearray to unicode in io_layer?
249 QString result = decoder->toUnicode(&s[i],1);
250 int reslen = result.length();
251 for (int j = 0; j < reslen; j++)
252 onRcvChar(result[j].unicode());
253 if (s[i] == '\n') bulkNewline();
254 }
255 bulkEnd();
256}
257
258// Selection --------------------------------------------------------------- --
259
260void EmulationLayer::onSelectionBegin(const int x, const int y) {
261 if (!connected) return;
262 scr->setSelBeginXY(x,y);
263 showBulk();
264}
265
266void EmulationLayer::onSelectionExtend(const int x, const int y) {
267 if (!connected) return;
268 scr->setSelExtentXY(x,y);
269 showBulk();
270}
271
272void EmulationLayer::setSelection(const BOOL preserve_line_breaks) {
273 if (!connected) return;
274 QString t = scr->getSelText(preserve_line_breaks);
275 if (!t.isNull()) gui->setSelection(t);
276}
277
278void EmulationLayer::clearSelection() {
279 if (!connected) return;
280 scr->clearSelection();
281 showBulk();
282}
283
284// Refreshing -------------------------------------------------------------- --
285
286#define BULK_TIMEOUT 20
287
288/*!
289 called when \n comes in. Evtl. triggers showBulk at endBulk
290*/
291
292void EmulationLayer::bulkNewline()
293{
294 bulk_nlcnt += 1;
295 bulk_incnt = 0; // reset bulk counter since `nl' rule applies
296}
297
298/*!
299*/
300
301void EmulationLayer::showBulk()
302{
303 bulk_nlcnt = 0; // reset bulk newline counter
304 bulk_incnt = 0; // reset bulk counter
305 if (connected)
306 {
307 ca* image = scr->getCookedImage(); // get the image
308 gui->setImage(image,
309 scr->getLines(),
310 scr->getColumns()); // actual refresh
311 free(image);
312 //FIXME: check that we do not trigger other draw event here.
313 gui->setScroll(scr->getHistCursor(),scr->getHistLines());
314 }
315}
316
317void EmulationLayer::bulkStart()
318{
319 if (bulk_timer.isActive()) bulk_timer.stop();
320}
321
322void EmulationLayer::bulkEnd()
323{
324 if ( bulk_nlcnt > gui->Lines() || bulk_incnt > 20 )
325 showBulk(); // resets bulk_??cnt to 0, too.
326 else
327 bulk_timer.start(BULK_TIMEOUT,TRUE);
328}
329
330void EmulationLayer::setConnect(bool c)
331{
332 connected = c;
333 if ( connected)
334 {
335 onImageSizeChange(gui->Lines(), gui->Columns());
336 showBulk();
337 }
338 else
339 {
340 scr->clearSelection();
341 }
342}
343
344// ---------------------------------------------------------------------------
345
346/*! triggered by image size change of the TEWidget `gui'.
347
348 This event is simply propagated to the attached screens
349 and to the related serial line.
350*/
351
352void EmulationLayer::onImageSizeChange(int lines, int columns)
353{
354 if (!connected) return;
355 screen[0]->resizeImage(lines,columns);
356 screen[1]->resizeImage(lines,columns);
357 showBulk();
358 emit ImageSizeChanged(lines,columns); // propagate event to serial line
359}
360
361void EmulationLayer::onHistoryCursorChange(int cursor)
362{
363 if (!connected) return;
364 scr->setHistCursor(cursor);
365 showBulk();
366}
367
368void EmulationLayer::setColumns(int columns)
369{
370 //FIXME: this goes strange ways.
371 // Can we put this straight or explain it at least?
372 emit changeColumns(columns);
373}
diff --git a/noncore/apps/opie-console/widget.cpp~ b/noncore/apps/opie-console/widget.cpp~
deleted file mode 100644
index e403015..0000000
--- a/noncore/apps/opie-console/widget.cpp~
+++ b/dev/null
@@ -1,1291 +0,0 @@
1/* ------------------------------------------------------------------------ */
2/* */
3/* [TEWidget.C] Terminal Emulation Widget */
4/* */
5/* ------------------------------------------------------------------------ */
6/* */
7/* Copyright (c) 1997,1998 by Lars Doelle <lars.doelle@on-line.de> */
8/* */
9/* This file is part of Konsole - an X terminal for KDE */
10/* */
11/* ------------------------------------------------------------------------ */
12/* */
13/* Ported Konsole to Qt/Embedded */
14/* */
15/* Copyright (C) 2000 by John Ryland <jryland@trolltech.com> */
16/* */
17/* -------------------------------------------------------------------------- */
18
19/* ibot:
20 i changed
21 "currentSession->getEmulation()->sendString()" to
22 "currentSession->layer()->send()"
23 # this is not right! EmulationLayer should send it...
24 i had to create a QByteArray before...
25
26TODO:
27alter TEWidget to use only QByteArray, where applicable.
28*/
29
30
31
32/*! \class TEWidget
33
34 \brief Visible screen contents
35
36 This class is responsible to map the `image' of a terminal emulation to the
37 display. All the dependency of the emulation to a specific GUI or toolkit is
38 localized here. Further, this widget has no knowledge about being part of an
39 emulation, it simply work within the terminal emulation framework by exposing
40 size and key events and by being ordered to show a new image.
41
42 <ul>
43 <li> The internal image has the size of the widget (evtl. rounded up)
44 <li> The external image used in setImage can have any size.
45 <li> (internally) the external image is simply copied to the internal
46 when a setImage happens. During a resizeEvent no painting is done
47 a paintEvent is expected to follow anyway.
48 </ul>
49
50 \sa TEScreen \sa Emulation
51*/
52
53/* FIXME:
54 - 'image' may also be used uninitialized (it isn't in fact) in resizeEvent
55 - 'font_a' not used in mouse events
56 - add destructor
57*/
58
59/* TODO
60 - evtl. be sensitive to `paletteChange' while using default colors.
61 - set different 'rounding' styles? I.e. have a mode to show clipped chars?
62*/
63
64// #include "config.h"
65#include "widget.h"
66#include "session.h"
67#include <qpe/config.h>
68#include <qapplication.h>
69
70#include <qcursor.h>
71#include <qregexp.h>
72#include <qpainter.h>
73#include <qclipboard.h>
74#include <qstyle.h>
75#include <qfile.h>
76#include <qdragobject.h>
77
78#include <stdio.h>
79#include <stdlib.h>
80#include <unistd.h>
81#include <ctype.h>
82#include <sys/stat.h>
83#include <sys/types.h>
84#include <signal.h>
85
86#include <assert.h>
87
88// #include "widget.moc"
89//#include <kapp.h>
90//#include <kcursor.h>
91//#include <kurl.h>
92//#include <kdebug.h>
93//#include <klocale.h>
94
95#define HERE printf("%s(%d): %s\n",__FILE__,__LINE__,__FUNCTION__)
96#define HCNT(Name) // { static int cnt = 1; printf("%s(%d): %s %d\n",__FILE__,__LINE__,Name,cnt++); }
97
98#define loc(X,Y) ((Y)*columns+(X))
99
100//FIXME: the rim should normally be 1, 0 only when running in full screen mode.
101#define rimX 0 // left/right rim width
102#define rimY 0 // top/bottom rim high
103
104#define SCRWIDTH 16 // width of the scrollbar
105
106#define yMouseScroll 1
107// scroll increment used when dragging selection at top/bottom of window.
108
109/* ------------------------------------------------------------------------- */
110/* */
111/* Colors */
112/* */
113/* ------------------------------------------------------------------------- */
114
115//FIXME: the default color table is in session.C now.
116// We need a way to get rid of this one, here.
117static const ColorEntry base_color_table[TABLE_COLORS] =
118// The following are almost IBM standard color codes, with some slight
119// gamma correction for the dim colors to compensate for bright X screens.
120// It contains the 8 ansiterm/xterm colors in 2 intensities.
121{
122 // Fixme: could add faint colors here, also.
123 // normal
124 ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 1, 0 ), // Dfore, Dback
125 ColorEntry(QColor(0x00,0x00,0x00), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0x18), 0, 0 ), // Black, Red
126 ColorEntry(QColor(0x18,0xB2,0x18), 0, 0 ), ColorEntry( QColor(0xB2,0x68,0x18), 0, 0 ), // Green, Yellow
127 ColorEntry(QColor(0x18,0x18,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ), // Blue, Magenta
128 ColorEntry(QColor(0x18,0xB2,0xB2), 0, 0 ), ColorEntry( QColor(0xB2,0xB2,0xB2), 0, 0 ), // Cyan, White
129 // intensiv
130 ColorEntry(QColor(0x00,0x00,0x00), 0, 1 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 1, 0 ),
131 ColorEntry(QColor(0x68,0x68,0x68), 0, 0 ), ColorEntry( QColor(0xFF,0x54,0x54), 0, 0 ),
132 ColorEntry(QColor(0x54,0xFF,0x54), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0x54), 0, 0 ),
133 ColorEntry(QColor(0x54,0x54,0xFF), 0, 0 ), ColorEntry( QColor(0xB2,0x18,0xB2), 0, 0 ),
134 ColorEntry(QColor(0x54,0xFF,0xFF), 0, 0 ), ColorEntry( QColor(0xFF,0xFF,0xFF), 0, 0 )
135};
136
137/* Note that we use ANSI color order (bgr), while IBMPC color order is (rgb)
138
139 Code 0 1 2 3 4 5 6 7
140 ----------- ------- ------- ------- ------- ------- ------- ------- -------
141 ANSI (bgr) Black Red Green Yellow Blue Magenta Cyan White
142 IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White
143*/
144
145QColor TEWidget::getDefaultBackColor()
146{
147 return color_table[DEFAULT_BACK_COLOR].color;
148}
149
150const ColorEntry* TEWidget::getColorTable() const
151{
152 return color_table;
153}
154
155const ColorEntry* TEWidget::getdefaultColorTable() const
156{
157 return base_color_table;
158}
159
160
161const QPixmap *TEWidget::backgroundPixmap()
162{
163 static QPixmap *bg = new QPixmap("~/qpim/main/pics/faded_bg.xpm");
164 const QPixmap *pm = bg;
165 return pm;
166}
167
168void TEWidget::setColorTable(const ColorEntry table[])
169{
170 for (int i = 0; i < TABLE_COLORS; i++) color_table[i] = table[i];
171
172 const QPixmap* pm = backgroundPixmap();
173 if (!pm) setBackgroundColor(color_table[DEFAULT_BACK_COLOR].color);
174 update();
175}
176
177//FIXME: add backgroundPixmapChanged.
178
179/* ------------------------------------------------------------------------- */
180/* */
181/* Font */
182/* */
183/* ------------------------------------------------------------------------- */
184
185/*
186 The VT100 has 32 special graphical characters. The usual vt100 extended
187 xterm fonts have these at 0x00..0x1f.
188
189 QT's iso mapping leaves 0x00..0x7f without any changes. But the graphicals
190 come in here as proper unicode characters.
191
192 We treat non-iso10646 fonts as VT100 extended and do the requiered mapping
193 from unicode to 0x00..0x1f. The remaining translation is then left to the
194 QCodec.
195*/
196
197// assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i.
198
199unsigned short vt100_graphics[32] =
200{ // 0/8 1/9 2/10 3/11 4/12 5/13 6/14 7/15
201 0x0020, 0x25C6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0,
202 0x00b1, 0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c,
203 0xF800, 0xF801, 0x2500, 0xF803, 0xF804, 0x251c, 0x2524, 0x2534,
204 0x252c, 0x2502, 0x2264, 0x2265, 0x03C0, 0x2260, 0x00A3, 0x00b7
205};
206
207static QChar vt100extended(QChar c)
208{
209 switch (c.unicode())
210 {
211 case 0x25c6 : return 1;
212 case 0x2592 : return 2;
213 case 0x2409 : return 3;
214 case 0x240c : return 4;
215 case 0x240d : return 5;
216 case 0x240a : return 6;
217 case 0x00b0 : return 7;
218 case 0x00b1 : return 8;
219 case 0x2424 : return 9;
220 case 0x240b : return 10;
221 case 0x2518 : return 11;
222 case 0x2510 : return 12;
223 case 0x250c : return 13;
224 case 0x2514 : return 14;
225 case 0x253c : return 15;
226 case 0xf800 : return 16;
227 case 0xf801 : return 17;
228 case 0x2500 : return 18;
229 case 0xf803 : return 19;
230 case 0xf804 : return 20;
231 case 0x251c : return 21;
232 case 0x2524 : return 22;
233 case 0x2534 : return 23;
234 case 0x252c : return 24;
235 case 0x2502 : return 25;
236 case 0x2264 : return 26;
237 case 0x2265 : return 27;
238 case 0x03c0 : return 28;
239 case 0x2260 : return 29;
240 case 0x00a3 : return 30;
241 case 0x00b7 : return 31;
242 }
243 return c;
244}
245
246static QChar identicalMap(QChar c)
247{
248 return c;
249}
250
251void TEWidget::fontChange(const QFont &)
252{
253 QFontMetrics fm(font());
254 font_h = fm.height();
255 font_w = fm.maxWidth();
256 font_a = fm.ascent();
257//printf("font_h: %d\n",font_h);
258//printf("font_w: %d\n",font_w);
259//printf("font_a: %d\n",font_a);
260//printf("charset: %s\n",QFont::encodingName(font().charSet()).ascii());
261//printf("rawname: %s\n",font().rawName().ascii());
262 fontMap =
263#if QT_VERSION < 300
264 strcmp(QFont::encodingName(font().charSet()).ascii(),"iso10646")
265 ? vt100extended
266 :
267#endif
268 identicalMap;
269 propagateSize();
270 update();
271}
272
273void TEWidget::setVTFont(const QFont& f)
274{
275 QFrame::setFont(f);
276}
277
278QFont TEWidget::getVTFont() {
279 return font();
280}
281
282void TEWidget::setFont(const QFont &)
283{
284 // ignore font change request if not coming from konsole itself
285}
286
287/* ------------------------------------------------------------------------- */
288/* */
289/* Constructor / Destructor */
290/* */
291/* ------------------------------------------------------------------------- */
292
293TEWidget::TEWidget(QWidget *parent, const char *name) : QFrame(parent,name)
294{
295#ifndef QT_NO_CLIPBOARD
296 cb = QApplication::clipboard();
297 QObject::connect( (QObject*)cb, SIGNAL(dataChanged()),
298 this, SLOT(onClearSelection()) );
299#endif
300
301 scrollbar = new QScrollBar(this);
302 scrollbar->setCursor( arrowCursor );
303 connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int)));
304
305 Config cfg("Konsole");
306 cfg.setGroup("ScrollBar");
307 switch( cfg.readNumEntry("Position",2)){
308 case 0:
309 scrollLoc = SCRNONE;
310 break;
311 case 1:
312 scrollLoc = SCRLEFT;
313 break;
314 case 2:
315 scrollLoc = SCRRIGHT;
316 break;
317 };
318
319 blinkT = new QTimer(this);
320 connect(blinkT, SIGNAL(timeout()), this, SLOT(blinkEvent()));
321 // blinking = FALSE;
322 blinking = TRUE;
323
324 resizing = FALSE;
325 actSel = 0;
326 image = 0;
327 lines = 1;
328 columns = 1;
329 font_w = 1;
330 font_h = 1;
331 font_a = 1;
332 word_selection_mode = FALSE;
333
334 setMouseMarks(TRUE);
335 setVTFont( QFont("fixed") );
336 setColorTable(base_color_table); // init color table
337
338 qApp->installEventFilter( this ); //FIXME: see below
339// KCursor::setAutoHideCursor( this, true );
340
341 // Init DnD ////////////////////////////////////////////////////////////////
342 currentSession = NULL;
343// setAcceptDrops(true); // attempt
344// m_drop = new QPopupMenu(this);
345// m_drop->insertItem( QString("Paste"), 0);
346// m_drop->insertItem( QString("cd"), 1);
347// connect(m_drop, SIGNAL(activated(int)), SLOT(drop_menu_activated(int)));
348
349 // we need focus so that the auto-hide cursor feature works
350 setFocus();
351 setFocusPolicy( WheelFocus );
352}
353
354//FIXME: make proper destructor
355// Here's a start (David)
356TEWidget::~TEWidget()
357{
358 qApp->removeEventFilter( this );
359 if (image) free(image);
360}
361
362/* ------------------------------------------------------------------------- */
363/* */
364/* Display Operations */
365/* */
366/* ------------------------------------------------------------------------- */
367
368/*!
369 attributed string draw primitive
370*/
371
372void TEWidget::drawAttrStr(QPainter &paint, QRect rect,
373 QString& str, ca attr, BOOL pm, BOOL clear)
374{
375 if (pm && color_table[attr.b].transparent)
376 {
377 paint.setBackgroundMode( TransparentMode );
378 if (clear) erase(rect);
379 }
380 else
381 {
382 if (blinking)
383 paint.fillRect(rect, color_table[attr.b].color);
384 else
385 {
386 paint.setBackgroundMode( OpaqueMode );
387 paint.setBackgroundColor( color_table[attr.b].color );
388 }
389 }
390
391 if (color_table[attr.f].bold)
392 paint.setPen(QColor( 0x8F, 0x00, 0x00 ));
393 else
394 paint.setPen(color_table[attr.f].color);
395
396 paint.drawText(rect.x(),rect.y()+font_a, str);
397
398 if (attr.r & RE_UNDERLINE)
399 paint.drawLine(rect.left(), rect.y()+font_a+1, rect.right(),rect.y()+font_a+1 );
400}
401
402/*!
403 The image can only be set completely.
404
405 The size of the new image may or may not match the size of the widget.
406*/
407
408void TEWidget::setImage(const ca* const newimg, int lines, int columns)
409{ int y,x,len;
410 const QPixmap* pm = backgroundPixmap();
411 QPainter paint;
412 setUpdatesEnabled(FALSE);
413 paint.begin( this );
414HCNT("setImage");
415
416 QPoint tL = contentsRect().topLeft();
417 int tLx = tL.x();
418 int tLy = tL.y();
419 hasBlinker = FALSE;
420
421 int cf = -1; // undefined
422 int cb = -1; // undefined
423 int cr = -1; // undefined
424
425 int lins = QMIN(this->lines, QMAX(0,lines ));
426 int cols = QMIN(this->columns,QMAX(0,columns));
427 QChar *disstrU = new QChar[cols];
428
429//{ static int cnt = 0; printf("setImage %d\n",cnt++); }
430 for (y = 0; y < lins; y++)
431 {
432 const ca* lcl = &image[y*this->columns];
433 const ca* const ext = &newimg[y*columns];
434 if (!resizing) // not while resizing, we're expecting a paintEvent
435 for (x = 0; x < cols; x++)
436 {
437 hasBlinker |= (ext[x].r & RE_BLINK);
438 if (ext[x] != lcl[x])
439 {
440 cr = ext[x].r;
441 cb = ext[x].b;
442 if (ext[x].f != cf) cf = ext[x].f;
443 int lln = cols - x;
444 disstrU[0] = fontMap(ext[x+0].c);
445 for (len = 1; len < lln; len++)
446 {
447 if (ext[x+len].f != cf || ext[x+len].b != cb || ext[x+len].r != cr ||
448 ext[x+len] == lcl[x+len] )
449 break;
450 disstrU[len] = fontMap(ext[x+len].c);
451 }
452 QString unistr(disstrU,len);
453 drawAttrStr(paint,
454 QRect(blX+tLx+font_w*x,bY+tLy+font_h*y,font_w*len,font_h),
455 unistr, ext[x], pm != NULL, true);
456 x += len - 1;
457 }
458 }
459 // finally, make `image' become `newimg'.
460 memcpy((void*)lcl,(const void*)ext,cols*sizeof(ca));
461 }
462 drawFrame( &paint );
463 paint.end();
464 setUpdatesEnabled(TRUE);
465 if ( hasBlinker && !blinkT->isActive()) blinkT->start(1000); // 1000 ms
466 if (!hasBlinker && blinkT->isActive()) { blinkT->stop(); blinking = FALSE; }
467 delete [] disstrU;
468}
469
470// paint Event ////////////////////////////////////////////////////
471
472/*!
473 The difference of this routine vs. the `setImage' is,
474 that the drawing does not include a difference analysis
475 between the old and the new image. Instead, the internal
476 image is used and the painting bound by the PaintEvent box.
477*/
478
479void TEWidget::paintEvent( QPaintEvent* pe )
480{
481
482//{ static int cnt = 0; printf("paint %d\n",cnt++); }
483 const QPixmap* pm = backgroundPixmap();
484 QPainter paint;
485 setUpdatesEnabled(FALSE);
486 paint.begin( this );
487 paint.setBackgroundMode( TransparentMode );
488HCNT("paintEvent");
489
490 // Note that the actual widget size can be slightly larger
491 // that the image (the size is truncated towards the smaller
492 // number of characters in `resizeEvent'. The paint rectangle
493 // can thus be larger than the image, but less then the size
494 // of one character.
495
496 QRect rect = pe->rect().intersect(contentsRect());
497
498 QPoint tL = contentsRect().topLeft();
499 int tLx = tL.x();
500 int tLy = tL.y();
501
502 int lux = QMIN(columns-1, QMAX(0,(rect.left() - tLx - blX ) / font_w));
503 int luy = QMIN(lines-1, QMAX(0,(rect.top() - tLy - bY ) / font_h));
504 int rlx = QMIN(columns-1, QMAX(0,(rect.right() - tLx - blX ) / font_w));
505 int rly = QMIN(lines-1, QMAX(0,(rect.bottom() - tLy - bY ) / font_h));
506
507 /*
508 printf("paintEvent: %d..%d, %d..%d (%d..%d, %d..%d)\n",lux,rlx,luy,rly,
509 rect.left(), rect.right(), rect.top(), rect.bottom());
510 */
511
512 // if (pm != NULL && color_table[image->b].transparent)
513 // erase(rect);
514 // BL: I have no idea why we need this, and it breaks the refresh.
515
516 QChar *disstrU = new QChar[columns];
517 for (int y = luy; y <= rly; y++)
518 for (int x = lux; x <= rlx; x++)
519 {
520 int len = 1;
521 disstrU[0] = fontMap(image[loc(x,y)].c);
522 int cf = image[loc(x,y)].f;
523 int cb = image[loc(x,y)].b;
524 int cr = image[loc(x,y)].r;
525 while (x+len <= rlx &&
526 image[loc(x+len,y)].f == cf &&
527 image[loc(x+len,y)].b == cb &&
528 image[loc(x+len,y)].r == cr )
529 {
530 disstrU[len] = fontMap(image[loc(x+len,y)].c);
531 len += 1;
532 }
533 QString unistr(disstrU,len);
534 drawAttrStr(paint,
535 QRect(blX+tLx+font_w*x,bY+tLy+font_h*y,font_w*len,font_h),
536 unistr, image[loc(x,y)], pm != NULL, false);
537 x += len - 1;
538 }
539 delete [] disstrU;
540 drawFrame( &paint );
541 paint.end();
542 setUpdatesEnabled(TRUE);
543}
544
545void TEWidget::blinkEvent()
546{
547 blinking = !blinking;
548 repaint(FALSE);
549}
550
551/* ------------------------------------------------------------------------- */
552/* */
553/* Resizing */
554/* */
555/* ------------------------------------------------------------------------- */
556
557void TEWidget::resizeEvent(QResizeEvent* ev)
558{
559// printf("resize: %d,%d\n",ev->size().width(),ev->size().height());
560 //printf("approx: %d,%d\n",ev->size().width()/font_w,ev->size().height()/font_h);
561 //printf("leaves: %d,%d\n",ev->size().width()%font_w,ev->size().height()%font_h);
562 //printf("curren: %d,%d\n",width(),height());
563HCNT("resizeEvent");
564
565 // see comment in `paintEvent' concerning the rounding.
566 //FIXME: could make a routine here; check width(),height()
567 assert(ev->size().width() == width());
568 assert(ev->size().height() == height());
569
570 propagateSize();
571}
572
573void TEWidget::propagateSize()
574{
575 ca* oldimg = image;
576 int oldlin = lines;
577 int oldcol = columns;
578 makeImage();
579 // we copy the old image to reduce flicker
580 int lins = QMIN(oldlin,lines);
581 int cols = QMIN(oldcol,columns);
582 if (oldimg)
583 {
584 for (int lin = 0; lin < lins; lin++)
585 memcpy((void*)&image[columns*lin],
586 (void*)&oldimg[oldcol*lin],cols*sizeof(ca));
587 free(oldimg); //FIXME: try new,delete
588 }
589 else
590 clearImage();
591
592 //NOTE: control flows from the back through the chest right into the eye.
593 // `emu' will call back via `setImage'.
594
595 resizing = TRUE;
596 emit changedImageSizeSignal(lines, columns); // expose resizeEvent
597 resizing = FALSE;
598}
599
600/* ------------------------------------------------------------------------- */
601/* */
602/* Scrollbar */
603/* */
604/* ------------------------------------------------------------------------- */
605
606void TEWidget::scrollChanged(int)
607{
608 emit changedHistoryCursor(scrollbar->value()); //expose
609}
610
611void TEWidget::setScroll(int cursor, int slines)
612{
613 disconnect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int)));
614 scrollbar->setRange(0,slines);
615 scrollbar->setSteps(1,lines);
616 scrollbar->setValue(cursor);
617 connect(scrollbar, SIGNAL(valueChanged(int)), this, SLOT(scrollChanged(int)));
618}
619
620void TEWidget::setScrollbarLocation(int loc)
621{
622 if (scrollLoc == loc) return; // quickly
623 scrollLoc = loc;
624 propagateSize();
625 update();
626}
627
628/* ------------------------------------------------------------------------- */
629/* */
630/* Mouse */
631/* */
632/* ------------------------------------------------------------------------- */
633
634/*!
635 Three different operations can be performed using the mouse, and the
636 routines in this section serve all of them:
637
638 1) The press/release events are exposed to the application
639 2) Marking (press and move left button) and Pasting (press middle button)
640 3) The right mouse button is used from the configuration menu
641
642 NOTE: During the marking process we attempt to keep the cursor within
643 the bounds of the text as being displayed by setting the mouse position
644 whenever the mouse has left the text area.
645
646 Two reasons to do so:
647 1) QT does not allow the `grabMouse' to confine-to the TEWidget.
648 Thus a `XGrapPointer' would have to be used instead.
649 2) Even if so, this would not help too much, since the text area
650 of the TEWidget is normally not identical with it's bounds.
651
652 The disadvantage of the current handling is, that the mouse can visibly
653 leave the bounds of the widget and is then moved back. Because of the
654 current construction, and the reasons mentioned above, we cannot do better
655 without changing the overall construction.
656*/
657
658/*!
659*/
660
661void TEWidget::mousePressEvent(QMouseEvent* ev)
662{
663//printf("press [%d,%d] %d\n",ev->x()/font_w,ev->y()/font_h,ev->button());
664 if ( !contentsRect().contains(ev->pos()) ) return;
665 QPoint tL = contentsRect().topLeft();
666 int tLx = tL.x();
667 int tLy = tL.y();
668
669 word_selection_mode = FALSE;
670
671//printf("press top left [%d,%d] by=%d\n",tLx,tLy, bY);
672 if ( ev->button() == LeftButton)
673 {
674 QPoint pos = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h);
675
676 if ( ev->state() & ControlButton ) preserve_line_breaks = FALSE ;
677
678 if (mouse_marks || (ev->state() & ShiftButton))
679 {
680 emit clearSelectionSignal();
681 iPntSel = pntSel = pos;
682 actSel = 1; // left mouse button pressed but nothing selected yet.
683 grabMouse( /*crossCursor*/ ); // handle with care!
684 }
685 else
686 {
687 emit mouseSignal( 0, pos.x() + 1, pos.y() + 1 ); // left button
688 }
689 }
690 if ( ev->button() == MidButton )
691 {
692 emitSelection();
693 }
694 if ( ev->button() == RightButton ) // Configure
695 {
696 emit configureRequest( this, ev->state()&(ShiftButton|ControlButton), ev->x(), ev->y() );
697 }
698}
699
700void TEWidget::mouseMoveEvent(QMouseEvent* ev)
701{
702 // for auto-hiding the cursor, we need mouseTracking
703 if (ev->state() == NoButton ) return;
704
705 if (actSel == 0) return;
706
707 // don't extend selection while pasting
708 if (ev->state() & MidButton) return;
709
710 //if ( !contentsRect().contains(ev->pos()) ) return;
711 QPoint tL = contentsRect().topLeft();
712 int tLx = tL.x();
713 int tLy = tL.y();
714 int scroll = scrollbar->value();
715
716 // we're in the process of moving the mouse with the left button pressed
717 // the mouse cursor will kept catched within the bounds of the text in
718 // this widget.
719
720 // Adjust position within text area bounds. See FIXME above.
721 QPoint pos = ev->pos();
722 if ( pos.x() < tLx+blX ) pos.setX( tLx+blX );
723 if ( pos.x() > tLx+blX+columns*font_w-1 ) pos.setX( tLx+blX+columns*font_w );
724 if ( pos.y() < tLy+bY ) pos.setY( tLy+bY );
725 if ( pos.y() > tLy+bY+lines*font_h-1 ) pos.setY( tLy+bY+lines*font_h-1 );
726 // check if we produce a mouse move event by this
727 if ( pos != ev->pos() ) cursor().setPos(mapToGlobal(pos));
728
729 if ( pos.y() == tLy+bY+lines*font_h-1 )
730 {
731 scrollbar->setValue(scrollbar->value()+yMouseScroll); // scrollforward
732 }
733 if ( pos.y() == tLy+bY )
734 {
735 scrollbar->setValue(scrollbar->value()-yMouseScroll); // scrollback
736 }
737
738 QPoint here = QPoint((pos.x()-tLx-blX)/font_w,(pos.y()-tLy-bY)/font_h);
739 QPoint ohere;
740 bool swapping = FALSE;
741
742 if ( word_selection_mode )
743 {
744 // Extend to word boundaries
745 int i;
746 int selClass;
747
748 bool left_not_right = ( here.y() < iPntSel.y() ||
749 here.y() == iPntSel.y() && here.x() < iPntSel.x() );
750 bool old_left_not_right = ( pntSel.y() < iPntSel.y() ||
751 pntSel.y() == iPntSel.y() && pntSel.x() < iPntSel.x() );
752 swapping = left_not_right != old_left_not_right;
753
754 // Find left (left_not_right ? from here : from start)
755 QPoint left = left_not_right ? here : iPntSel;
756 i = loc(left.x(),left.y());
757 selClass = charClass(image[i].c);
758 while ( left.x() > 0 && charClass(image[i-1].c) == selClass )
759 { i--; left.rx()--; }
760
761 // Find left (left_not_right ? from start : from here)
762 QPoint right = left_not_right ? iPntSel : here;
763 i = loc(right.x(),right.y());
764 selClass = charClass(image[i].c);
765 while ( right.x() < columns-1 && charClass(image[i+1].c) == selClass )
766 { i++; right.rx()++; }
767
768 // Pick which is start (ohere) and which is extension (here)
769 if ( left_not_right )
770 {
771 here = left; ohere = right;
772 }
773 else
774 {
775 here = right; ohere = left;
776 }
777 }
778
779 if (here == pntSel && scroll == scrollbar->value()) return; // not moved
780
781 if ( word_selection_mode ) {
782 if ( actSel < 2 || swapping ) {
783 emit beginSelectionSignal( ohere.x(), ohere.y() );
784 }
785 } else if ( actSel < 2 ) {
786 emit beginSelectionSignal( pntSel.x(), pntSel.y() );
787 }
788
789 actSel = 2; // within selection
790 pntSel = here;
791 emit extendSelectionSignal( here.x(), here.y() );
792}
793
794void TEWidget::mouseReleaseEvent(QMouseEvent* ev)
795{
796//printf("release [%d,%d] %d\n",ev->x()/font_w,ev->y()/font_h,ev->button());
797 if ( ev->button() == LeftButton)
798 {
799 if ( actSel > 1 ) emit endSelectionSignal(preserve_line_breaks);
800 preserve_line_breaks = TRUE;
801 actSel = 0;
802
803 //FIXME: emits a release event even if the mouse is
804 // outside the range. The procedure used in `mouseMoveEvent'
805 // applies here, too.
806
807 QPoint tL = contentsRect().topLeft();
808 int tLx = tL.x();
809 int tLy = tL.y();
810
811 if (!mouse_marks && !(ev->state() & ShiftButton))
812 emit mouseSignal( 3, // release
813 (ev->x()-tLx-blX)/font_w + 1,
814 (ev->y()-tLy-bY)/font_h + 1 );
815 releaseMouse();
816 }
817}
818
819void TEWidget::mouseDoubleClickEvent(QMouseEvent* ev)
820{
821 if ( ev->button() != LeftButton) return;
822
823 QPoint tL = contentsRect().topLeft();
824 int tLx = tL.x();
825 int tLy = tL.y();
826 QPoint pos = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h);
827
828 // pass on double click as two clicks.
829 if (!mouse_marks && !(ev->state() & ShiftButton))
830 {
831 emit mouseSignal( 0, pos.x()+1, pos.y()+1 ); // left button
832 emit mouseSignal( 3, pos.x()+1, pos.y()+1 ); // release
833 emit mouseSignal( 0, pos.x()+1, pos.y()+1 ); // left button
834 return;
835 }
836
837
838 emit clearSelectionSignal();
839 QPoint bgnSel = pos;
840 QPoint endSel = QPoint((ev->x()-tLx-blX)/font_w,(ev->y()-tLy-bY)/font_h);
841 int i = loc(bgnSel.x(),bgnSel.y());
842 iPntSel = bgnSel;
843
844 word_selection_mode = TRUE;
845
846 // find word boundaries...
847 int selClass = charClass(image[i].c);
848 {
849 // set the start...
850 int x = bgnSel.x();
851 while ( x > 0 && charClass(image[i-1].c) == selClass )
852 { i--; x--; }
853 bgnSel.setX(x);
854 emit beginSelectionSignal( bgnSel.x(), bgnSel.y() );
855
856 // set the end...
857 i = loc( endSel.x(), endSel.y() );
858 x = endSel.x();
859 while( x < columns-1 && charClass(image[i+1].c) == selClass )
860 { i++; x++ ; }
861 endSel.setX(x);
862 actSel = 2; // within selection
863 emit extendSelectionSignal( endSel.x(), endSel.y() );
864 emit endSelectionSignal(preserve_line_breaks);
865 preserve_line_breaks = TRUE;
866 }
867}
868
869void TEWidget::focusInEvent( QFocusEvent * )
870{
871
872 // do nothing, to prevent repainting
873}
874
875
876void TEWidget::focusOutEvent( QFocusEvent * )
877{
878 // do nothing, to prevent repainting
879}
880
881bool TEWidget::focusNextPrevChild( bool next )
882{
883 if (next)
884 return false; // This disables changing the active part in konqueror
885 // when pressing Tab
886 return QFrame::focusNextPrevChild( next );
887}
888
889
890int TEWidget::charClass(char ch) const
891{
892 // This might seem like overkill, but imagine if ch was a Unicode
893 // character (Qt 2.0 QChar) - it might then be sensible to separate
894 // the different language ranges, etc.
895
896 if ( isspace(ch) ) return ' ';
897
898 static const char *word_characters = ":@-./_~";
899 if ( isalnum(ch) || strchr(word_characters, ch) )
900 return 'a';
901
902 // Everything else is weird
903 return 1;
904}
905
906void TEWidget::setMouseMarks(bool on)
907{
908 mouse_marks = on;
909 setCursor( mouse_marks ? ibeamCursor : arrowCursor );
910}
911
912/* ------------------------------------------------------------------------- */
913/* */
914/* Clipboard */
915/* */
916/* ------------------------------------------------------------------------- */
917
918#undef KeyPress
919
920void TEWidget::emitSelection()
921// Paste Clipboard by simulating keypress events
922{
923#ifndef QT_NO_CLIPBOARD
924 QString text = QApplication::clipboard()->text();
925 if ( ! text.isNull() )
926 {
927 text.replace(QRegExp("\n"), "\r");
928 QKeyEvent e(QEvent::KeyPress, 0, -1, 0, text);
929 emit keyPressedSignal(&e); // expose as a big fat keypress event
930 emit clearSelectionSignal();
931 }
932#endif
933}
934
935void TEWidget::emitText(QString text)
936{
937 QKeyEvent e(QEvent::KeyPress, 0, -1, 0, text);
938 emit keyPressedSignal(&e); // expose as a big fat keypress event
939}
940
941void TEWidget::pasteClipboard( )
942{
943 emitSelection();
944}
945
946void TEWidget::setSelection(const QString& t)
947{
948#ifndef QT_NO_CLIPBOARD
949 // Disconnect signal while WE set the clipboard
950 QObject *cb = QApplication::clipboard();
951 QObject::disconnect( cb, SIGNAL(dataChanged()),
952 this, SLOT(onClearSelection()) );
953
954 QApplication::clipboard()->setText(t);
955
956 QObject::connect( cb, SIGNAL(dataChanged()),
957 this, SLOT(onClearSelection()) );
958#endif
959}
960
961void TEWidget::onClearSelection()
962{
963 emit clearSelectionSignal();
964}
965
966/* ------------------------------------------------------------------------- */
967/* */
968/* Keyboard */
969/* */
970/* ------------------------------------------------------------------------- */
971
972//FIXME: an `eventFilter' has been installed instead of a `keyPressEvent'
973// due to a bug in `QT' or the ignorance of the author to prevent
974// repaint events being emitted to the screen whenever one leaves
975// or reenters the screen to/from another application.
976//
977// Troll says one needs to change focusInEvent() and focusOutEvent(),
978// which would also let you have an in-focus cursor and an out-focus
979// cursor like xterm does.
980
981// for the auto-hide cursor feature, I added empty focusInEvent() and
982// focusOutEvent() so that update() isn't called.
983// For auto-hide, we need to get keypress-events, but we only get them when
984// we have focus.
985
986void TEWidget::doScroll(int lines)
987{
988 scrollbar->setValue(scrollbar->value()+lines);
989}
990
991bool TEWidget::eventFilter( QObject *obj, QEvent *e )
992{
993 if ( (e->type() == QEvent::Accel ||
994 e->type() == QEvent::AccelAvailable ) && qApp->focusWidget() == this ) {
995 static_cast<QKeyEvent *>( e )->ignore();
996 return true;
997 }
998 if ( obj != this /* when embedded */ && obj != parent() /* when standalone */ )
999 return FALSE; // not us
1000 if ( e->type() == QEvent::Wheel) {
1001 QApplication::sendEvent(scrollbar, e);
1002 }
1003
1004#ifdef FAKE_CTRL_AND_ALT
1005 static bool control = FALSE;
1006 static bool alt = FALSE;
1007// qDebug(" Has a keyboard with no CTRL and ALT keys, but we fake it:");
1008 bool dele=FALSE;
1009 if ( e->type() == QEvent::KeyPress || e->type() == QEvent::KeyRelease ) {
1010 QKeyEvent* ke = (QKeyEvent*)e;
1011 bool keydown = e->type() == QEvent::KeyPress || ke->isAutoRepeat();
1012 switch (ke->key()) {
1013 case Key_F9: // let this be "Control"
1014 control = keydown;
1015 e = new QKeyEvent(QEvent::KeyPress, Key_Control, 0, ke->state());
1016 dele=TRUE;
1017 break;
1018 case Key_F13: // let this be "Alt"
1019 alt = keydown;
1020 e = new QKeyEvent(QEvent::KeyPress, Key_Alt, 0, ke->state());
1021 dele=TRUE;
1022 break;
1023 default:
1024 if ( control ) {
1025 int a = toupper(ke->ascii())-64;
1026 if ( a >= 0 && a < ' ' ) {
1027 e = new QKeyEvent(e->type(), ke->key(),
1028 a, ke->state()|ControlButton, QChar(a,0));
1029 dele=TRUE;
1030 }
1031 }
1032 if ( alt ) {
1033 e = new QKeyEvent(e->type(), ke->key(),
1034 ke->ascii(), ke->state()|AltButton, ke->text());
1035 dele=TRUE;
1036 }
1037 }
1038 }
1039#endif
1040
1041 if ( e->type() == QEvent::KeyPress ) {
1042 QKeyEvent* ke = (QKeyEvent*)e;
1043 actSel=0; // Key stroke implies a screen update, so TEWidget won't
1044 // know where the current selection is.
1045
1046// qDebug("key pressed is 0x%x",ke->key());
1047
1048 if( ke->state() == ShiftButton && ke->key() == Key_Tab) { //lets hardcode this sucker
1049
1050// qDebug("key pressed 2 is 0x%x",ke->key());
1051 emitText("\\"); // expose
1052 } else
1053 emit keyPressedSignal(ke); // expose
1054 ke->accept();
1055#ifdef FAKE_CTRL_AND_ALT
1056 if ( dele ) delete e;
1057#endif
1058 return true; // stop the event
1059 }
1060 if ( e->type() == QEvent::Enter ) {
1061 QObject::disconnect( (QObject*)cb, SIGNAL(dataChanged()),
1062 this, SLOT(onClearSelection()) );
1063 }
1064 if ( e->type() == QEvent::Leave ) {
1065 QObject::connect( (QObject*)cb, SIGNAL(dataChanged()),
1066 this, SLOT(onClearSelection()) );
1067 }
1068 return QFrame::eventFilter( obj, e );
1069}
1070
1071/* ------------------------------------------------------------------------- */
1072/* */
1073/* Frame */
1074/* */
1075/* ------------------------------------------------------------------------- */
1076
1077void TEWidget::frameChanged()
1078{
1079 propagateSize();
1080 update();
1081}
1082
1083/* ------------------------------------------------------------------------- */
1084/* */
1085/* Sound */
1086/* */
1087/* ------------------------------------------------------------------------- */
1088
1089void TEWidget::Bell()
1090{
1091 QApplication::beep();
1092}
1093
1094/* ------------------------------------------------------------------------- */
1095/* */
1096/* Auxiluary */
1097/* */
1098/* ------------------------------------------------------------------------- */
1099
1100void TEWidget::clearImage()
1101// initialize the image
1102// for internal use only
1103{
1104 for (int y = 0; y < lines; y++)
1105 for (int x = 0; x < columns; x++)
1106 {
1107 image[loc(x,y)].c = 0xff; //' ';
1108 image[loc(x,y)].f = 0xff; //DEFAULT_FORE_COLOR;
1109 image[loc(x,y)].b = 0xff; //DEFAULT_BACK_COLOR;
1110 image[loc(x,y)].r = 0xff; //DEFAULT_RENDITION;
1111 }
1112}
1113
1114// Create Image ///////////////////////////////////////////////////////
1115
1116void TEWidget::calcGeometry()
1117{
1118 //FIXME: set rimX == rimY == 0 when running in full screen mode.
1119
1120 scrollbar->resize(QApplication::style().scrollBarExtent().width(),
1121 contentsRect().height());
1122 switch(scrollLoc)
1123 {
1124 case SCRNONE :
1125 columns = ( contentsRect().width() - 2 * rimX ) / font_w;
1126 blX = (contentsRect().width() - (columns*font_w) ) / 2;
1127 brX = blX;
1128 scrollbar->hide();
1129 break;
1130 case SCRLEFT :
1131 columns = ( contentsRect().width() - 2 * rimX - scrollbar->width()) / font_w;
1132 brX = (contentsRect().width() - (columns*font_w) - scrollbar->width() ) / 2;
1133 blX = brX + scrollbar->width();
1134 scrollbar->move(contentsRect().topLeft());
1135 scrollbar->show();
1136 break;
1137 case SCRRIGHT:
1138 columns = ( contentsRect().width() - 2 * rimX - scrollbar->width()) / font_w;
1139 blX = (contentsRect().width() - (columns*font_w) - scrollbar->width() ) / 2;
1140 brX = blX;
1141 scrollbar->move(contentsRect().topRight() - QPoint(scrollbar->width()-1,0));
1142 scrollbar->show();
1143 break;
1144 }
1145 //FIXME: support 'rounding' styles
1146 lines = ( contentsRect().height() - 2 * rimY ) / font_h;
1147 bY = (contentsRect().height() - (lines *font_h)) / 2;
1148}
1149
1150void TEWidget::makeImage()
1151//FIXME: rename 'calcGeometry?
1152{
1153 calcGeometry();
1154 image = (ca*) malloc(lines*columns*sizeof(ca));
1155 clearImage();
1156}
1157
1158// calculate the needed size
1159QSize TEWidget::calcSize(int cols, int lins) const
1160{
1161 int frw = width() - contentsRect().width();
1162 int frh = height() - contentsRect().height();
1163 int scw = (scrollLoc==SCRNONE?0:scrollbar->width());
1164 return QSize( font_w*cols + 2*rimX + frw + scw, font_h*lins + 2*rimY + frh );
1165}
1166
1167QSize TEWidget::sizeHint() const
1168{
1169 return size();
1170}
1171
1172void TEWidget::styleChange(QStyle &)
1173{
1174 propagateSize();
1175}
1176
1177#ifndef QT_NO_DRAGANDDROP
1178
1179/* --------------------------------------------------------------------- */
1180/* */
1181/* Drag & Drop */
1182/* */
1183/* --------------------------------------------------------------------- */
1184
1185
1186void TEWidget::dragEnterEvent(QDragEnterEvent* e)
1187{
1188 e->accept(QTextDrag::canDecode(e) ||
1189 QUriDrag::canDecode(e));
1190}
1191
1192void TEWidget::dropEvent(QDropEvent* event)
1193{
1194 // The current behaviour when url(s) are dropped is
1195 // * if there is only ONE url and if it's a LOCAL one, ask for paste or cd
1196 // * in all other cases, just paste
1197 // (for non-local ones, or for a list of URLs, 'cd' is nonsense)
1198 QStrList strlist;
1199 int file_count = 0;
1200 dropText = "";
1201 bool bPopup = true;
1202
1203 if(QUriDrag::decode(event, strlist)) {
1204 if (strlist.count()) {
1205 for(const char* p = strlist.first(); p; p = strlist.next()) {
1206 if(file_count++ > 0) {
1207 dropText += " ";
1208 bPopup = false; // more than one file, don't popup
1209 }
1210
1211/*
1212 KURL url(p);
1213 if (url.isLocalFile()) {
1214 dropText += url.path(); // local URL : remove protocol
1215 }
1216 else {
1217 dropText += url.prettyURL();
1218 bPopup = false; // a non-local file, don't popup
1219 }
1220*/
1221
1222 }
1223
1224 if (bPopup)
1225 // m_drop->popup(pos() + event->pos());
1226 m_drop->popup(mapToGlobal(event->pos()));
1227 else
1228 {
1229 if (currentSession) {
1230 //currentSession->getEmulation()->sendString(dropText.local8Bit());
1231 QByteArray tmp;
1232 // ibot: this should be pretty wrong...
1233 currentSession->layer()->send( tmp.setRawData( dropText.local8Bit()));
1234 }
1235 // kdDebug() << "Drop:" << dropText.local8Bit() << "\n";
1236 }
1237 }
1238 }
1239 else if(QTextDrag::decode(event, dropText)) {
1240// kdDebug() << "Drop:" << dropText.local8Bit() << "\n";
1241 if (currentSession) {
1242 //currentSession->getEmulation()->sendString(dropText.local8Bit());
1243 QByteArray tmp;
1244 currentSession->layer()->send( tmp.setRawData( dropText.local8Bit()));
1245 }
1246 // Paste it
1247 }
1248}
1249#endif
1250
1251
1252void TEWidget::drop_menu_activated(int item)
1253{
1254#ifndef QT_NO_DRAGANDDROP
1255 QByteArray tmp;
1256 switch (item)
1257 {
1258 case 0: // paste
1259 //currentSession->getEmulation()->sendString(dropText.local8Bit());
1260 currentSession->layer()->send( tmp.setRawData( dropText.local8Bit()));
1261
1262// KWM::activate((Window)this->winId());
1263 break;
1264 case 1: // cd ...
1265 //currentSession->getEmulation()->sendString("cd ");
1266 tmp.setRawData( "cd " );
1267 currentSession->layer()->send( tmp );
1268 struct stat statbuf;
1269 if ( ::stat( QFile::encodeName( dropText ), &statbuf ) == 0 )
1270 {
1271 if ( !S_ISDIR(statbuf.st_mode) )
1272 {
1273/*
1274 KURL url;
1275 url.setPath( dropText );
1276 dropText = url.directory( true, false ); // remove filename
1277*/
1278 }
1279 }
1280 dropText.replace(QRegExp(" "), "\\ "); // escape spaces
1281 QByteArray tmp2;
1282 tmp.setRawDate( dropText.local8Bit() + "\n" );
1283 //currentSession->getEmulation()->sendString(dropText.local8Bit());
1284 //currentSession->getEmulation()->sendString("\n");
1285 currentSession->layer()->send( tmp );
1286// KWM::activate((Window)this->winId());
1287 break;
1288 }
1289#endif
1290}
1291