comparison libqterminal/unix/TerminalView.cpp @ 15671:14da85a0d1c3

Set terminal to fixed width, renamed some variables.
author Jacob Dawid <jacob.dawid@googlemail.com>
date Fri, 08 Jun 2012 18:12:41 +0200
parents a8ff19a82906
children 76452c97add8
comparison
equal deleted inserted replaced
15670:d79d1a3130c8 15671:14da85a0d1c3
54 #endif 54 #endif
55 55
56 #define yMouseScroll 1 56 #define yMouseScroll 1
57 57
58 #define REPCHAR "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \ 58 #define REPCHAR "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
59 "abcdefgjijklmnopqrstuvwxyz" \ 59 "abcdefgjijklmnopqrstuvwxyz" \
60 "0123456789./+@" 60 "0123456789./+@"
61 61
62 // scroll increment used when dragging selection at top/bottom of window. 62 // scroll increment used when dragging selection at top/bottom of window.
63 63
64 // static 64 // static
65 bool TerminalView::_antialiasText = true; 65 bool TerminalView::_antialiasText = true;
79 IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White 79 IBMPC (rgb) Black Blue Green Cyan Red Magenta Yellow White
80 */ 80 */
81 81
82 ScreenWindow* TerminalView::screenWindow() const 82 ScreenWindow* TerminalView::screenWindow() const
83 { 83 {
84 return _screenWindow; 84 return _screenWindow;
85 } 85 }
86 void TerminalView::setScreenWindow(ScreenWindow* window) 86 void TerminalView::setScreenWindow(ScreenWindow* window)
87 { 87 {
88 // disconnect existing screen window if any 88 // disconnect existing screen window if any
89 if ( _screenWindow ) 89 if ( _screenWindow )
90 { 90 {
91 disconnect( _screenWindow , 0 , this , 0 ); 91 disconnect( _screenWindow , 0 , this , 0 );
92 } 92 }
93 93
94 _screenWindow = window; 94 _screenWindow = window;
95 95
96 if ( window ) 96 if ( window )
97 { 97 {
98 //#warning "The order here is not specified - does it matter whether updateImage or updateLineProperties comes first?" 98 //#warning "The order here is not specified - does it matter whether updateImage or updateLineProperties comes first?"
99 connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateLineProperties()) ); 99 connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateLineProperties()) );
100 connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateImage()) ); 100 connect( _screenWindow , SIGNAL(outputChanged()) , this , SLOT(updateImage()) );
101 window->setWindowLines(_lines); 101 window->setWindowLines(_lines);
102 } 102 }
103 } 103 }
104 104
105 const ColorEntry* TerminalView::colorTable() const 105 const ColorEntry* TerminalView::colorTable() const
106 { 106 {
108 } 108 }
109 109
110 void TerminalView::setColorTable(const ColorEntry table[]) 110 void TerminalView::setColorTable(const ColorEntry table[])
111 { 111 {
112 for (int i = 0; i < TABLE_COLORS; i++) 112 for (int i = 0; i < TABLE_COLORS; i++)
113 _colorTable[i] = table[i]; 113 _colorTable[i] = table[i];
114 114
115 QPalette p = palette(); 115 QPalette p = palette();
116 p.setColor( backgroundRole(), _colorTable[DEFAULT_BACK_COLOR].color ); 116 p.setColor( backgroundRole(), _colorTable[DEFAULT_BACK_COLOR].color );
117 setPalette( p ); 117 setPalette( p );
118 118
141 */ 141 */
142 142
143 static inline bool isLineChar(quint16 c) { return ((c & 0xFF80) == 0x2500);} 143 static inline bool isLineChar(quint16 c) { return ((c & 0xFF80) == 0x2500);}
144 static inline bool isLineCharString(const QString& string) 144 static inline bool isLineCharString(const QString& string)
145 { 145 {
146 return (string.length() > 0) && (isLineChar(string.at(0).unicode())); 146 return (string.length() > 0) && (isLineChar(string.at(0).unicode()));
147 } 147 }
148 148
149 149
150 // assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i. 150 // assert for i in [0..31] : vt100extended(vt100_graphics[i]) == i.
151 151
171 171
172 _fixedFont = true; 172 _fixedFont = true;
173 173
174 int fw = fm.width(REPCHAR[0]); 174 int fw = fm.width(REPCHAR[0]);
175 for(unsigned int i=1; i< strlen(REPCHAR); i++) 175 for(unsigned int i=1; i< strlen(REPCHAR); i++)
176 { 176 {
177 if (fw != fm.width(REPCHAR[i])) 177 if (fw != fm.width(REPCHAR[i]))
178 { 178 {
179 _fixedFont = false; 179 _fixedFont = false;
180 break; 180 break;
181 } 181 }
182 } 182 }
183
183 184
184 if (_fontWidth < 1) 185 if (_fontWidth < 1)
185 _fontWidth=1; 186 _fontWidth=1;
186 187
187 _fontAscent = fm.ascent(); 188 _fontAscent = fm.ascent();
188 189
189 emit changedFontMetricSignal( _fontHeight, _fontWidth ); 190 emit changedFontMetricSignal( _fontHeight, _fontWidth );
191 parentWidget()->setFixedWidth(_fontWidth * 80 + _leftMargin);
190 propagateSize(); 192 propagateSize();
191 update(); 193 update();
192 } 194 }
193 195
194 void TerminalView::setVTFont(const QFont& f) 196 void TerminalView::setVTFont(const QFont& f)
196 QFont font = f; 198 QFont font = f;
197 199
198 QFontMetrics metrics(font); 200 QFontMetrics metrics(font);
199 201
200 if ( metrics.height() < height() && metrics.maxWidth() < width() ) 202 if ( metrics.height() < height() && metrics.maxWidth() < width() )
201 { 203 {
202 // hint that text should be drawn without anti-aliasing. 204 // hint that text should be drawn without anti-aliasing.
203 // depending on the user's font configuration, this may not be respected 205 // depending on the user's font configuration, this may not be respected
204 if (!_antialiasText) 206 if (!_antialiasText)
205 font.setStyleStrategy( QFont::NoAntialias ); 207 font.setStyleStrategy( QFont::NoAntialias );
206 208
207 // experimental optimization. Konsole assumes that the terminal is using a 209 // experimental optimization. Konsole assumes that the terminal is using a
208 // mono-spaced font, in which case kerning information should have an effect. 210 // mono-spaced font, in which case kerning information should have an effect.
209 // Disabling kerning saves some computation when rendering text. 211 // Disabling kerning saves some computation when rendering text.
210 font.setKerning(false); 212 // font.setKerning(false);
211 213
212 QWidget::setFont(font); 214 QWidget::setFont(font);
213 fontChange(font); 215 fontChange(font);
214 } 216 }
215 } 217 }
216 218
217 void TerminalView::setFont(const QFont &) 219 void TerminalView::setFont(const QFont &)
218 { 220 {
219 // ignore font change request if not coming from konsole itself 221 // ignore font change request if not coming from konsole itself
224 /* Constructor / Destructor */ 226 /* Constructor / Destructor */
225 /* */ 227 /* */
226 /* ------------------------------------------------------------------------- */ 228 /* ------------------------------------------------------------------------- */
227 229
228 TerminalView::TerminalView(QWidget *parent) 230 TerminalView::TerminalView(QWidget *parent)
229 :QWidget(parent) 231 :QWidget(parent)
230 ,_screenWindow(0) 232 ,_screenWindow(0)
231 ,_allowBell(true) 233 ,_allowBell(true)
232 ,_gridLayout(0) 234 ,_gridLayout(0)
233 ,_fontHeight(1) 235 ,_fontHeight(1)
234 ,_fontWidth(1) 236 ,_fontWidth(1)
235 ,_fontAscent(1) 237 ,_fontAscent(1)
236 ,_lines(1) 238 ,_lines(1)
237 ,_columns(1) 239 ,_columns(1)
238 ,_usedLines(1) 240 ,_usedLines(1)
239 ,_usedColumns(1) 241 ,_usedColumns(1)
240 ,_contentHeight(1) 242 ,_contentHeight(1)
241 ,_contentWidth(1) 243 ,_contentWidth(1)
242 ,_image(0) 244 ,_image(0)
243 ,_randomSeed(0) 245 ,_randomSeed(0)
244 ,_resizing(false) 246 ,_resizing(false)
245 ,_terminalSizeHint(false) 247 ,_terminalSizeHint(false)
246 ,_terminalSizeStartup(true) 248 ,_terminalSizeStartup(true)
247 ,_bidiEnabled(false) 249 ,_bidiEnabled(false)
248 ,_actSel(0) 250 ,_actSel(0)
249 ,_wordSelectionMode(false) 251 ,_wordSelectionMode(false)
250 ,_lineSelectionMode(false) 252 ,_lineSelectionMode(false)
251 ,_preserveLineBreaks(false) 253 ,_preserveLineBreaks(false)
252 ,_columnSelectionMode(false) 254 ,_columnSelectionMode(false)
253 ,_scrollbarLocation(NoScrollBar) 255 ,_scrollbarLocation(NoScrollBar)
254 ,_wordCharacters(":@-./_~") 256 ,_wordCharacters(":@-./_~")
255 ,_bellMode(SystemBeepBell) 257 ,_bellMode(SystemBeepBell)
256 ,_blinking(false) 258 ,_blinking(false)
257 ,_cursorBlinking(false) 259 ,_cursorBlinking(false)
258 ,_hasBlinkingCursor(false) 260 ,_hasBlinkingCursor(false)
259 ,_ctrlDrag(false) 261 ,_ctrlDrag(false)
260 ,_tripleClickMode(SelectWholeLine) 262 ,_tripleClickMode(SelectWholeLine)
261 ,_isFixedSize(false) 263 ,_isFixedSize(false)
262 ,_possibleTripleClick(false) 264 ,_possibleTripleClick(false)
263 ,_resizeWidget(0) 265 ,_resizeWidget(0)
264 ,_resizeTimer(0) 266 ,_resizeTimer(0)
265 ,_outputSuspendedLabel(0) 267 ,_outputSuspendedLabel(0)
266 ,_lineSpacing(0) 268 ,_lineSpacing(0)
267 ,_colorsInverted(false) 269 ,_colorsInverted(false)
268 ,_blendColor(qRgba(0,0,0,0xff)) 270 ,_blendColor(qRgba(0,0,0,0xff))
269 ,_filterChain(new TerminalImageFilterChain()) 271 ,_filterChain(new TerminalImageFilterChain())
270 ,_cursorShape(BlockCursor) 272 ,_cursorShape(BlockCursor)
271 ,_readonly(false) 273 ,_readonly(false)
272 { 274 {
273 // terminal applications are not designed with Right-To-Left in mind, 275 // terminal applications are not designed with Right-To-Left in mind,
274 // so the layout is forced to Left-To-Right 276 // so the layout is forced to Left-To-Right
275 setLayoutDirection(Qt::LeftToRight); 277 setLayoutDirection(Qt::LeftToRight);
276 278
284 // set the scroll bar's slider to occupy the whole area of the scroll bar initially 286 // set the scroll bar's slider to occupy the whole area of the scroll bar initially
285 _scrollBar = new QScrollBar(this); 287 _scrollBar = new QScrollBar(this);
286 setScroll(0,0); 288 setScroll(0,0);
287 _scrollBar->setCursor( Qt::ArrowCursor ); 289 _scrollBar->setCursor( Qt::ArrowCursor );
288 connect(_scrollBar, SIGNAL(valueChanged(int)), this, 290 connect(_scrollBar, SIGNAL(valueChanged(int)), this,
289 SLOT(scrollBarPositionChanged(int))); 291 SLOT(scrollBarPositionChanged(int)));
290 292
291 // setup timers for blinking cursor and text 293 // setup timers for blinking cursor and text
292 _blinkTimer = new QTimer(this); 294 _blinkTimer = new QTimer(this);
293 connect(_blinkTimer, SIGNAL(timeout()), this, SLOT(blinkEvent())); 295 connect(_blinkTimer, SIGNAL(timeout()), this, SLOT(blinkEvent()));
294 _blinkCursorTimer = new QTimer(this); 296 _blinkCursorTimer = new QTimer(this);
295 connect(_blinkCursorTimer, SIGNAL(timeout()), this, SLOT(blinkCursorEvent())); 297 connect(_blinkCursorTimer, SIGNAL(timeout()), this, SLOT(blinkCursorEvent()));
296 298
297 // QCursor::setAutoHideCursor( this, true ); 299 // QCursor::setAutoHideCursor( this, true );
298 300
299 setUsesMouse(true); 301 setUsesMouse(true);
300 setColorTable(base_color_table); 302 setColorTable(base_color_table);
301 setMouseTracking(true); 303 setMouseTracking(true);
302 304
355 */ 357 */
356 358
357 359
358 enum LineEncode 360 enum LineEncode
359 { 361 {
360 TopL = (1<<1), 362 TopL = (1<<1),
361 TopC = (1<<2), 363 TopC = (1<<2),
362 TopR = (1<<3), 364 TopR = (1<<3),
363 365
364 LeftT = (1<<5), 366 LeftT = (1<<5),
365 Int11 = (1<<6), 367 Int11 = (1<<6),
366 Int12 = (1<<7), 368 Int12 = (1<<7),
367 Int13 = (1<<8), 369 Int13 = (1<<8),
368 RightT = (1<<9), 370 RightT = (1<<9),
369 371
370 LeftC = (1<<10), 372 LeftC = (1<<10),
371 Int21 = (1<<11), 373 Int21 = (1<<11),
372 Int22 = (1<<12), 374 Int22 = (1<<12),
373 Int23 = (1<<13), 375 Int23 = (1<<13),
374 RightC = (1<<14), 376 RightC = (1<<14),
375 377
376 LeftB = (1<<15), 378 LeftB = (1<<15),
377 Int31 = (1<<16), 379 Int31 = (1<<16),
378 Int32 = (1<<17), 380 Int32 = (1<<17),
379 Int33 = (1<<18), 381 Int33 = (1<<18),
380 RightB = (1<<19), 382 RightB = (1<<19),
381 383
382 BotL = (1<<21), 384 BotL = (1<<21),
383 BotC = (1<<22), 385 BotC = (1<<22),
384 BotR = (1<<23) 386 BotR = (1<<23)
385 }; 387 };
386 388
387 #include "LineFont.h" 389 #include "LineFont.h"
388 390
389 static void drawLineChar(QPainter& paint, int x, int y, int w, int h, uchar code) 391 static void drawLineChar(QPainter& paint, int x, int y, int w, int h, uchar code)
390 { 392 {
391 //Calculate cell midpoints, end points. 393 //Calculate cell midpoints, end points.
392 int cx = x + w/2; 394 int cx = x + w/2;
393 int cy = y + h/2; 395 int cy = y + h/2;
394 int ex = x + w - 1; 396 int ex = x + w - 1;
395 int ey = y + h - 1; 397 int ey = y + h - 1;
396 398
397 quint32 toDraw = LineChars[code]; 399 quint32 toDraw = LineChars[code];
398 400
399 //Top _lines: 401 //Top _lines:
400 if (toDraw & TopL) 402 if (toDraw & TopL)
401 paint.drawLine(cx-1, y, cx-1, cy-2); 403 paint.drawLine(cx-1, y, cx-1, cy-2);
402 if (toDraw & TopC) 404 if (toDraw & TopC)
403 paint.drawLine(cx, y, cx, cy-2); 405 paint.drawLine(cx, y, cx, cy-2);
404 if (toDraw & TopR) 406 if (toDraw & TopR)
405 paint.drawLine(cx+1, y, cx+1, cy-2); 407 paint.drawLine(cx+1, y, cx+1, cy-2);
406 408
407 //Bot _lines: 409 //Bot _lines:
408 if (toDraw & BotL) 410 if (toDraw & BotL)
409 paint.drawLine(cx-1, cy+2, cx-1, ey); 411 paint.drawLine(cx-1, cy+2, cx-1, ey);
410 if (toDraw & BotC) 412 if (toDraw & BotC)
411 paint.drawLine(cx, cy+2, cx, ey); 413 paint.drawLine(cx, cy+2, cx, ey);
412 if (toDraw & BotR) 414 if (toDraw & BotR)
413 paint.drawLine(cx+1, cy+2, cx+1, ey); 415 paint.drawLine(cx+1, cy+2, cx+1, ey);
414 416
415 //Left _lines: 417 //Left _lines:
416 if (toDraw & LeftT) 418 if (toDraw & LeftT)
417 paint.drawLine(x, cy-1, cx-2, cy-1); 419 paint.drawLine(x, cy-1, cx-2, cy-1);
418 if (toDraw & LeftC) 420 if (toDraw & LeftC)
419 paint.drawLine(x, cy, cx-2, cy); 421 paint.drawLine(x, cy, cx-2, cy);
420 if (toDraw & LeftB) 422 if (toDraw & LeftB)
421 paint.drawLine(x, cy+1, cx-2, cy+1); 423 paint.drawLine(x, cy+1, cx-2, cy+1);
422 424
423 //Right _lines: 425 //Right _lines:
424 if (toDraw & RightT) 426 if (toDraw & RightT)
425 paint.drawLine(cx+2, cy-1, ex, cy-1); 427 paint.drawLine(cx+2, cy-1, ex, cy-1);
426 if (toDraw & RightC) 428 if (toDraw & RightC)
427 paint.drawLine(cx+2, cy, ex, cy); 429 paint.drawLine(cx+2, cy, ex, cy);
428 if (toDraw & RightB) 430 if (toDraw & RightB)
429 paint.drawLine(cx+2, cy+1, ex, cy+1); 431 paint.drawLine(cx+2, cy+1, ex, cy+1);
430 432
431 //Intersection points. 433 //Intersection points.
432 if (toDraw & Int11) 434 if (toDraw & Int11)
433 paint.drawPoint(cx-1, cy-1); 435 paint.drawPoint(cx-1, cy-1);
434 if (toDraw & Int12) 436 if (toDraw & Int12)
435 paint.drawPoint(cx, cy-1); 437 paint.drawPoint(cx, cy-1);
436 if (toDraw & Int13) 438 if (toDraw & Int13)
437 paint.drawPoint(cx+1, cy-1); 439 paint.drawPoint(cx+1, cy-1);
438 440
439 if (toDraw & Int21) 441 if (toDraw & Int21)
440 paint.drawPoint(cx-1, cy); 442 paint.drawPoint(cx-1, cy);
441 if (toDraw & Int22) 443 if (toDraw & Int22)
442 paint.drawPoint(cx, cy); 444 paint.drawPoint(cx, cy);
443 if (toDraw & Int23) 445 if (toDraw & Int23)
444 paint.drawPoint(cx+1, cy); 446 paint.drawPoint(cx+1, cy);
445 447
446 if (toDraw & Int31) 448 if (toDraw & Int31)
447 paint.drawPoint(cx-1, cy+1); 449 paint.drawPoint(cx-1, cy+1);
448 if (toDraw & Int32) 450 if (toDraw & Int32)
449 paint.drawPoint(cx, cy+1); 451 paint.drawPoint(cx, cy+1);
450 if (toDraw & Int33) 452 if (toDraw & Int33)
451 paint.drawPoint(cx+1, cy+1); 453 paint.drawPoint(cx+1, cy+1);
452 454
453 } 455 }
454 456
455 void TerminalView::drawLineCharString( QPainter& painter, int x, int y, const QString& str, 457 void TerminalView::drawLineCharString( QPainter& painter, int x, int y, const QString& str,
456 const Character* attributes) 458 const Character* attributes)
457 { 459 {
458 const QPen& currentPen = painter.pen(); 460 const QPen& currentPen = painter.pen();
459 461
460 if ( attributes->rendition & RE_BOLD ) 462 if ( attributes->rendition & RE_BOLD )
461 { 463 {
462 QPen boldPen(currentPen); 464 QPen boldPen(currentPen);
463 boldPen.setWidth(3); 465 boldPen.setWidth(3);
464 painter.setPen( boldPen ); 466 painter.setPen( boldPen );
465 } 467 }
466 468
467 for (int i=0 ; i < str.length(); i++) 469 for (int i=0 ; i < str.length(); i++)
468 { 470 {
469 uchar code = str[i].cell(); 471 uchar code = str[i].cell();
470 if (LineChars[code]) 472 if (LineChars[code])
471 drawLineChar(painter, x + (_fontWidth*i), y, _fontWidth, _fontHeight, code); 473 drawLineChar(painter, x + (_fontWidth*i), y, _fontWidth, _fontHeight, code);
472 } 474 }
473 475
474 painter.setPen( currentPen ); 476 painter.setPen( currentPen );
475 } 477 }
476 478
477 void TerminalView::setKeyboardCursorShape(KeyboardCursorShape shape) 479 void TerminalView::setKeyboardCursorShape(KeyboardCursorShape shape)
478 { 480 {
479 _cursorShape = shape; 481 _cursorShape = shape;
480 } 482 }
481 TerminalView::KeyboardCursorShape TerminalView::keyboardCursorShape() const 483 TerminalView::KeyboardCursorShape TerminalView::keyboardCursorShape() const
482 { 484 {
483 return _cursorShape; 485 return _cursorShape;
484 } 486 }
485 void TerminalView::setKeyboardCursorColor(bool useForegroundColor, const QColor& color) 487 void TerminalView::setKeyboardCursorColor(bool useForegroundColor, const QColor& color)
486 { 488 {
487 if (useForegroundColor) 489 if (useForegroundColor)
488 _cursorColor = QColor(); // an invalid color means that 490 _cursorColor = QColor(); // an invalid color means that
489 // the foreground color of the 491 // the foreground color of the
490 // current character should 492 // current character should
491 // be used 493 // be used
492 494
493 else 495 else
494 _cursorColor = color; 496 _cursorColor = color;
495 } 497 }
496 QColor TerminalView::keyboardCursorColor() const 498 QColor TerminalView::keyboardCursorColor() const
497 { 499 {
498 return _cursorColor; 500 return _cursorColor;
499 } 501 }
500 502
501 void TerminalView::setOpacity(qreal opacity) 503 void TerminalView::setOpacity(qreal opacity)
502 { 504 {
503 QColor color(_blendColor); 505 QColor color(_blendColor);
504 color.setAlphaF(opacity); 506 color.setAlphaF(opacity);
505 507
506 // enable automatic background filling to prevent the display 508 // enable automatic background filling to prevent the display
507 // flickering if there is no transparency 509 // flickering if there is no transparency
508 if ( color.alpha() == 255 ) 510 if ( color.alpha() == 255 )
509 { 511 {
510 setAutoFillBackground(true); 512 setAutoFillBackground(true);
511 } 513 }
512 else 514 else
513 { 515 {
514 setAutoFillBackground(false); 516 setAutoFillBackground(false);
515 } 517 }
516 518
517 _blendColor = color.rgba(); 519 _blendColor = color.rgba();
518 } 520 }
519 521
520 void TerminalView::drawBackground(QPainter& painter, const QRect& rect, const QColor& backgroundColor, bool useOpacitySetting ) 522 void TerminalView::drawBackground(QPainter& painter, const QRect& rect, const QColor& backgroundColor, bool useOpacitySetting )
521 { 523 {
522 // the area of the widget showing the contents of the terminal display is drawn 524 // the area of the widget showing the contents of the terminal display is drawn
523 // using the background color from the color scheme set with setColorTable() 525 // using the background color from the color scheme set with setColorTable()
524 // 526 //
525 // the area of the widget behind the scroll-bar is drawn using the background 527 // the area of the widget behind the scroll-bar is drawn using the background
526 // brush from the scroll-bar's palette, to give the effect of the scroll-bar 528 // brush from the scroll-bar's palette, to give the effect of the scroll-bar
527 // being outside of the terminal display and visual consistency with other KDE 529 // being outside of the terminal display and visual consistency with other KDE
528 // applications. 530 // applications.
529 // 531 //
530 QRect scrollBarArea = _scrollBar->isVisible() ? 532 QRect scrollBarArea = _scrollBar->isVisible() ?
531 rect.intersected(_scrollBar->geometry()) : 533 rect.intersected(_scrollBar->geometry()) :
532 QRect(); 534 QRect();
533 QRegion contentsRegion = QRegion(rect).subtracted(scrollBarArea); 535 QRegion contentsRegion = QRegion(rect).subtracted(scrollBarArea);
534 QRect contentsRect = contentsRegion.boundingRect(); 536 QRect contentsRect = contentsRegion.boundingRect();
535 537
536 if ( HAVE_TRANSPARENCY && qAlpha(_blendColor) < 0xff && useOpacitySetting ) 538 if ( HAVE_TRANSPARENCY && qAlpha(_blendColor) < 0xff && useOpacitySetting )
539 {
540 QColor color(backgroundColor);
541 color.setAlpha(qAlpha(_blendColor));
542
543 painter.save();
544 painter.setCompositionMode(QPainter::CompositionMode_Source);
545 painter.fillRect(contentsRect, color);
546 painter.restore();
547 }
548 else {
549 painter.fillRect(contentsRect, backgroundColor);
550 }
551
552 painter.fillRect(scrollBarArea,_scrollBar->palette().background());
553 }
554
555 void TerminalView::drawCursor(QPainter& painter,
556 const QRect& rect,
557 const QColor& foregroundColor,
558 const QColor& /*backgroundColor*/,
559 bool& invertCharacterColor)
560 {
561 QRect cursorRect = rect;
562 cursorRect.setHeight(_fontHeight - _lineSpacing - 1);
563
564 if (!_cursorBlinking)
565 {
566 if ( _cursorColor.isValid() )
567 painter.setPen(_cursorColor);
568 else {
569 painter.setPen(foregroundColor);
570 }
571
572 if ( _cursorShape == BlockCursor )
537 { 573 {
538 QColor color(backgroundColor); 574 // draw the cursor outline, adjusting the area so that
539 color.setAlpha(qAlpha(_blendColor)); 575 // it is draw entirely inside 'rect'
540 576 int penWidth = qMax(1,painter.pen().width());
541 painter.save(); 577
542 painter.setCompositionMode(QPainter::CompositionMode_Source); 578 painter.drawRect(cursorRect.adjusted(penWidth/2,
543 painter.fillRect(contentsRect, color); 579 penWidth/2,
544 painter.restore(); 580 - penWidth/2 - penWidth%2,
545 } 581 - penWidth/2 - penWidth%2));
546 else { 582 if ( hasFocus() )
547 painter.fillRect(contentsRect, backgroundColor);
548 }
549
550 painter.fillRect(scrollBarArea,_scrollBar->palette().background());
551 }
552
553 void TerminalView::drawCursor(QPainter& painter,
554 const QRect& rect,
555 const QColor& foregroundColor,
556 const QColor& /*backgroundColor*/,
557 bool& invertCharacterColor)
558 {
559 QRect cursorRect = rect;
560 cursorRect.setHeight(_fontHeight - _lineSpacing - 1);
561
562 if (!_cursorBlinking)
563 {
564 if ( _cursorColor.isValid() )
565 painter.setPen(_cursorColor);
566 else {
567 painter.setPen(foregroundColor);
568 }
569
570 if ( _cursorShape == BlockCursor )
571 {
572 // draw the cursor outline, adjusting the area so that
573 // it is draw entirely inside 'rect'
574 int penWidth = qMax(1,painter.pen().width());
575
576 painter.drawRect(cursorRect.adjusted(penWidth/2,
577 penWidth/2,
578 - penWidth/2 - penWidth%2,
579 - penWidth/2 - penWidth%2));
580 if ( hasFocus() )
581 { 583 {
582 painter.fillRect(cursorRect, _cursorColor.isValid() ? _cursorColor : foregroundColor); 584 painter.fillRect(cursorRect, _cursorColor.isValid() ? _cursorColor : foregroundColor);
583 585
584 if ( !_cursorColor.isValid() ) 586 if ( !_cursorColor.isValid() )
585 { 587 {
586 // invert the colour used to draw the text to ensure that the character at 588 // invert the colour used to draw the text to ensure that the character at
587 // the cursor position is readable 589 // the cursor position is readable
588 invertCharacterColor = true; 590 invertCharacterColor = true;
589 } 591 }
590 } 592 }
591 } 593 }
592 else if ( _cursorShape == UnderlineCursor ) 594 else if ( _cursorShape == UnderlineCursor )
593 painter.drawLine(cursorRect.left(), 595 painter.drawLine(cursorRect.left(),
594 cursorRect.bottom(), 596 cursorRect.bottom(),
595 cursorRect.right(), 597 cursorRect.right(),
596 cursorRect.bottom()); 598 cursorRect.bottom());
597 else if ( _cursorShape == IBeamCursor ) 599 else if ( _cursorShape == IBeamCursor )
598 painter.drawLine(cursorRect.left(), 600 painter.drawLine(cursorRect.left(),
599 cursorRect.top(), 601 cursorRect.top(),
600 cursorRect.left(), 602 cursorRect.left(),
601 cursorRect.bottom()); 603 cursorRect.bottom());
602 604
603 } 605 }
604 } 606 }
605 607
606 void TerminalView::drawCharacters(QPainter& painter, 608 void TerminalView::drawCharacters(QPainter& painter,
607 const QRect& rect, 609 const QRect& rect,
608 const QString& text, 610 const QString& text,
609 const Character* style, 611 const Character* style,
610 bool invertCharacterColor) 612 bool invertCharacterColor)
611 { 613 {
612 // don't draw text which is currently blinking 614 // don't draw text which is currently blinking
613 if ( _blinking && (style->rendition & RE_BLINK) ) 615 if ( _blinking && (style->rendition & RE_BLINK) )
614 return; 616 return;
615 617
616 // setup bold and underline 618 // setup bold and underline
617 bool useBold = style->rendition & RE_BOLD || style->isBold(_colorTable) || font().bold(); 619 bool useBold = style->rendition & RE_BOLD || style->isBold(_colorTable) || font().bold();
618 bool useUnderline = style->rendition & RE_UNDERLINE || font().underline(); 620 bool useUnderline = style->rendition & RE_UNDERLINE || font().underline();
619 621
620 QFont font = painter.font(); 622 QFont font = painter.font();
621 if ( font.bold() != useBold 623 if ( font.bold() != useBold
622 || font.underline() != useUnderline ) 624 || font.underline() != useUnderline )
623 { 625 {
624 font.setBold(useBold); 626 font.setBold(useBold);
625 font.setUnderline(useUnderline); 627 font.setUnderline(useUnderline);
626 painter.setFont(font); 628 painter.setFont(font);
627 } 629 }
628 630
629 const CharacterColor& textColor = ( invertCharacterColor ? style->backgroundColor : style->foregroundColor ); 631 const CharacterColor& textColor = ( invertCharacterColor ? style->backgroundColor : style->foregroundColor );
630 const QColor color = textColor.color(_colorTable); 632 const QColor color = textColor.color(_colorTable);
631 633
632 QPen pen = painter.pen(); 634 QPen pen = painter.pen();
633 if ( pen.color() != color ) 635 if ( pen.color() != color )
634 { 636 {
635 pen.setColor(color); 637 pen.setColor(color);
636 painter.setPen(color); 638 painter.setPen(color);
637 } 639 }
638 // draw text 640 // draw text
639 if ( isLineCharString(text) ) { 641 if ( isLineCharString(text) ) {
640 drawLineCharString(painter,rect.x(),rect.y(),text,style); 642 drawLineCharString(painter,rect.x(),rect.y(),text,style);
641 } 643 }
642 else 644 else
643 { 645 {
644 // the drawText(rect,flags,string) overload is used here with null flags 646 // the drawText(rect,flags,string) overload is used here with null flags
645 // instead of drawText(rect,string) because the (rect,string) overload causes 647 // instead of drawText(rect,string) because the (rect,string) overload causes
646 // the application's default layout direction to be used instead of 648 // the application's default layout direction to be used instead of
647 // the widget-specific layout direction, which should always be 649 // the widget-specific layout direction, which should always be
648 // Qt::LeftToRight for this widget 650 // Qt::LeftToRight for this widget
649 painter.drawText(rect,0,text); 651 painter.drawText(rect,0,text);
650 } 652 }
651 } 653 }
652 654
653 void TerminalView::drawTextFragment(QPainter& painter , 655 void TerminalView::drawTextFragment(QPainter& painter ,
654 const QRect& rect, 656 const QRect& rect,
655 const QString& text, 657 const QString& text,
656 const Character* style) 658 const Character* style)
657 { 659 {
658 painter.save(); 660 painter.save();
659 661
660 // setup painter 662 // setup painter
661 const QColor foregroundColor = style->foregroundColor.color(_colorTable); 663 const QColor foregroundColor = style->foregroundColor.color(_colorTable);
662 const QColor backgroundColor = style->backgroundColor.color(_colorTable); 664 const QColor backgroundColor = style->backgroundColor.color(_colorTable);
663 665
664 // draw background if different from the display's background color 666 // draw background if different from the display's background color
665 if ( backgroundColor != palette().background().color() ) 667 if ( backgroundColor != palette().background().color() )
666 drawBackground(painter,rect,backgroundColor, false /* do not use transparency */); 668 drawBackground(painter,rect,backgroundColor, false /* do not use transparency */);
667 669
668 // draw cursor shape if the current character is the cursor 670 // draw cursor shape if the current character is the cursor
669 // this may alter the foreground and background colors 671 // this may alter the foreground and background colors
670 bool invertCharacterColor = false; 672 bool invertCharacterColor = false;
671 673
672 if ( style->rendition & RE_CURSOR ) 674 if ( style->rendition & RE_CURSOR )
673 drawCursor(painter,rect,foregroundColor,backgroundColor,invertCharacterColor); 675 drawCursor(painter,rect,foregroundColor,backgroundColor,invertCharacterColor);
674 // draw text 676 // draw text
675 drawCharacters(painter,rect,text,style,invertCharacterColor); 677 drawCharacters(painter,rect,text,style,invertCharacterColor);
676 678
677 painter.restore(); 679 painter.restore();
678 } 680 }
679 681
680 void TerminalView::setRandomSeed(uint randomSeed) { _randomSeed = randomSeed; } 682 void TerminalView::setRandomSeed(uint randomSeed) { _randomSeed = randomSeed; }
681 uint TerminalView::randomSeed() const { return _randomSeed; } 683 uint TerminalView::randomSeed() const { return _randomSeed; }
682 684
684 /*! 686 /*!
685 Set XIM Position 687 Set XIM Position
686 */ 688 */
687 void TerminalDisplay::setCursorPos(const int curx, const int cury) 689 void TerminalDisplay::setCursorPos(const int curx, const int cury)
688 { 690 {
689 QPoint tL = contentsRect().topLeft(); 691 QPoint tL = contentsRect().topLeft();
690 int tLx = tL.x(); 692 int tLx = tL.x();
691 int tLy = tL.y(); 693 int tLy = tL.y();
692 694
693 int xpos, ypos; 695 int xpos, ypos;
694 ypos = _topMargin + tLy + _fontHeight*(cury-1) + _fontAscent; 696 ypos = _topMargin + tLy + _fontHeight*(cury-1) + _fontAscent;
695 xpos = _leftMargin + tLx + _fontWidth*curx; 697 xpos = _leftMargin + tLx + _fontWidth*curx;
696 //setMicroFocusHint(xpos, ypos, 0, _fontHeight); //### ??? 698 //setMicroFocusHint(xpos, ypos, 0, _fontHeight); //### ???
697 // fprintf(stderr, "x/y = %d/%d\txpos/ypos = %d/%d\n", curx, cury, xpos, ypos); 699 // fprintf(stderr, "x/y = %d/%d\txpos/ypos = %d/%d\n", curx, cury, xpos, ypos);
698 _cursorLine = cury; 700 _cursorLine = cury;
699 _cursorCol = curx; 701 _cursorCol = curx;
700 } 702 }
701 #endif 703 #endif
702 704
703 // scrolls the image by 'lines', down if lines > 0 or up otherwise. 705 // scrolls the image by 'lines', down if lines > 0 or up otherwise.
704 // 706 //
713 // scrolled aligns properly with the character grid - 715 // scrolled aligns properly with the character grid -
714 // which has a top left point at (_leftMargin,_topMargin) , 716 // which has a top left point at (_leftMargin,_topMargin) ,
715 // a cell width of _fontWidth and a cell height of _fontHeight). 717 // a cell width of _fontWidth and a cell height of _fontHeight).
716 void TerminalView::scrollImage(int lines , const QRect& screenWindowRegion) 718 void TerminalView::scrollImage(int lines , const QRect& screenWindowRegion)
717 { 719 {
718 // if the flow control warning is enabled this will interfere with the 720 // if the flow control warning is enabled this will interfere with the
719 // scrolling optimisations and cause artifacts. the simple solution here 721 // scrolling optimisations and cause artifacts. the simple solution here
720 // is to just disable the optimisation whilst it is visible 722 // is to just disable the optimisation whilst it is visible
721 if ( _outputSuspendedLabel && _outputSuspendedLabel->isVisible() ) { 723 if ( _outputSuspendedLabel && _outputSuspendedLabel->isVisible() ) {
722 return; 724 return;
723 } 725 }
724 726
725 // constrain the region to the display 727 // constrain the region to the display
726 // the bottom of the region is capped to the number of lines in the display's 728 // the bottom of the region is capped to the number of lines in the display's
727 // internal image - 2, so that the height of 'region' is strictly less 729 // internal image - 2, so that the height of 'region' is strictly less
728 // than the height of the internal image. 730 // than the height of the internal image.
729 QRect region = screenWindowRegion; 731 QRect region = screenWindowRegion;
730 region.setBottom( qMin(region.bottom(),this->_lines-2) ); 732 region.setBottom( qMin(region.bottom(),this->_lines-2) );
731 733
732 if ( lines == 0 734 if ( lines == 0
733 || _image == 0 735 || _image == 0
734 || !region.isValid() 736 || !region.isValid()
735 || (region.top() + abs(lines)) >= region.bottom() 737 || (region.top() + abs(lines)) >= region.bottom()
736 || this->_lines <= region.height() ) return; 738 || this->_lines <= region.height() ) return;
737 739
738 QRect scrollRect; 740 QRect scrollRect;
739 741
740 void* firstCharPos = &_image[ region.top() * this->_columns ]; 742 void* firstCharPos = &_image[ region.top() * this->_columns ];
741 void* lastCharPos = &_image[ (region.top() + abs(lines)) * this->_columns ]; 743 void* lastCharPos = &_image[ (region.top() + abs(lines)) * this->_columns ];
742 744
743 int top = _topMargin + (region.top() * _fontHeight); 745 int top = _topMargin + (region.top() * _fontHeight);
744 int linesToMove = region.height() - abs(lines); 746 int linesToMove = region.height() - abs(lines);
745 int bytesToMove = linesToMove * 747 int bytesToMove = linesToMove *
746 this->_columns * 748 this->_columns *
747 sizeof(Character); 749 sizeof(Character);
748 750
749 Q_ASSERT( linesToMove > 0 ); 751 Q_ASSERT( linesToMove > 0 );
750 Q_ASSERT( bytesToMove > 0 ); 752 Q_ASSERT( bytesToMove > 0 );
751 753
752 //scroll internal image 754 //scroll internal image
753 if ( lines > 0 ) 755 if ( lines > 0 )
754 { 756 {
755 // check that the memory areas that we are going to move are valid 757 // check that the memory areas that we are going to move are valid
756 Q_ASSERT( (char*)lastCharPos + bytesToMove < 758 Q_ASSERT( (char*)lastCharPos + bytesToMove <
757 (char*)(_image + (this->_lines * this->_columns)) ); 759 (char*)(_image + (this->_lines * this->_columns)) );
758 760
759 Q_ASSERT( (lines*this->_columns) < _imageSize ); 761 Q_ASSERT( (lines*this->_columns) < _imageSize );
760 762
761 //scroll internal image down 763 //scroll internal image down
762 memmove( firstCharPos , lastCharPos , bytesToMove ); 764 memmove( firstCharPos , lastCharPos , bytesToMove );
763 765
764 //set region of display to scroll, making sure that 766 //set region of display to scroll, making sure that
765 //the region aligns correctly to the character grid 767 //the region aligns correctly to the character grid
766 scrollRect = QRect( _leftMargin , top, 768 scrollRect = QRect( _leftMargin , top,
767 this->_usedColumns * _fontWidth , 769 this->_usedColumns * _fontWidth ,
768 linesToMove * _fontHeight ); 770 linesToMove * _fontHeight );
769 } 771 }
770 else 772 else
771 { 773 {
772 // check that the memory areas that we are going to move are valid 774 // check that the memory areas that we are going to move are valid
773 Q_ASSERT( (char*)firstCharPos + bytesToMove < 775 Q_ASSERT( (char*)firstCharPos + bytesToMove <
774 (char*)(_image + (this->_lines * this->_columns)) ); 776 (char*)(_image + (this->_lines * this->_columns)) );
775 777
776 //scroll internal image up 778 //scroll internal image up
777 memmove( lastCharPos , firstCharPos , bytesToMove ); 779 memmove( lastCharPos , firstCharPos , bytesToMove );
778 780
779 //set region of the display to scroll, making sure that 781 //set region of the display to scroll, making sure that
780 //the region aligns correctly to the character grid 782 //the region aligns correctly to the character grid
781 QPoint topPoint( _leftMargin , top + abs(lines)*_fontHeight ); 783 QPoint topPoint( _leftMargin , top + abs(lines)*_fontHeight );
782 784
783 scrollRect = QRect( topPoint , 785 scrollRect = QRect( topPoint ,
784 QSize( this->_usedColumns*_fontWidth , 786 QSize( this->_usedColumns*_fontWidth ,
785 linesToMove * _fontHeight )); 787 linesToMove * _fontHeight ));
786 } 788 }
787 789
788 //scroll the display vertically to match internal _image 790 //scroll the display vertically to match internal _image
789 scroll( 0 , _fontHeight * (-lines) , scrollRect ); 791 scroll( 0 , _fontHeight * (-lines) , scrollRect );
790 } 792 }
791 793
792 QRegion TerminalView::hotSpotRegion() const 794 QRegion TerminalView::hotSpotRegion() const
793 { 795 {
794 QRegion region; 796 QRegion region;
795 foreach( Filter::HotSpot* hotSpot , _filterChain->hotSpots() ) 797 foreach( Filter::HotSpot* hotSpot , _filterChain->hotSpots() )
796 { 798 {
797 QRect rect; 799 QRect rect;
798 rect.setLeft(hotSpot->startColumn()); 800 rect.setLeft(hotSpot->startColumn());
799 rect.setTop(hotSpot->startLine()); 801 rect.setTop(hotSpot->startLine());
800 rect.setRight(hotSpot->endColumn()); 802 rect.setRight(hotSpot->endColumn());
801 rect.setBottom(hotSpot->endLine()); 803 rect.setBottom(hotSpot->endLine());
802 804
803 region |= imageToWidget(rect); 805 region |= imageToWidget(rect);
804 } 806 }
805 return region; 807 return region;
806 } 808 }
807 809
808 void TerminalView::processFilters() 810 void TerminalView::processFilters()
809 { 811 {
810 if (!_screenWindow) 812 if (!_screenWindow)
811 return; 813 return;
812 814
813 QRegion preUpdateHotSpots = hotSpotRegion(); 815 QRegion preUpdateHotSpots = hotSpotRegion();
814 816
815 // use _screenWindow->getImage() here rather than _image because 817 // use _screenWindow->getImage() here rather than _image because
816 // other classes may call processFilters() when this display's 818 // other classes may call processFilters() when this display's
817 // ScreenWindow emits a scrolled() signal - which will happen before 819 // ScreenWindow emits a scrolled() signal - which will happen before
818 // updateImage() is called on the display and therefore _image is 820 // updateImage() is called on the display and therefore _image is
819 // out of date at this point 821 // out of date at this point
820 _filterChain->setImage( _screenWindow->getImage(), 822 _filterChain->setImage( _screenWindow->getImage(),
821 _screenWindow->windowLines(), 823 _screenWindow->windowLines(),
822 _screenWindow->windowColumns(), 824 _screenWindow->windowColumns(),
823 _screenWindow->getLineProperties() ); 825 _screenWindow->getLineProperties() );
824 _filterChain->process(); 826 _filterChain->process();
825 827
826 QRegion postUpdateHotSpots = hotSpotRegion(); 828 QRegion postUpdateHotSpots = hotSpotRegion();
827 829
828 update( preUpdateHotSpots | postUpdateHotSpots ); 830 update( preUpdateHotSpots | postUpdateHotSpots );
829 } 831 }
830 832
831 void TerminalView::updateImage() 833 void TerminalView::updateImage()
832 { 834 {
833 if ( !_screenWindow ) 835 if ( !_screenWindow )
834 return; 836 return;
835 updateLineProperties(); 837 updateLineProperties();
836 838
837 // optimization - scroll the existing image where possible and 839 // optimization - scroll the existing image where possible and
838 // avoid expensive text drawing for parts of the image that 840 // avoid expensive text drawing for parts of the image that
839 // can simply be moved up or down 841 // can simply be moved up or down
846 int columns = _screenWindow->windowColumns(); 848 int columns = _screenWindow->windowColumns();
847 849
848 setScroll( _screenWindow->currentLine() , _screenWindow->lineCount() ); 850 setScroll( _screenWindow->currentLine() , _screenWindow->lineCount() );
849 851
850 if (!_image) 852 if (!_image)
851 updateImageSize(); // Create _image 853 updateImageSize(); // Create _image
852 854
853 Q_ASSERT( this->_usedLines <= this->_lines ); 855 Q_ASSERT( this->_usedLines <= this->_lines );
854 Q_ASSERT( this->_usedColumns <= this->_columns ); 856 Q_ASSERT( this->_usedColumns <= this->_columns );
855 857
856 int y,x,len; 858 int y,x,len;
876 // be 'dirty' ( ie. have changed from the old _image to the new _image ) and 878 // be 'dirty' ( ie. have changed from the old _image to the new _image ) and
877 // which therefore need to be repainted 879 // which therefore need to be repainted
878 int dirtyLineCount = 0; 880 int dirtyLineCount = 0;
879 881
880 for (y = 0; y < linesToUpdate; y++) 882 for (y = 0; y < linesToUpdate; y++)
881 { 883 {
882 const Character* currentLine = &_image[y*this->_columns]; 884 const Character* currentLine = &_image[y*this->_columns];
883 const Character* const newLine = &newimg[y*columns]; 885 const Character* const newLine = &newimg[y*columns];
884 886
885 bool updateLine = false; 887 bool updateLine = false;
886 888
887 // The dirty mask indicates which characters need repainting. We also 889 // The dirty mask indicates which characters need repainting. We also
888 // mark surrounding neighbours dirty, in case the character exceeds 890 // mark surrounding neighbours dirty, in case the character exceeds
889 // its cell boundaries 891 // its cell boundaries
890 memset(dirtyMask, 0, columnsToUpdate+2); 892 memset(dirtyMask, 0, columnsToUpdate+2);
891 893
892 for( x = 0 ; x < columnsToUpdate ; x++) 894 for( x = 0 ; x < columnsToUpdate ; x++)
893 {
894 if ( newLine[x] != currentLine[x] )
895 { 895 {
896 dirtyMask[x] = true; 896 if ( newLine[x] != currentLine[x] )
897 } 897 {
898 } 898 dirtyMask[x] = true;
899 899 }
900 if (!_resizing) // not while _resizing, we're expecting a paintEvent 900 }
901 for (x = 0; x < columnsToUpdate; x++) 901
902 { 902 if (!_resizing) // not while _resizing, we're expecting a paintEvent
903 _hasBlinker |= (newLine[x].rendition & RE_BLINK); 903 for (x = 0; x < columnsToUpdate; x++)
904 904 {
905 // Start drawing if this character or the next one differs. 905 _hasBlinker |= (newLine[x].rendition & RE_BLINK);
906 // We also take the next one into account to handle the situation 906
907 // where characters exceed their cell width. 907 // Start drawing if this character or the next one differs.
908 if (dirtyMask[x]) 908 // We also take the next one into account to handle the situation
909 { 909 // where characters exceed their cell width.
910 quint16 c = newLine[x+0].character; 910 if (dirtyMask[x])
911 if ( !c ) 911 {
912 continue; 912 quint16 c = newLine[x+0].character;
913 int p = 0; 913 if ( !c )
914 disstrU[p++] = c; //fontMap(c); 914 continue;
915 bool lineDraw = isLineChar(c); 915 int p = 0;
916 bool doubleWidth = (x+1 == columnsToUpdate) ? false : (newLine[x+1].character == 0); 916 disstrU[p++] = c; //fontMap(c);
917 cr = newLine[x].rendition; 917 bool lineDraw = isLineChar(c);
918 _clipboard = newLine[x].backgroundColor; 918 bool doubleWidth = (x+1 == columnsToUpdate) ? false : (newLine[x+1].character == 0);
919 if (newLine[x].foregroundColor != cf) cf = newLine[x].foregroundColor; 919 cr = newLine[x].rendition;
920 int lln = columnsToUpdate - x; 920 _clipboard = newLine[x].backgroundColor;
921 for (len = 1; len < lln; len++) 921 if (newLine[x].foregroundColor != cf) cf = newLine[x].foregroundColor;
922 int lln = columnsToUpdate - x;
923 for (len = 1; len < lln; len++)
924 {
925 const Character& ch = newLine[x+len];
926
927 if (!ch.character)
928 continue; // Skip trailing part of multi-col chars.
929
930 bool nextIsDoubleWidth = (x+len+1 == columnsToUpdate) ? false : (newLine[x+len+1].character == 0);
931
932 if ( ch.foregroundColor != cf ||
933 ch.backgroundColor != _clipboard ||
934 ch.rendition != cr ||
935 !dirtyMask[x+len] ||
936 isLineChar(c) != lineDraw ||
937 nextIsDoubleWidth != doubleWidth )
938 break;
939
940 disstrU[p++] = c; //fontMap(c);
941 }
942
943 QString unistr(disstrU, p);
944
945 bool saveFixedFont = _fixedFont;
946 if (lineDraw)
947 _fixedFont = false;
948 if (doubleWidth)
949 _fixedFont = false;
950
951 updateLine = true;
952
953 _fixedFont = saveFixedFont;
954 x += len - 1;
955 }
956
957 }
958
959 //both the top and bottom halves of double height _lines must always be redrawn
960 //although both top and bottom halves contain the same characters, only
961 //the top one is actually
962 //drawn.
963 if (_lineProperties.count() > y)
964 updateLine |= (_lineProperties[y] & LINE_DOUBLEHEIGHT);
965
966 // if the characters on the line are different in the old and the new _image
967 // then this line must be repainted.
968 if (updateLine)
922 { 969 {
923 const Character& ch = newLine[x+len]; 970 dirtyLineCount++;
924 971
925 if (!ch.character) 972 // add the area occupied by this line to the region which needs to be
926 continue; // Skip trailing part of multi-col chars. 973 // repainted
927 974 QRect dirtyRect = QRect( _leftMargin+tLx ,
928 bool nextIsDoubleWidth = (x+len+1 == columnsToUpdate) ? false : (newLine[x+len+1].character == 0); 975 _topMargin+tLy+_fontHeight*y ,
929 976 _fontWidth * columnsToUpdate ,
930 if ( ch.foregroundColor != cf || 977 _fontHeight );
931 ch.backgroundColor != _clipboard || 978
932 ch.rendition != cr || 979 dirtyRegion |= dirtyRect;
933 !dirtyMask[x+len] || 980 }
934 isLineChar(c) != lineDraw || 981
935 nextIsDoubleWidth != doubleWidth ) 982 // replace the line of characters in the old _image with the
936 break; 983 // current line of the new _image
937 984 memcpy((void*)currentLine,(const void*)newLine,columnsToUpdate*sizeof(Character));
938 disstrU[p++] = c; //fontMap(c); 985 }
939 }
940
941 QString unistr(disstrU, p);
942
943 bool saveFixedFont = _fixedFont;
944 if (lineDraw)
945 _fixedFont = false;
946 if (doubleWidth)
947 _fixedFont = false;
948
949 updateLine = true;
950
951 _fixedFont = saveFixedFont;
952 x += len - 1;
953 }
954
955 }
956
957 //both the top and bottom halves of double height _lines must always be redrawn
958 //although both top and bottom halves contain the same characters, only
959 //the top one is actually
960 //drawn.
961 if (_lineProperties.count() > y)
962 updateLine |= (_lineProperties[y] & LINE_DOUBLEHEIGHT);
963
964 // if the characters on the line are different in the old and the new _image
965 // then this line must be repainted.
966 if (updateLine)
967 {
968 dirtyLineCount++;
969
970 // add the area occupied by this line to the region which needs to be
971 // repainted
972 QRect dirtyRect = QRect( _leftMargin+tLx ,
973 _topMargin+tLy+_fontHeight*y ,
974 _fontWidth * columnsToUpdate ,
975 _fontHeight );
976
977 dirtyRegion |= dirtyRect;
978 }
979
980 // replace the line of characters in the old _image with the
981 // current line of the new _image
982 memcpy((void*)currentLine,(const void*)newLine,columnsToUpdate*sizeof(Character));
983 }
984 986
985 // if the new _image is smaller than the previous _image, then ensure that the area 987 // if the new _image is smaller than the previous _image, then ensure that the area
986 // outside the new _image is cleared 988 // outside the new _image is cleared
987 if ( linesToUpdate < _usedLines ) 989 if ( linesToUpdate < _usedLines )
988 { 990 {
989 dirtyRegion |= QRect( _leftMargin+tLx , 991 dirtyRegion |= QRect( _leftMargin+tLx ,
990 _topMargin+tLy+_fontHeight*linesToUpdate , 992 _topMargin+tLy+_fontHeight*linesToUpdate ,
991 _fontWidth * this->_columns , 993 _fontWidth * this->_columns ,
992 _fontHeight * (_usedLines-linesToUpdate) ); 994 _fontHeight * (_usedLines-linesToUpdate) );
993 } 995 }
994 _usedLines = linesToUpdate; 996 _usedLines = linesToUpdate;
995 997
996 if ( columnsToUpdate < _usedColumns ) 998 if ( columnsToUpdate < _usedColumns )
997 { 999 {
998 dirtyRegion |= QRect( _leftMargin+tLx+columnsToUpdate*_fontWidth , 1000 dirtyRegion |= QRect( _leftMargin+tLx+columnsToUpdate*_fontWidth ,
999 _topMargin+tLy , 1001 _topMargin+tLy ,
1000 _fontWidth * (_usedColumns-columnsToUpdate) , 1002 _fontWidth * (_usedColumns-columnsToUpdate) ,
1001 _fontHeight * this->_lines ); 1003 _fontHeight * this->_lines );
1002 } 1004 }
1003 _usedColumns = columnsToUpdate; 1005 _usedColumns = columnsToUpdate;
1004 1006
1005 dirtyRegion |= _inputMethodData.previousPreeditRect; 1007 dirtyRegion |= _inputMethodData.previousPreeditRect;
1006 1008
1007 // update the parts of the display which have changed 1009 // update the parts of the display which have changed
1015 } 1017 }
1016 1018
1017 void TerminalView::showResizeNotification() 1019 void TerminalView::showResizeNotification()
1018 { 1020 {
1019 if (_terminalSizeHint && isVisible()) 1021 if (_terminalSizeHint && isVisible())
1020 { 1022 {
1021 if (_terminalSizeStartup) { 1023 if (_terminalSizeStartup) {
1022 _terminalSizeStartup=false; 1024 _terminalSizeStartup=false;
1023 return; 1025 return;
1024 } 1026 }
1025 if (!_resizeWidget) 1027 if (!_resizeWidget)
1026 { 1028 {
1027 _resizeWidget = new QLabel(("Size: XXX x XXX"), this); 1029 _resizeWidget = new QLabel(("Size: XXX x XXX"), this);
1028 _resizeWidget->setMinimumWidth(_resizeWidget->fontMetrics().width(("Size: XXX x XXX"))); 1030 _resizeWidget->setMinimumWidth(_resizeWidget->fontMetrics().width(("Size: XXX x XXX")));
1029 _resizeWidget->setMinimumHeight(_resizeWidget->sizeHint().height()); 1031 _resizeWidget->setMinimumHeight(_resizeWidget->sizeHint().height());
1030 _resizeWidget->setAlignment(Qt::AlignCenter); 1032 _resizeWidget->setAlignment(Qt::AlignCenter);
1031 1033
1032 _resizeWidget->setStyleSheet("background-color:palette(window);border-style:solid;border-width:1px;border-color:palette(dark)"); 1034 _resizeWidget->setStyleSheet("background-color:palette(window);border-style:solid;border-width:1px;border-color:palette(dark)");
1033 1035
1034 _resizeTimer = new QTimer(this); 1036 _resizeTimer = new QTimer(this);
1035 _resizeTimer->setSingleShot(true); 1037 _resizeTimer->setSingleShot(true);
1036 connect(_resizeTimer, SIGNAL(timeout()), _resizeWidget, SLOT(hide())); 1038 connect(_resizeTimer, SIGNAL(timeout()), _resizeWidget, SLOT(hide()));
1037 1039
1038 } 1040 }
1039 QString sizeStr; 1041 QString sizeStr;
1040 sizeStr.sprintf("Size: %d x %d", _columns, _lines); 1042 sizeStr.sprintf("Size: %d x %d", _columns, _lines);
1041 _resizeWidget->setText(sizeStr); 1043 _resizeWidget->setText(sizeStr);
1042 _resizeWidget->move((width()-_resizeWidget->width())/2, 1044 _resizeWidget->move((width()-_resizeWidget->width())/2,
1043 (height()-_resizeWidget->height())/2+20); 1045 (height()-_resizeWidget->height())/2+20);
1044 _resizeWidget->show(); 1046 _resizeWidget->show();
1045 _resizeTimer->start(1000); 1047 _resizeTimer->start(1000);
1046 } 1048 }
1047 } 1049 }
1048 1050
1049 void TerminalView::setBlinkingCursor(bool blink) 1051 void TerminalView::setBlinkingCursor(bool blink)
1050 { 1052 {
1051 _hasBlinkingCursor=blink; 1053 _hasBlinkingCursor=blink;
1052 1054
1053 if (blink && !_blinkCursorTimer->isActive()) 1055 if (blink && !_blinkCursorTimer->isActive())
1054 _blinkCursorTimer->start(BLINK_DELAY); 1056 _blinkCursorTimer->start(BLINK_DELAY);
1055 1057
1056 if (!blink && _blinkCursorTimer->isActive()) 1058 if (!blink && _blinkCursorTimer->isActive())
1057 { 1059 {
1058 _blinkCursorTimer->stop(); 1060 _blinkCursorTimer->stop();
1059 if (_cursorBlinking) 1061 if (_cursorBlinking)
1060 blinkCursorEvent(); 1062 blinkCursorEvent();
1061 else 1063 else
1062 _cursorBlinking = false; 1064 _cursorBlinking = false;
1063 } 1065 }
1064 } 1066 }
1065 1067
1066 void TerminalView::paintEvent( QPaintEvent* pe ) 1068 void TerminalView::paintEvent( QPaintEvent* pe )
1067 { 1069 {
1068 updateImage(); 1070 updateImage();
1069 //qDebug("%s %d paintEvent", __FILE__, __LINE__); 1071 //qDebug("%s %d paintEvent", __FILE__, __LINE__);
1070 QPainter paint(this); 1072 QPainter paint(this);
1071 //qDebug("%s %d paintEvent %d %d", __FILE__, __LINE__, paint.window().top(), paint.window().right()); 1073 //qDebug("%s %d paintEvent %d %d", __FILE__, __LINE__, paint.window().top(), paint.window().right());
1072 1074
1073 foreach (QRect rect, (pe->region() & contentsRect()).rects()) 1075 foreach (QRect rect, (pe->region() & contentsRect()).rects())
1074 { 1076 {
1075 drawBackground(paint,rect,palette().background().color(), true /* use opacity setting */); 1077 drawBackground(paint,rect,palette().background().color(), true /* use opacity setting */);
1076 drawContents(paint, rect); 1078 drawContents(paint, rect);
1077 } 1079 }
1078 // drawBackground(paint,contentsRect(),palette().background().color(), true /* use opacity setting */); 1080 // drawBackground(paint,contentsRect(),palette().background().color(), true /* use opacity setting */);
1079 // drawContents(paint, contentsRect()); 1081 // drawContents(paint, contentsRect());
1080 drawInputMethodPreeditString(paint,preeditRect()); 1082 //drawInputMethodPreeditString(paint,preeditRect());
1081 paintFilters(paint); 1083 //paintFilters(paint);
1082 1084
1083 paint.end(); 1085 paint.end();
1084 } 1086 }
1085 1087
1086 QPoint TerminalView::cursorPosition() const 1088 QPoint TerminalView::cursorPosition() const
1087 { 1089 {
1088 if (_screenWindow) 1090 if (_screenWindow)
1089 return _screenWindow->cursorPosition(); 1091 return _screenWindow->cursorPosition();
1090 else 1092 else
1091 return QPoint(0,0); 1093 return QPoint(0,0);
1092 } 1094 }
1093 1095
1094 QRect TerminalView::preeditRect() const 1096 QRect TerminalView::preeditRect() const
1095 { 1097 {
1096 const int preeditLength = string_width(_inputMethodData.preeditString); 1098 const int preeditLength = string_width(_inputMethodData.preeditString);
1097 1099
1098 if ( preeditLength == 0 ) 1100 if ( preeditLength == 0 )
1099 return QRect(); 1101 return QRect();
1100 1102
1101 return QRect(_leftMargin + _fontWidth*cursorPosition().x(), 1103 return QRect(_leftMargin + _fontWidth*cursorPosition().x(),
1102 _topMargin + _fontHeight*cursorPosition().y(), 1104 _topMargin + _fontHeight*cursorPosition().y(),
1103 _fontWidth*preeditLength, 1105 _fontWidth*preeditLength,
1104 _fontHeight); 1106 _fontHeight);
1105 } 1107 }
1106 1108
1107 void TerminalView::drawInputMethodPreeditString(QPainter& painter , const QRect& rect) 1109 void TerminalView::drawInputMethodPreeditString(QPainter& painter , const QRect& rect)
1108 { 1110 {
1109 if ( _inputMethodData.preeditString.isEmpty() ) { 1111 if ( _inputMethodData.preeditString.isEmpty() ) {
1110 return; 1112 return;
1111 } 1113 }
1112 const QPoint cursorPos = cursorPosition(); 1114 const QPoint cursorPos = cursorPosition();
1113 1115
1114 bool invertColors = false; 1116 bool invertColors = false;
1115 const QColor background = _colorTable[DEFAULT_BACK_COLOR].color; 1117 const QColor background = _colorTable[DEFAULT_BACK_COLOR].color;
1116 const QColor foreground = _colorTable[DEFAULT_FORE_COLOR].color; 1118 const QColor foreground = _colorTable[DEFAULT_FORE_COLOR].color;
1117 const Character* style = &_image[loc(cursorPos.x(),cursorPos.y())]; 1119 const Character* style = &_image[loc(cursorPos.x(),cursorPos.y())];
1118 1120
1119 drawBackground(painter,rect,background,true); 1121 drawBackground(painter,rect,background,true);
1120 drawCursor(painter,rect,foreground,background,invertColors); 1122 drawCursor(painter,rect,foreground,background,invertColors);
1121 drawCharacters(painter,rect,_inputMethodData.preeditString,style,invertColors); 1123 drawCharacters(painter,rect,_inputMethodData.preeditString,style,invertColors);
1122 1124
1123 _inputMethodData.previousPreeditRect = rect; 1125 _inputMethodData.previousPreeditRect = rect;
1124 } 1126 }
1125 1127
1126 FilterChain* TerminalView::filterChain() const 1128 FilterChain* TerminalView::filterChain() const
1127 { 1129 {
1128 return _filterChain; 1130 return _filterChain;
1129 } 1131 }
1130 1132
1131 void TerminalView::paintFilters(QPainter& painter) 1133 void TerminalView::paintFilters(QPainter& painter)
1132 { 1134 {
1133 //qDebug("%s %d paintFilters", __FILE__, __LINE__); 1135 //qDebug("%s %d paintFilters", __FILE__, __LINE__);
1134 1136
1135 // get color of character under mouse and use it to draw 1137 // get color of character under mouse and use it to draw
1136 // lines for filters 1138 // lines for filters
1137 QPoint cursorPos = mapFromGlobal(QCursor::pos()); 1139 QPoint cursorPos = mapFromGlobal(QCursor::pos());
1138 int cursorLine; 1140 int cursorLine;
1139 int cursorColumn; 1141 int cursorColumn;
1140 getCharacterPosition( cursorPos , cursorLine , cursorColumn ); 1142 getCharacterPosition( cursorPos , cursorLine , cursorColumn );
1141 Character cursorCharacter = _image[loc(cursorColumn,cursorLine)]; 1143 Character cursorCharacter = _image[loc(cursorColumn,cursorLine)];
1142 1144
1143 painter.setPen( QPen(cursorCharacter.foregroundColor.color(colorTable())) ); 1145 painter.setPen( QPen(cursorCharacter.foregroundColor.color(colorTable())) );
1144 1146
1145 // iterate over hotspots identified by the display's currently active filters 1147 // iterate over hotspots identified by the display's currently active filters
1146 // and draw appropriate visuals to indicate the presence of the hotspot 1148 // and draw appropriate visuals to indicate the presence of the hotspot
1147 1149
1148 QList<Filter::HotSpot*> spots = _filterChain->hotSpots(); 1150 QList<Filter::HotSpot*> spots = _filterChain->hotSpots();
1149 QListIterator<Filter::HotSpot*> iter(spots); 1151 QListIterator<Filter::HotSpot*> iter(spots);
1150 while (iter.hasNext()) 1152 while (iter.hasNext())
1151 { 1153 {
1152 Filter::HotSpot* spot = iter.next(); 1154 Filter::HotSpot* spot = iter.next();
1153 1155
1154 for ( int line = spot->startLine() ; line <= spot->endLine() ; line++ ) 1156 for ( int line = spot->startLine() ; line <= spot->endLine() ; line++ )
1155 { 1157 {
1156 int startColumn = 0; 1158 int startColumn = 0;
1157 int endColumn = _columns-1; // TODO use number of _columns which are actually 1159 int endColumn = _columns-1; // TODO use number of _columns which are actually
1158 // occupied on this line rather than the width of the 1160 // occupied on this line rather than the width of the
1159 // display in _columns 1161 // display in _columns
1160 1162
1161 // ignore whitespace at the end of the lines 1163 // ignore whitespace at the end of the lines
1162 while ( QChar(_image[loc(endColumn,line)].character).isSpace() && endColumn > 0 ) 1164 while ( QChar(_image[loc(endColumn,line)].character).isSpace() && endColumn > 0 )
1163 endColumn--; 1165 endColumn--;
1164 1166
1165 // increment here because the column which we want to set 'endColumn' to 1167 // increment here because the column which we want to set 'endColumn' to
1166 // is the first whitespace character at the end of the line 1168 // is the first whitespace character at the end of the line
1167 endColumn++; 1169 endColumn++;
1168 1170
1169 if ( line == spot->startLine() ) 1171 if ( line == spot->startLine() )
1170 startColumn = spot->startColumn(); 1172 startColumn = spot->startColumn();
1171 if ( line == spot->endLine() ) 1173 if ( line == spot->endLine() )
1172 endColumn = spot->endColumn(); 1174 endColumn = spot->endColumn();
1173 1175
1174 // subtract one pixel from 1176 // subtract one pixel from
1175 // the right and bottom so that 1177 // the right and bottom so that
1176 // we do not overdraw adjacent 1178 // we do not overdraw adjacent
1177 // hotspots 1179 // hotspots
1178 // 1180 //
1179 // subtracting one pixel from all sides also prevents an edge case where 1181 // subtracting one pixel from all sides also prevents an edge case where
1180 // moving the mouse outside a link could still leave it underlined 1182 // moving the mouse outside a link could still leave it underlined
1181 // because the check below for the position of the cursor 1183 // because the check below for the position of the cursor
1182 // finds it on the border of the target area 1184 // finds it on the border of the target area
1183 QRect r; 1185 QRect r;
1184 r.setCoords( startColumn*_fontWidth + 1, line*_fontHeight + 1, 1186 r.setCoords( startColumn*_fontWidth + 1, line*_fontHeight + 1,
1185 endColumn*_fontWidth - 1, (line+1)*_fontHeight - 1 ); 1187 endColumn*_fontWidth - 1, (line+1)*_fontHeight - 1 );
1186 1188
1187 // Underline link hotspots 1189 // Underline link hotspots
1188 if ( spot->type() == Filter::HotSpot::Link ) 1190 if ( spot->type() == Filter::HotSpot::Link )
1189 { 1191 {
1190 QFontMetrics metrics(font()); 1192 QFontMetrics metrics(font());
1191 1193
1192 // find the baseline (which is the invisible line that the characters in the font sit on, 1194 // find the baseline (which is the invisible line that the characters in the font sit on,
1193 // with some having tails dangling below) 1195 // with some having tails dangling below)
1194 int baseline = r.bottom() - metrics.descent(); 1196 int baseline = r.bottom() - metrics.descent();
1195 // find the position of the underline below that 1197 // find the position of the underline below that
1196 int underlinePos = baseline + metrics.underlinePos(); 1198 int underlinePos = baseline + metrics.underlinePos();
1197 1199
1198 if ( r.contains( mapFromGlobal(QCursor::pos()) ) ) 1200 if ( r.contains( mapFromGlobal(QCursor::pos()) ) )
1199 painter.drawLine( r.left() , underlinePos , 1201 painter.drawLine( r.left() , underlinePos ,
1200 r.right() , underlinePos ); 1202 r.right() , underlinePos );
1201 } 1203 }
1202 // Marker hotspots simply have a transparent rectanglular shape 1204 // Marker hotspots simply have a transparent rectanglular shape
1203 // drawn on top of them 1205 // drawn on top of them
1204 else if ( spot->type() == Filter::HotSpot::Marker ) 1206 else if ( spot->type() == Filter::HotSpot::Marker )
1205 { 1207 {
1206 //TODO - Do not use a hardcoded colour for this 1208 //TODO - Do not use a hardcoded colour for this
1207 painter.fillRect(r,QBrush(QColor(255,0,0,120))); 1209 painter.fillRect(r,QBrush(QColor(255,0,0,120)));
1208 } 1210 }
1209 } 1211 }
1210 } 1212 }
1211 } 1213 }
1212 void TerminalView::drawContents(QPainter &paint, const QRect &rect) 1214 void TerminalView::drawContents(QPainter &paint, const QRect &rect)
1213 { 1215 {
1214 //qDebug("%s %d drawContents and rect x=%d y=%d w=%d h=%d", __FILE__, __LINE__, rect.x(), rect.y(),rect.width(),rect.height()); 1216 //qDebug("%s %d drawContents and rect x=%d y=%d w=%d h=%d", __FILE__, __LINE__, rect.x(), rect.y(),rect.width(),rect.height());
1215 1217
1216 QPoint tL = contentsRect().topLeft(); 1218 QPoint topLeft = contentsRect().topLeft();
1217 // int tLx = tL.x(); 1219 // Take the topmost vertical position for the view.
1218 int tLy = tL.y(); 1220 int topLeftY = topLeft.y();
1219 1221
1220 int tLx = (_contentWidth - _usedColumns * _fontWidth)/2; 1222 // In Konsole, the view has been centered. Don't do that here, since there
1221 // int tLy = (_contentHeight - _usedLines * _fontHeight)/2; 1223 // are strange hopping effects during a resize when the view does no match
1222 //qDebug("%d %d %d %d", tLx, tLy, _contentWidth, _usedColumns * _fontWidth); 1224 // exactly the widget width.
1223 1225 // int topLeftX = (_contentWidth - _usedColumns * _fontWidth) / 2;
1224 int lux = qMin(_usedColumns-1, qMax(0,(rect.left() - tLx - _leftMargin ) / _fontWidth)); 1226 int topLeftX = 0;
1225 int luy = qMin(_usedLines-1, qMax(0, (rect.top() - tLy - _topMargin ) / _fontHeight)); 1227
1226 int rlx = qMin(_usedColumns-1, qMax(0, (rect.right() - tLx - _leftMargin ) / _fontWidth)); 1228 int leftUpperX = qMin(_usedColumns-1, qMax(0,(rect.left() - topLeftX - _leftMargin ) / _fontWidth));
1227 int rly = qMin(_usedLines-1, qMax(0, (rect.bottom() - tLy - _topMargin ) / _fontHeight)); 1229 int leftUpperY = qMin(_usedLines-1, qMax(0, (rect.top() - topLeftY - _topMargin ) / _fontHeight));
1230 int rightLowerX = qMin(_usedColumns-1, qMax(0, (rect.right() - topLeftX - _leftMargin ) / _fontWidth));
1231 int rightLowerY = qMin(_usedLines-1, qMax(0, (rect.bottom() - topLeftY - _topMargin ) / _fontHeight));
1228 1232
1229 const int bufferSize = _usedColumns; 1233 const int bufferSize = _usedColumns;
1230 QChar *disstrU = new QChar[bufferSize]; 1234 QChar *disstrU = new QChar[bufferSize];
1231 for (int y = luy; y <= rly; y++) 1235 for (int y = leftUpperY; y <= rightLowerY; y++)
1232 { 1236 {
1233 quint16 c = _image[loc(lux,y)].character; 1237 quint16 c = _image[loc(leftUpperX,y)].character;
1234 int x = lux; 1238 int x = leftUpperX;
1235 if(!c && x) 1239 if(!c && x)
1236 x--; // Search for start of multi-column character 1240 x--; // Search for start of multi-column character
1237 for (; x <= rlx; x++) 1241 for (; x <= rightLowerX; x++)
1238 {
1239 int len = 1;
1240 int p = 0;
1241
1242 // is this a single character or a sequence of characters ?
1243 if ( _image[loc(x,y)].rendition & RE_EXTENDED_CHAR )
1244 {
1245 // sequence of characters
1246 ushort extendedCharLength = 0;
1247 ushort* chars = ExtendedCharTable::instance
1248 .lookupExtendedChar(_image[loc(x,y)].charSequence,extendedCharLength);
1249 for ( int index = 0 ; index < extendedCharLength ; index++ )
1250 { 1242 {
1251 Q_ASSERT( p < bufferSize ); 1243 int len = 1;
1252 disstrU[p++] = chars[index]; 1244 int p = 0;
1253 } 1245
1254 } 1246 // is this a single character or a sequence of characters ?
1255 else 1247 if ( _image[loc(x,y)].rendition & RE_EXTENDED_CHAR )
1256 { 1248 {
1257 // single character 1249 // sequence of characters
1258 c = _image[loc(x,y)].character; 1250 ushort extendedCharLength = 0;
1259 if (c) 1251 ushort* chars = ExtendedCharTable::instance
1260 { 1252 .lookupExtendedChar(_image[loc(x,y)].charSequence,extendedCharLength);
1261 Q_ASSERT( p < bufferSize ); 1253 for ( int index = 0 ; index < extendedCharLength ; index++ )
1262 disstrU[p++] = c; //fontMap(c); 1254 {
1263 } 1255 Q_ASSERT( p < bufferSize );
1264 } 1256 disstrU[p++] = chars[index];
1265 1257 }
1266 bool lineDraw = isLineChar(c); 1258 }
1267 bool doubleWidth = (_image[ qMin(loc(x,y)+1,_imageSize) ].character == 0); 1259 else
1268 CharacterColor currentForeground = _image[loc(x,y)].foregroundColor; 1260 {
1269 CharacterColor currentBackground = _image[loc(x,y)].backgroundColor; 1261 // single character
1270 quint8 currentRendition = _image[loc(x,y)].rendition; 1262 c = _image[loc(x,y)].character;
1271 1263 if (c)
1272 while (x+len <= rlx && 1264 {
1273 _image[loc(x+len,y)].foregroundColor == currentForeground && 1265 Q_ASSERT( p < bufferSize );
1274 _image[loc(x+len,y)].backgroundColor == currentBackground && 1266 disstrU[p++] = c; //fontMap(c);
1275 _image[loc(x+len,y)].rendition == currentRendition && 1267 }
1276 (_image[ qMin(loc(x+len,y)+1,_imageSize) ].character == 0) == doubleWidth && 1268 }
1277 isLineChar( c = _image[loc(x+len,y)].character) == lineDraw) // Assignment! 1269
1278 { 1270 bool lineDraw = isLineChar(c);
1279 if (c) 1271 bool doubleWidth = (_image[ qMin(loc(x,y)+1,_imageSize) ].character == 0);
1280 disstrU[p++] = c; //fontMap(c); 1272 CharacterColor currentForeground = _image[loc(x,y)].foregroundColor;
1281 if (doubleWidth) // assert((_image[loc(x+len,y)+1].character == 0)), see above if condition 1273 CharacterColor currentBackground = _image[loc(x,y)].backgroundColor;
1282 len++; // Skip trailing part of multi-column character 1274 quint8 currentRendition = _image[loc(x,y)].rendition;
1283 len++; 1275
1284 } 1276 while (x+len <= rightLowerX &&
1285 if ((x+len < _usedColumns) && (!_image[loc(x+len,y)].character)) 1277 _image[loc(x+len,y)].foregroundColor == currentForeground &&
1286 len++; // Adjust for trailing part of multi-column character 1278 _image[loc(x+len,y)].backgroundColor == currentBackground &&
1287 1279 _image[loc(x+len,y)].rendition == currentRendition &&
1288 bool save__fixedFont = _fixedFont; 1280 (_image[ qMin(loc(x+len,y)+1,_imageSize) ].character == 0) == doubleWidth &&
1289 if (lineDraw) 1281 isLineChar( c = _image[loc(x+len,y)].character) == lineDraw) // Assignment!
1282 {
1283 if (c)
1284 disstrU[p++] = c; //fontMap(c);
1285 if (doubleWidth) // assert((_image[loc(x+len,y)+1].character == 0)), see above if condition
1286 len++; // Skip trailing part of multi-column character
1287 len++;
1288 }
1289 if ((x+len < _usedColumns) && (!_image[loc(x+len,y)].character))
1290 len++; // Adjust for trailing part of multi-column character
1291
1292 bool save__fixedFont = _fixedFont;
1293 if (lineDraw)
1290 _fixedFont = false; 1294 _fixedFont = false;
1291 if (doubleWidth) 1295 if (doubleWidth)
1292 _fixedFont = false; 1296 _fixedFont = false;
1293 QString unistr(disstrU,p); 1297 QString unistr(disstrU,p);
1294 1298
1295 if (y < _lineProperties.size()) 1299 if (y < _lineProperties.size())
1296 { 1300 {
1297 if (_lineProperties[y] & LINE_DOUBLEWIDTH) { 1301 if (_lineProperties[y] & LINE_DOUBLEWIDTH) {
1298 paint.scale(2,1); 1302 paint.scale(2,1);
1299 } 1303 }
1300 1304
1301 if (_lineProperties[y] & LINE_DOUBLEHEIGHT) { 1305 if (_lineProperties[y] & LINE_DOUBLEHEIGHT) {
1302 paint.scale(1,2); 1306 paint.scale(1,2);
1303 } 1307 }
1304 } 1308 }
1305 1309
1306 //calculate the area in which the text will be drawn 1310 // calculate the area in which the text will be drawn
1307 QRect textArea = QRect( _leftMargin+tLx+_fontWidth*x , 1311 QRect textArea = QRect( _leftMargin+topLeftX+_fontWidth*x ,
1308 _topMargin+tLy+_fontHeight*y , 1312 _topMargin+topLeftY+_fontHeight*y ,
1309 _fontWidth*len, 1313 _fontWidth*len,
1310 _fontHeight); 1314 _fontHeight);
1311 1315
1312 //move the calculated area to take account of scaling applied to the painter. 1316 // move the calculated area to take account of scaling applied to the painter.
1313 //the position of the area from the origin (0,0) is scaled 1317 // the position of the area from the origin (0,0) is scaled
1314 //by the opposite of whatever 1318 // by the opposite of whatever
1315 //transformation has been applied to the painter. this ensures that 1319 // transformation has been applied to the painter. this ensures that
1316 //painting does actually start from textArea.topLeft() 1320 // painting does actually start from textArea.topLeft()
1317 //(instead of textArea.topLeft() * painter-scale) 1321 // (instead of textArea.topLeft() * painter-scale)
1318 QMatrix inverted = paint.matrix().inverted(); 1322 QMatrix inverted = paint.matrix().inverted();
1319 // textArea.moveTopLeft( inverted.map(textArea.topLeft()) ); 1323 textArea.moveCenter( inverted.map(textArea.center()) );
1320 textArea.moveCenter( inverted.map(textArea.center()) ); 1324
1321 1325
1322 1326 //paint text fragment
1323 //paint text fragment 1327 drawTextFragment( paint,
1324 drawTextFragment( paint, 1328 textArea,
1325 textArea, 1329 unistr,
1326 unistr, 1330 &_image[loc(x,y)] );
1327 &_image[loc(x,y)] ); //, 1331
1328 //0, 1332
1329 //!_isPrinting ); 1333 _fixedFont = save__fixedFont;
1330 1334
1331 _fixedFont = save__fixedFont; 1335 //reset back to single-width, single-height _lines
1332 1336 paint.resetMatrix();
1333 //reset back to single-width, single-height _lines 1337
1334 paint.resetMatrix(); 1338 if (y < _lineProperties.size()-1)
1335 1339 {
1336 if (y < _lineProperties.size()-1) 1340 //double-height _lines are represented by two adjacent _lines
1337 { 1341 //containing the same characters
1338 //double-height _lines are represented by two adjacent _lines 1342 //both _lines will have the LINE_DOUBLEHEIGHT attribute.
1339 //containing the same characters 1343 //If the current line has the LINE_DOUBLEHEIGHT attribute,
1340 //both _lines will have the LINE_DOUBLEHEIGHT attribute. 1344 //we can therefore skip the next line
1341 //If the current line has the LINE_DOUBLEHEIGHT attribute, 1345 if (_lineProperties[y] & LINE_DOUBLEHEIGHT)
1342 //we can therefore skip the next line 1346 y++;
1343 if (_lineProperties[y] & LINE_DOUBLEHEIGHT) 1347 }
1344 y++; 1348 x += len - 1;
1345 } 1349 } // for x
1346 1350 } // for y
1347 x += len - 1;
1348 }
1349 }
1350 delete [] disstrU; 1351 delete [] disstrU;
1351 } 1352 }
1352 1353
1353 void TerminalView::blinkEvent() 1354 void TerminalView::blinkEvent()
1354 { 1355 {
1360 update(); 1361 update();
1361 } 1362 }
1362 1363
1363 QRect TerminalView::imageToWidget(const QRect& imageArea) const 1364 QRect TerminalView::imageToWidget(const QRect& imageArea) const
1364 { 1365 {
1365 //qDebug("%s %d imageToWidget", __FILE__, __LINE__); 1366 //qDebug("%s %d imageToWidget", __FILE__, __LINE__);
1366 QRect result; 1367 QRect result;
1367 result.setLeft( _leftMargin + _fontWidth * imageArea.left() ); 1368 result.setLeft( _leftMargin + _fontWidth * imageArea.left() );
1368 result.setTop( _topMargin + _fontHeight * imageArea.top() ); 1369 result.setTop( _topMargin + _fontHeight * imageArea.top() );
1369 result.setWidth( _fontWidth * imageArea.width() ); 1370 result.setWidth( _fontWidth * imageArea.width() );
1370 result.setHeight( _fontHeight * imageArea.height() ); 1371 result.setHeight( _fontHeight * imageArea.height() );
1371 1372
1372 return result; 1373 return result;
1373 } 1374 }
1374 1375
1375 void TerminalView::blinkCursorEvent() 1376 void TerminalView::blinkCursorEvent()
1376 { 1377 {
1377 _cursorBlinking = !_cursorBlinking; 1378 _cursorBlinking = !_cursorBlinking;
1393 } 1394 }
1394 1395
1395 void TerminalView::propagateSize() 1396 void TerminalView::propagateSize()
1396 { 1397 {
1397 if (_isFixedSize) 1398 if (_isFixedSize)
1398 { 1399 {
1399 setSize(_columns, _lines); 1400 setSize(_columns, _lines);
1400 QWidget::setFixedSize(sizeHint()); 1401 QWidget::setFixedSize(sizeHint());
1401 parentWidget()->adjustSize(); 1402 parentWidget()->adjustSize();
1402 parentWidget()->setFixedSize(parentWidget()->sizeHint()); 1403 parentWidget()->setFixedSize(parentWidget()->sizeHint());
1403 return; 1404 return;
1404 } 1405 }
1405 if (_image) 1406 if (_image)
1406 updateImageSize(); 1407 updateImageSize();
1407 } 1408 }
1408 1409
1409 void TerminalView::updateImageSize() 1410 void TerminalView::updateImageSize()
1410 { 1411 {
1411 //qDebug("%s %d updateImageSize", __FILE__, __LINE__); 1412 //qDebug("%s %d updateImageSize", __FILE__, __LINE__);
1412 Character* oldimg = _image; 1413 Character* oldimg = _image;
1413 int oldlin = _lines; 1414 int oldlin = _lines;
1414 int oldcol = _columns; 1415 int oldcol = _columns;
1415 1416
1416 makeImage(); 1417 makeImage();
1418 1419
1419 // copy the old image to reduce flicker 1420 // copy the old image to reduce flicker
1420 int lines = qMin(oldlin,_lines); 1421 int lines = qMin(oldlin,_lines);
1421 int columns = qMin(oldcol,_columns); 1422 int columns = qMin(oldcol,_columns);
1422 1423
1423 //qDebug("%s %d updateImageSize", __FILE__, __LINE__); 1424 //qDebug("%s %d updateImageSize", __FILE__, __LINE__);
1424 if (oldimg) 1425 if (oldimg)
1425 { 1426 {
1426 for (int line = 0; line < lines; line++) 1427 for (int line = 0; line < lines; line++)
1427 { 1428 {
1428 memcpy((void*)&_image[_columns*line], 1429 memcpy((void*)&_image[_columns*line],
1429 (void*)&oldimg[oldcol*line],columns*sizeof(Character)); 1430 (void*)&oldimg[oldcol*line],columns*sizeof(Character));
1430 } 1431 }
1431 delete[] oldimg; 1432 delete[] oldimg;
1432 } 1433 }
1433 1434
1434 //qDebug("%s %d updateImageSize", __FILE__, __LINE__); 1435 //qDebug("%s %d updateImageSize", __FILE__, __LINE__);
1435 if (_screenWindow) 1436 if (_screenWindow)
1436 _screenWindow->setWindowLines(_lines); 1437 _screenWindow->setWindowLines(_lines);
1437 1438
1438 _resizing = (oldlin!=_lines) || (oldcol!=_columns); 1439 _resizing = (oldlin!=_lines) || (oldcol!=_columns);
1439 1440
1440 if ( _resizing ) 1441 if ( _resizing )
1441 { 1442 {
1442 //qDebug("%s %d updateImageSize", __FILE__, __LINE__); 1443 //qDebug("%s %d updateImageSize", __FILE__, __LINE__);
1443 showResizeNotification(); 1444 showResizeNotification();
1444 emit changedContentSizeSignal(_contentHeight, _contentWidth); // expose resizeEvent 1445 emit changedContentSizeSignal(_contentHeight, _contentWidth); // expose resizeEvent
1445 } 1446 }
1446 //qDebug("%s %d updateImageSize", __FILE__, __LINE__); 1447 //qDebug("%s %d updateImageSize", __FILE__, __LINE__);
1447 1448
1448 _resizing = false; 1449 _resizing = false;
1449 } 1450 }
1450 1451
1451 //showEvent and hideEvent are reimplemented here so that it appears to other classes that the 1452 //showEvent and hideEvent are reimplemented here so that it appears to other classes that the
1454 //this allows 1455 //this allows
1455 //TODO: Perhaps it would be better to have separate signals for show and hide instead of using 1456 //TODO: Perhaps it would be better to have separate signals for show and hide instead of using
1456 //the same signal as the one for a content size change 1457 //the same signal as the one for a content size change
1457 void TerminalView::showEvent(QShowEvent*) 1458 void TerminalView::showEvent(QShowEvent*)
1458 { 1459 {
1459 emit changedContentSizeSignal(_contentHeight,_contentWidth); 1460 emit changedContentSizeSignal(_contentHeight,_contentWidth);
1460 } 1461 }
1461 void TerminalView::hideEvent(QHideEvent*) 1462 void TerminalView::hideEvent(QHideEvent*)
1462 { 1463 {
1463 emit changedContentSizeSignal(_contentHeight,_contentWidth); 1464 emit changedContentSizeSignal(_contentHeight,_contentWidth);
1464 } 1465 }
1465 1466
1466 /* ------------------------------------------------------------------------- */ 1467 /* ------------------------------------------------------------------------- */
1467 /* */ 1468 /* */
1468 /* Scrollbar */ 1469 /* Scrollbar */
1470 /* ------------------------------------------------------------------------- */ 1471 /* ------------------------------------------------------------------------- */
1471 1472
1472 void TerminalView::scrollBarPositionChanged(int) 1473 void TerminalView::scrollBarPositionChanged(int)
1473 { 1474 {
1474 if ( !_screenWindow ) 1475 if ( !_screenWindow )
1475 return; 1476 return;
1476 1477
1477 _screenWindow->scrollTo( _scrollBar->value() ); 1478 _screenWindow->scrollTo( _scrollBar->value() );
1478 1479
1479 // if the thumb has been moved to the bottom of the _scrollBar then set 1480 // if the thumb has been moved to the bottom of the _scrollBar then set
1480 // the display to automatically track new output, 1481 // the display to automatically track new output,
1486 updateImage(); 1487 updateImage();
1487 } 1488 }
1488 1489
1489 void TerminalView::setScroll(int cursor, int slines) 1490 void TerminalView::setScroll(int cursor, int slines)
1490 { 1491 {
1491 //qDebug("%s %d setScroll", __FILE__, __LINE__); 1492 //qDebug("%s %d setScroll", __FILE__, __LINE__);
1492 // update _scrollBar if the range or value has changed, 1493 // update _scrollBar if the range or value has changed,
1493 // otherwise return 1494 // otherwise return
1494 // 1495 //
1495 // setting the range or value of a _scrollBar will always trigger 1496 // setting the range or value of a _scrollBar will always trigger
1496 // a repaint, so it should be avoided if it is not necessary 1497 // a repaint, so it should be avoided if it is not necessary
1497 if ( _scrollBar->minimum() == 0 && 1498 if ( _scrollBar->minimum() == 0 &&
1498 _scrollBar->maximum() == (slines - _lines) && 1499 _scrollBar->maximum() == (slines - _lines) &&
1499 _scrollBar->value() == cursor ) 1500 _scrollBar->value() == cursor )
1500 { 1501 {
1501 return; 1502 return;
1502 } 1503 }
1503 1504
1504 disconnect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int))); 1505 disconnect(_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(scrollBarPositionChanged(int)));
1505 _scrollBar->setRange(0,slines - _lines); 1506 _scrollBar->setRange(0,slines - _lines);
1506 _scrollBar->setSingleStep(1); 1507 _scrollBar->setSingleStep(1);
1507 _scrollBar->setPageStep(_lines); 1508 _scrollBar->setPageStep(_lines);
1510 } 1511 }
1511 1512
1512 void TerminalView::setScrollBarPosition(ScrollBarPosition position) 1513 void TerminalView::setScrollBarPosition(ScrollBarPosition position)
1513 { 1514 {
1514 if (_scrollbarLocation == position) { 1515 if (_scrollbarLocation == position) {
1515 // return; 1516 // return;
1516 } 1517 }
1517 1518
1518 if ( position == NoScrollBar ) 1519 if ( position == NoScrollBar )
1519 _scrollBar->hide(); 1520 _scrollBar->hide();
1520 else 1521 else
1521 _scrollBar->show(); 1522 _scrollBar->show();
1522 1523
1523 _topMargin = _leftMargin = 1; 1524 _topMargin = _leftMargin = 1;
1524 _scrollbarLocation = position; 1525 _scrollbarLocation = position;
1525 1526
1526 propagateSize(); 1527 propagateSize();
1528 } 1529 }
1529 1530
1530 void TerminalView::mousePressEvent(QMouseEvent* ev) 1531 void TerminalView::mousePressEvent(QMouseEvent* ev)
1531 { 1532 {
1532 if ( _possibleTripleClick && (ev->button()==Qt::LeftButton) ) { 1533 if ( _possibleTripleClick && (ev->button()==Qt::LeftButton) ) {
1533 mouseTripleClickEvent(ev); 1534 mouseTripleClickEvent(ev);
1534 return; 1535 return;
1535 } 1536 }
1536 1537
1537 if ( !contentsRect().contains(ev->pos()) ) return; 1538 if ( !contentsRect().contains(ev->pos()) ) return;
1538 1539
1539 if ( !_screenWindow ) return; 1540 if ( !_screenWindow ) return;
1540 1541
1542 int charColumn; 1543 int charColumn;
1543 getCharacterPosition(ev->pos(),charLine,charColumn); 1544 getCharacterPosition(ev->pos(),charLine,charColumn);
1544 QPoint pos = QPoint(charColumn,charLine); 1545 QPoint pos = QPoint(charColumn,charLine);
1545 1546
1546 if ( ev->button() == Qt::LeftButton) 1547 if ( ev->button() == Qt::LeftButton)
1547 { 1548 {
1548 _lineSelectionMode = false; 1549 _lineSelectionMode = false;
1549 _wordSelectionMode = false; 1550 _wordSelectionMode = false;
1550 1551
1551 emit isBusySelecting(true); // Keep it steady... 1552 emit isBusySelecting(true); // Keep it steady...
1552 // Drag only when the Control key is hold 1553 // Drag only when the Control key is hold
1553 bool selected = false; 1554 bool selected = false;
1554 1555
1555 // The receiver of the testIsSelected() signal will adjust 1556 // The receiver of the testIsSelected() signal will adjust
1556 // 'selected' accordingly. 1557 // 'selected' accordingly.
1557 //emit testIsSelected(pos.x(), pos.y(), selected); 1558 //emit testIsSelected(pos.x(), pos.y(), selected);
1558 1559
1559 selected = _screenWindow->isSelected(pos.x(),pos.y()); 1560 selected = _screenWindow->isSelected(pos.x(),pos.y());
1560 1561
1561 if ((!_ctrlDrag || ev->modifiers() & Qt::ControlModifier) && selected ) { 1562 if ((!_ctrlDrag || ev->modifiers() & Qt::ControlModifier) && selected ) {
1562 // The user clicked inside selected text 1563 // The user clicked inside selected text
1563 dragInfo.state = diPending; 1564 dragInfo.state = diPending;
1564 dragInfo.start = ev->pos(); 1565 dragInfo.start = ev->pos();
1565 } 1566 }
1566 else { 1567 else {
1567 // No reason to ever start a drag event 1568 // No reason to ever start a drag event
1568 dragInfo.state = diNone; 1569 dragInfo.state = diNone;
1569 1570
1570 _preserveLineBreaks = !( ( ev->modifiers() & Qt::ControlModifier ) && !(ev->modifiers() & Qt::AltModifier) ); 1571 _preserveLineBreaks = !( ( ev->modifiers() & Qt::ControlModifier ) && !(ev->modifiers() & Qt::AltModifier) );
1571 _columnSelectionMode = (ev->modifiers() & Qt::AltModifier) && (ev->modifiers() & Qt::ControlModifier); 1572 _columnSelectionMode = (ev->modifiers() & Qt::AltModifier) && (ev->modifiers() & Qt::ControlModifier);
1572 1573
1574 if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier))
1575 {
1576 _screenWindow->clearSelection();
1577
1578 //emit clearSelectionSignal();
1579 pos.ry() += _scrollBar->value();
1580 _iPntSel = _pntSel = pos;
1581 _actSel = 1; // left mouse button pressed but nothing selected yet.
1582
1583 }
1584 else
1585 {
1586 emit mouseSignal( 0, charColumn + 1, charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0);
1587 }
1588 }
1589 }
1590 else if ( ev->button() == Qt::MidButton )
1591 {
1592 if ( _mouseMarks || (!_mouseMarks && (ev->modifiers() & Qt::ShiftModifier)) )
1593 emitSelection(true,ev->modifiers() & Qt::ControlModifier);
1594 else
1595 emit mouseSignal( 1, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0);
1596 }
1597 else if ( ev->button() == Qt::RightButton )
1598 {
1573 if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier)) 1599 if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier))
1574 { 1600 {
1575 _screenWindow->clearSelection(); 1601 emit configureRequest( this,
1576 1602 ev->modifiers() & (Qt::ShiftModifier|Qt::ControlModifier),
1577 //emit clearSelectionSignal(); 1603 ev->pos()
1578 pos.ry() += _scrollBar->value(); 1604 );
1579 _iPntSel = _pntSel = pos; 1605 }
1580 _actSel = 1; // left mouse button pressed but nothing selected yet.
1581
1582 }
1583 else 1606 else
1584 { 1607 emit mouseSignal( 2, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0);
1585 emit mouseSignal( 0, charColumn + 1, charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0); 1608 }
1586 }
1587 }
1588 }
1589 else if ( ev->button() == Qt::MidButton )
1590 {
1591 if ( _mouseMarks || (!_mouseMarks && (ev->modifiers() & Qt::ShiftModifier)) )
1592 emitSelection(true,ev->modifiers() & Qt::ControlModifier);
1593 else
1594 emit mouseSignal( 1, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0);
1595 }
1596 else if ( ev->button() == Qt::RightButton )
1597 {
1598 if (_mouseMarks || (ev->modifiers() & Qt::ShiftModifier))
1599 {
1600 emit configureRequest( this,
1601 ev->modifiers() & (Qt::ShiftModifier|Qt::ControlModifier),
1602 ev->pos()
1603 );
1604 }
1605 else
1606 emit mouseSignal( 2, charColumn +1, charLine +1 +_scrollBar->value() -_scrollBar->maximum() , 0);
1607 }
1608 1609
1609 QWidget::mousePressEvent (ev); 1610 QWidget::mousePressEvent (ev);
1610 } 1611 }
1611 1612
1612 QList<QAction*> TerminalView::filterActions(const QPoint& position) 1613 QList<QAction*> TerminalView::filterActions(const QPoint& position)
1628 1629
1629 // handle filters 1630 // handle filters
1630 // change link hot-spot appearance on mouse-over 1631 // change link hot-spot appearance on mouse-over
1631 Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn); 1632 Filter::HotSpot* spot = _filterChain->hotSpotAt(charLine,charColumn);
1632 if ( spot && spot->type() == Filter::HotSpot::Link) 1633 if ( spot && spot->type() == Filter::HotSpot::Link)
1633 { 1634 {
1634 QRect previousHotspotArea = _mouseOverHotspotArea; 1635 QRect previousHotspotArea = _mouseOverHotspotArea;
1635 _mouseOverHotspotArea.setCoords( qMin(spot->startColumn() , spot->endColumn()) * _fontWidth, 1636 _mouseOverHotspotArea.setCoords( qMin(spot->startColumn() , spot->endColumn()) * _fontWidth,
1636 spot->startLine() * _fontHeight, 1637 spot->startLine() * _fontHeight,
1637 qMax(spot->startColumn() , spot->endColumn()) * _fontHeight, 1638 qMax(spot->startColumn() , spot->endColumn()) * _fontHeight,
1638 (spot->endLine()+1) * _fontHeight ); 1639 (spot->endLine()+1) * _fontHeight );
1639 1640
1640 // display tooltips when mousing over links 1641 // display tooltips when mousing over links
1641 // TODO: Extend this to work with filter types other than links 1642 // TODO: Extend this to work with filter types other than links
1642 const QString& tooltip = spot->tooltip(); 1643 const QString& tooltip = spot->tooltip();
1643 if ( !tooltip.isEmpty() ) 1644 if ( !tooltip.isEmpty() )
1644 { 1645 {
1645 QToolTip::showText( mapToGlobal(ev->pos()) , tooltip , this , _mouseOverHotspotArea ); 1646 QToolTip::showText( mapToGlobal(ev->pos()) , tooltip , this , _mouseOverHotspotArea );
1646 } 1647 }
1647 1648
1648 update( _mouseOverHotspotArea | previousHotspotArea ); 1649 update( _mouseOverHotspotArea | previousHotspotArea );
1649 } 1650 }
1650 else if ( _mouseOverHotspotArea.isValid() ) 1651 else if ( _mouseOverHotspotArea.isValid() )
1651 { 1652 {
1652 update( _mouseOverHotspotArea ); 1653 update( _mouseOverHotspotArea );
1653 // set hotspot area to an invalid rectangle 1654 // set hotspot area to an invalid rectangle
1654 _mouseOverHotspotArea = QRect(); 1655 _mouseOverHotspotArea = QRect();
1655 } 1656 }
1656 1657
1657 // for auto-hiding the cursor, we need mouseTracking 1658 // for auto-hiding the cursor, we need mouseTracking
1658 if (ev->buttons() == Qt::NoButton ) return; 1659 if (ev->buttons() == Qt::NoButton ) return;
1659 1660
1660 // if the terminal is interested in mouse movements 1661 // if the terminal is interested in mouse movements
1661 // then emit a mouse movement signal, unless the shift 1662 // then emit a mouse movement signal, unless the shift
1662 // key is being held down, which overrides this. 1663 // key is being held down, which overrides this.
1663 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) 1664 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
1664 { 1665 {
1665 int button = 3; 1666 int button = 3;
1666 if (ev->buttons() & Qt::LeftButton) 1667 if (ev->buttons() & Qt::LeftButton)
1667 button = 0; 1668 button = 0;
1668 if (ev->buttons() & Qt::MidButton) 1669 if (ev->buttons() & Qt::MidButton)
1669 button = 1; 1670 button = 1;
1670 if (ev->buttons() & Qt::RightButton) 1671 if (ev->buttons() & Qt::RightButton)
1671 button = 2; 1672 button = 2;
1672 1673
1673 1674
1674 emit mouseSignal( button, 1675 emit mouseSignal( button,
1675 charColumn + 1, 1676 charColumn + 1,
1676 charLine + 1 +_scrollBar->value() -_scrollBar->maximum(), 1677 charLine + 1 +_scrollBar->value() -_scrollBar->maximum(),
1677 1 ); 1678 1 );
1678 1679
1679 return; 1680 return;
1680 } 1681 }
1681 1682
1682 if (dragInfo.state == diPending) 1683 if (dragInfo.state == diPending)
1683 { 1684 {
1684 // we had a mouse down, but haven't confirmed a drag yet 1685 // we had a mouse down, but haven't confirmed a drag yet
1685 // if the mouse has moved sufficiently, we will confirm 1686 // if the mouse has moved sufficiently, we will confirm
1686 1687
1687 int distance = 10; //KGlobalSettings::dndEventDelay(); 1688 int distance = 10; //KGlobalSettings::dndEventDelay();
1688 if ( ev->x() > dragInfo.start.x() + distance || ev->x() < dragInfo.start.x() - distance || 1689 if ( ev->x() > dragInfo.start.x() + distance || ev->x() < dragInfo.start.x() - distance ||
1689 ev->y() > dragInfo.start.y() + distance || ev->y() < dragInfo.start.y() - distance) 1690 ev->y() > dragInfo.start.y() + distance || ev->y() < dragInfo.start.y() - distance)
1690 { 1691 {
1691 // we've left the drag square, we can start a real drag operation now 1692 // we've left the drag square, we can start a real drag operation now
1692 emit isBusySelecting(false); // Ok.. we can breath again. 1693 emit isBusySelecting(false); // Ok.. we can breath again.
1693 1694
1694 _screenWindow->clearSelection(); 1695 _screenWindow->clearSelection();
1695 doDrag(); 1696 doDrag();
1696 } 1697 }
1697 return; 1698 return;
1698 } 1699 }
1699 else if (dragInfo.state == diDragging) 1700 else if (dragInfo.state == diDragging)
1700 { 1701 {
1701 // this isn't technically needed because mouseMoveEvent is suppressed during 1702 // this isn't technically needed because mouseMoveEvent is suppressed during
1702 // Qt drag operations, replaced by dragMoveEvent 1703 // Qt drag operations, replaced by dragMoveEvent
1703 return; 1704 return;
1704 } 1705 }
1705 1706
1706 if (_actSel == 0) return; 1707 if (_actSel == 0) return;
1707 1708
1708 // don't extend selection while pasting 1709 // don't extend selection while pasting
1709 if (ev->buttons() & Qt::MidButton) return; 1710 if (ev->buttons() & Qt::MidButton) return;
1710 1711
1711 extendSelection( ev->pos() ); 1712 extendSelection( ev->pos() );
1712 } 1713 }
1713 1714
1721 void TerminalView::extendSelection(const QPoint& position) { 1722 void TerminalView::extendSelection(const QPoint& position) {
1722 QPoint pos = position; 1723 QPoint pos = position;
1723 1724
1724 if (!_screenWindow) { 1725 if (!_screenWindow) {
1725 return; 1726 return;
1726 } 1727 }
1727 1728
1728 QPoint tL = contentsRect().topLeft(); 1729 QPoint tL = contentsRect().topLeft();
1729 int tLx = tL.x(); 1730 int tLx = tL.x();
1730 int tLy = tL.y(); 1731 int tLy = tL.y();
1731 int scroll = _scrollBar->value(); 1732 int scroll = _scrollBar->value();
1735 // this widget. 1736 // this widget.
1736 1737
1737 // Adjust position within text area bounds. See FIXME above. 1738 // Adjust position within text area bounds. See FIXME above.
1738 if (pos.x() < tLx + _leftMargin) { 1739 if (pos.x() < tLx + _leftMargin) {
1739 pos.setX(tLx + _leftMargin); 1740 pos.setX(tLx + _leftMargin);
1740 } 1741 }
1741 if (pos.x() > tLx + _leftMargin + _usedColumns * _fontWidth - 1) { 1742 if (pos.x() > tLx + _leftMargin + _usedColumns * _fontWidth - 1) {
1742 pos.setX(tLx + _leftMargin + _usedColumns * _fontWidth); 1743 pos.setX(tLx + _leftMargin + _usedColumns * _fontWidth);
1743 } 1744 }
1744 if (pos.y() < tLy + _topMargin) { 1745 if (pos.y() < tLy + _topMargin) {
1745 pos.setY(tLy + _topMargin); 1746 pos.setY(tLy + _topMargin);
1746 } 1747 }
1747 if (pos.y() > tLy + _topMargin + _usedLines * _fontHeight - 1) { 1748 if (pos.y() > tLy + _topMargin + _usedLines * _fontHeight - 1) {
1748 pos.setY(tLy + _topMargin + _usedLines * _fontHeight - 1); 1749 pos.setY(tLy + _topMargin + _usedLines * _fontHeight - 1);
1749 } 1750 }
1750 1751
1751 if (pos.y() == tLy + _topMargin + _usedLines * _fontHeight - 1) { 1752 if (pos.y() == tLy + _topMargin + _usedLines * _fontHeight - 1) {
1752 _scrollBar->setValue(_scrollBar->value() + yMouseScroll); // scrollforward 1753 _scrollBar->setValue(_scrollBar->value() + yMouseScroll); // scrollforward
1753 } 1754 }
1754 if (pos.y() == tLy + _topMargin) { 1755 if (pos.y() == tLy + _topMargin) {
1755 _scrollBar->setValue(_scrollBar->value() - yMouseScroll); // scrollback 1756 _scrollBar->setValue(_scrollBar->value() - yMouseScroll); // scrollback
1756 } 1757 }
1757 1758
1758 int charColumn = 0; 1759 int charColumn = 0;
1759 int charLine = 0; 1760 int charLine = 0;
1760 getCharacterPosition(pos, charLine, charColumn); 1761 getCharacterPosition(pos, charLine, charColumn);
1761 1762
1766 QPoint _pntSelCorr = _pntSel; 1767 QPoint _pntSelCorr = _pntSel;
1767 _pntSelCorr.ry() -= _scrollBar->value(); 1768 _pntSelCorr.ry() -= _scrollBar->value();
1768 bool swapping = false; 1769 bool swapping = false;
1769 1770
1770 if (_wordSelectionMode) { 1771 if (_wordSelectionMode) {
1771 // Extend to word boundaries 1772 // Extend to word boundaries
1772 int i = 0; 1773 int i = 0;
1773 int selClass = 0; 1774 int selClass = 0;
1774 1775
1775 bool left_not_right = (here.y() < _iPntSelCorr.y() || 1776 bool left_not_right = (here.y() < _iPntSelCorr.y() ||
1776 (here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x())); 1777 (here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x()));
1777 bool old_left_not_right = (_pntSelCorr.y() < _iPntSelCorr.y() || 1778 bool old_left_not_right = (_pntSelCorr.y() < _iPntSelCorr.y() ||
1778 (_pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x())); 1779 (_pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x()));
1779 swapping = left_not_right != old_left_not_right; 1780 swapping = left_not_right != old_left_not_right;
1780 1781
1781 // Find left (left_not_right ? from here : from start) 1782 // Find left (left_not_right ? from here : from start)
1782 QPoint left = left_not_right ? here : _iPntSelCorr; 1783 QPoint left = left_not_right ? here : _iPntSelCorr;
1783 i = loc(left.x(), left.y()); 1784 i = loc(left.x(), left.y());
1784 if (i >= 0 && i <= _imageSize) { 1785 if (i >= 0 && i <= _imageSize) {
1785 selClass = charClass(_image[i].character); 1786 selClass = charClass(_image[i].character);
1786 while (((left.x() > 0) || (left.y() > 0 && (_lineProperties[left.y() - 1] & LINE_WRAPPED))) 1787 while (((left.x() > 0) || (left.y() > 0 && (_lineProperties[left.y() - 1] & LINE_WRAPPED)))
1787 && charClass(_image[i - 1].character) == selClass) { 1788 && charClass(_image[i - 1].character) == selClass) {
1788 i--; 1789 i--;
1789 if (left.x() > 0) { 1790 if (left.x() > 0) {
1790 left.rx()--; 1791 left.rx()--;
1791 } else { 1792 } else {
1792 left.rx() = _usedColumns - 1; 1793 left.rx() = _usedColumns - 1;
1793 left.ry()--; 1794 left.ry()--;
1794 } 1795 }
1795 } 1796 }
1796 } 1797 }
1797 1798
1798 // Find left (left_not_right ? from start : from here) 1799 // Find left (left_not_right ? from start : from here)
1799 QPoint right = left_not_right ? _iPntSelCorr : here; 1800 QPoint right = left_not_right ? _iPntSelCorr : here;
1800 i = loc(right.x(), right.y()); 1801 i = loc(right.x(), right.y());
1801 if (i >= 0 && i <= _imageSize) { 1802 if (i >= 0 && i <= _imageSize) {
1802 selClass = charClass(_image[i].character); 1803 selClass = charClass(_image[i].character);
1803 while (((right.x() < _usedColumns - 1) || (right.y() < _usedLines - 1 && (_lineProperties[right.y()] & LINE_WRAPPED))) 1804 while (((right.x() < _usedColumns - 1) || (right.y() < _usedLines - 1 && (_lineProperties[right.y()] & LINE_WRAPPED)))
1804 && charClass(_image[i + 1].character) == selClass) { 1805 && charClass(_image[i + 1].character) == selClass) {
1805 i++; 1806 i++;
1806 if (right.x() < _usedColumns - 1) { 1807 if (right.x() < _usedColumns - 1) {
1807 right.rx()++; 1808 right.rx()++;
1808 } else { 1809 } else {
1809 right.rx() = 0; 1810 right.rx() = 0;
1810 right.ry()++; 1811 right.ry()++;
1811 } 1812 }
1812 } 1813 }
1813 } 1814 }
1814 1815
1815 // Pick which is start (ohere) and which is extension (here) 1816 // Pick which is start (ohere) and which is extension (here)
1816 if (left_not_right) { 1817 if (left_not_right) {
1817 here = left; 1818 here = left;
1818 ohere = right; 1819 ohere = right;
1819 } else { 1820 } else {
1820 here = right; 1821 here = right;
1821 ohere = left; 1822 ohere = left;
1822 } 1823 }
1823 ohere.rx()++; 1824 ohere.rx()++;
1824 } 1825 }
1825 1826
1826 if (_lineSelectionMode) { 1827 if (_lineSelectionMode) {
1827 // Extend to complete line 1828 // Extend to complete line
1828 bool above_not_below = (here.y() < _iPntSelCorr.y()); 1829 bool above_not_below = (here.y() < _iPntSelCorr.y());
1829 1830
1830 QPoint above = above_not_below ? here : _iPntSelCorr; 1831 QPoint above = above_not_below ? here : _iPntSelCorr;
1831 QPoint below = above_not_below ? _iPntSelCorr : here; 1832 QPoint below = above_not_below ? _iPntSelCorr : here;
1832 1833
1833 while (above.y() > 0 && (_lineProperties[above.y() - 1] & LINE_WRAPPED)) { 1834 while (above.y() > 0 && (_lineProperties[above.y() - 1] & LINE_WRAPPED)) {
1834 above.ry()--; 1835 above.ry()--;
1835 } 1836 }
1836 while (below.y() < _usedLines - 1 && (_lineProperties[below.y()] & LINE_WRAPPED)) { 1837 while (below.y() < _usedLines - 1 && (_lineProperties[below.y()] & LINE_WRAPPED)) {
1837 below.ry()++; 1838 below.ry()++;
1838 } 1839 }
1839 1840
1840 above.setX(0); 1841 above.setX(0);
1841 below.setX(_usedColumns - 1); 1842 below.setX(_usedColumns - 1);
1842 1843
1843 // Pick which is start (ohere) and which is extension (here) 1844 // Pick which is start (ohere) and which is extension (here)
1844 if (above_not_below) { 1845 if (above_not_below) {
1845 here = above; 1846 here = above;
1846 ohere = below; 1847 ohere = below;
1847 } else { 1848 } else {
1848 here = below; 1849 here = below;
1849 ohere = above; 1850 ohere = above;
1850 } 1851 }
1851 1852
1852 QPoint newSelBegin = QPoint(ohere.x(), ohere.y()); 1853 QPoint newSelBegin = QPoint(ohere.x(), ohere.y());
1853 swapping = !(_tripleSelBegin == newSelBegin); 1854 swapping = !(_tripleSelBegin == newSelBegin);
1854 _tripleSelBegin = newSelBegin; 1855 _tripleSelBegin = newSelBegin;
1855 1856
1856 ohere.rx()++; 1857 ohere.rx()++;
1857 } 1858 }
1858 1859
1859 int offset = 0; 1860 int offset = 0;
1860 if (!_wordSelectionMode && !_lineSelectionMode) { 1861 if (!_wordSelectionMode && !_lineSelectionMode) {
1861 int i = 0; 1862 int i = 0;
1862 int selClass = 0; 1863 int selClass = 0;
1863 1864
1864 bool left_not_right = (here.y() < _iPntSelCorr.y() || 1865 bool left_not_right = (here.y() < _iPntSelCorr.y() ||
1865 (here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x())); 1866 (here.y() == _iPntSelCorr.y() && here.x() < _iPntSelCorr.x()));
1866 bool old_left_not_right = (_pntSelCorr.y() < _iPntSelCorr.y() || 1867 bool old_left_not_right = (_pntSelCorr.y() < _iPntSelCorr.y() ||
1867 (_pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x())); 1868 (_pntSelCorr.y() == _iPntSelCorr.y() && _pntSelCorr.x() < _iPntSelCorr.x()));
1868 swapping = left_not_right != old_left_not_right; 1869 swapping = left_not_right != old_left_not_right;
1869 1870
1870 // Find left (left_not_right ? from here : from start) 1871 // Find left (left_not_right ? from here : from start)
1871 QPoint left = left_not_right ? here : _iPntSelCorr; 1872 QPoint left = left_not_right ? here : _iPntSelCorr;
1872 1873
1873 // Find left (left_not_right ? from start : from here) 1874 // Find left (left_not_right ? from start : from here)
1874 QPoint right = left_not_right ? _iPntSelCorr : here; 1875 QPoint right = left_not_right ? _iPntSelCorr : here;
1875 if (right.x() > 0 && !_columnSelectionMode) { 1876 if (right.x() > 0 && !_columnSelectionMode) {
1876 i = loc(right.x(), right.y()); 1877 i = loc(right.x(), right.y());
1877 if (i >= 0 && i <= _imageSize) { 1878 if (i >= 0 && i <= _imageSize) {
1878 selClass = charClass(_image[i - 1].character); 1879 selClass = charClass(_image[i - 1].character);
1879 if (selClass == ' ') { 1880 if (selClass == ' ') {
1880 while (right.x() < _usedColumns - 1 && charClass(_image[i + 1].character) == selClass && (right.y() < _usedLines - 1) && 1881 while (right.x() < _usedColumns - 1 && charClass(_image[i + 1].character) == selClass && (right.y() < _usedLines - 1) &&
1881 !(_lineProperties[right.y()] & LINE_WRAPPED)) { 1882 !(_lineProperties[right.y()] & LINE_WRAPPED)) {
1882 i++; 1883 i++;
1883 right.rx()++; 1884 right.rx()++;
1884 } 1885 }
1885 if (right.x() < _usedColumns - 1) { 1886 if (right.x() < _usedColumns - 1) {
1886 right = left_not_right ? _iPntSelCorr : here; 1887 right = left_not_right ? _iPntSelCorr : here;
1887 } else { 1888 } else {
1888 right.rx()++; // will be balanced later because of offset=-1; 1889 right.rx()++; // will be balanced later because of offset=-1;
1889 } 1890 }
1890 } 1891 }
1891 } 1892 }
1892 } 1893 }
1893 1894
1894 // Pick which is start (ohere) and which is extension (here) 1895 // Pick which is start (ohere) and which is extension (here)
1895 if (left_not_right) { 1896 if (left_not_right) {
1896 here = left; 1897 here = left;
1897 ohere = right; 1898 ohere = right;
1898 offset = 0; 1899 offset = 0;
1899 } else { 1900 } else {
1900 here = right; 1901 here = right;
1901 ohere = left; 1902 ohere = left;
1902 offset = -1; 1903 offset = -1;
1903 } 1904 }
1904 } 1905 }
1905 1906
1906 if ((here == _pntSelCorr) && (scroll == _scrollBar->value())) { 1907 if ((here == _pntSelCorr) && (scroll == _scrollBar->value())) {
1907 return; // not moved 1908 return; // not moved
1908 } 1909 }
1909 1910
1910 if (here == ohere) { 1911 if (here == ohere) {
1911 return; // It's not left, it's not right. 1912 return; // It's not left, it's not right.
1912 } 1913 }
1913 1914
1914 if (_actSel < 2 || swapping) { 1915 if (_actSel < 2 || swapping) {
1915 if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) { 1916 if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) {
1916 _screenWindow->setSelectionStart(ohere.x(), ohere.y(), true); 1917 _screenWindow->setSelectionStart(ohere.x(), ohere.y(), true);
1917 } else { 1918 } else {
1918 _screenWindow->setSelectionStart(ohere.x() - 1 - offset , ohere.y(), false); 1919 _screenWindow->setSelectionStart(ohere.x() - 1 - offset , ohere.y(), false);
1919 } 1920 }
1920 1921
1921 } 1922 }
1922 1923
1923 _actSel = 2; // within selection 1924 _actSel = 2; // within selection
1924 _pntSel = here; 1925 _pntSel = here;
1925 _pntSel.ry() += _scrollBar->value(); 1926 _pntSel.ry() += _scrollBar->value();
1926 1927
1927 if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) { 1928 if (_columnSelectionMode && !_lineSelectionMode && !_wordSelectionMode) {
1928 _screenWindow->setSelectionEnd(here.x(), here.y()); 1929 _screenWindow->setSelectionEnd(here.x(), here.y());
1929 } else { 1930 } else {
1930 _screenWindow->setSelectionEnd(here.x() + offset, here.y()); 1931 _screenWindow->setSelectionEnd(here.x() + offset, here.y());
1931 } 1932 }
1932 } 1933 }
1933 1934
1934 void TerminalView::mouseReleaseEvent(QMouseEvent* ev) 1935 void TerminalView::mouseReleaseEvent(QMouseEvent* ev)
1935 { 1936 {
1936 if ( !_screenWindow ) 1937 if ( !_screenWindow )
1937 return; 1938 return;
1938 1939
1939 int charLine; 1940 int charLine;
1940 int charColumn; 1941 int charColumn;
1941 getCharacterPosition(ev->pos(),charLine,charColumn); 1942 getCharacterPosition(ev->pos(),charLine,charColumn);
1942 1943
1943 if ( ev->button() == Qt::LeftButton) 1944 if ( ev->button() == Qt::LeftButton)
1944 { 1945 {
1945 emit isBusySelecting(false); 1946 emit isBusySelecting(false);
1946 if(dragInfo.state == diPending) 1947 if(dragInfo.state == diPending)
1947 { 1948 {
1948 // We had a drag event pending but never confirmed. Kill selection 1949 // We had a drag event pending but never confirmed. Kill selection
1949 _screenWindow->clearSelection(); 1950 _screenWindow->clearSelection();
1950 //emit clearSelectionSignal(); 1951 //emit clearSelectionSignal();
1951 } 1952 }
1952 else 1953 else
1953 { 1954 {
1954 if ( _actSel > 1 ) 1955 if ( _actSel > 1 )
1955 { 1956 {
1956 setSelection( _screenWindow->selectedText(_preserveLineBreaks) ); 1957 setSelection( _screenWindow->selectedText(_preserveLineBreaks) );
1957 } 1958 }
1958 1959
1959 _actSel = 0; 1960 _actSel = 0;
1960 1961
1961 //FIXME: emits a release event even if the mouse is 1962 //FIXME: emits a release event even if the mouse is
1962 // outside the range. The procedure used in `mouseMoveEvent' 1963 // outside the range. The procedure used in `mouseMoveEvent'
1963 // applies here, too. 1964 // applies here, too.
1964 1965
1965 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) 1966 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
1966 emit mouseSignal( 3, // release 1967 emit mouseSignal( 3, // release
1967 charColumn + 1, 1968 charColumn + 1,
1968 charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0); 1969 charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 0);
1969 } 1970 }
1970 dragInfo.state = diNone; 1971 dragInfo.state = diNone;
1971 } 1972 }
1972 1973
1973 1974
1974 if ( !_mouseMarks && 1975 if ( !_mouseMarks &&
1975 ((ev->button() == Qt::RightButton && !(ev->modifiers() & Qt::ShiftModifier)) 1976 ((ev->button() == Qt::RightButton && !(ev->modifiers() & Qt::ShiftModifier))
1976 || ev->button() == Qt::MidButton) ) 1977 || ev->button() == Qt::MidButton) )
1977 { 1978 {
1978 emit mouseSignal( 3, 1979 emit mouseSignal( 3,
1979 charColumn + 1, 1980 charColumn + 1,
1980 charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 1981 charLine + 1 +_scrollBar->value() -_scrollBar->maximum() ,
1981 0); 1982 0);
1982 } 1983 }
1983 1984
1984 QWidget::mouseReleaseEvent(ev); 1985 QWidget::mouseReleaseEvent(ev);
1985 } 1986 }
1986 1987
1987 void TerminalView::getCharacterPosition(const QPoint& widgetPoint,int& line,int& column) const 1988 void TerminalView::getCharacterPosition(const QPoint& widgetPoint,int& line,int& column) const
1988 { 1989 {
1989 1990
1990 column = (widgetPoint.x() + _fontWidth/2 -contentsRect().left()-_leftMargin) / _fontWidth; 1991 column = (widgetPoint.x() + _fontWidth/2 -contentsRect().left()-_leftMargin) / _fontWidth;
1991 line = (widgetPoint.y()-contentsRect().top()-_topMargin) / _fontHeight; 1992 line = (widgetPoint.y()-contentsRect().top()-_topMargin) / _fontHeight;
1992 1993
1993 if ( line < 0 ) 1994 if ( line < 0 )
1994 line = 0; 1995 line = 0;
1995 if ( column < 0 ) 1996 if ( column < 0 )
1996 column = 0; 1997 column = 0;
1997 1998
1998 if ( line >= _usedLines ) 1999 if ( line >= _usedLines )
1999 line = _usedLines-1; 2000 line = _usedLines-1;
2000 2001
2001 // the column value returned can be equal to _usedColumns, which 2002 // the column value returned can be equal to _usedColumns, which
2002 // is the position just after the last character displayed in a line. 2003 // is the position just after the last character displayed in a line.
2003 // 2004 //
2004 // this is required so that the user can select characters in the right-most 2005 // this is required so that the user can select characters in the right-most
2005 // column (or left-most for right-to-left input) 2006 // column (or left-most for right-to-left input)
2006 if ( column > _usedColumns ) 2007 if ( column > _usedColumns )
2007 column = _usedColumns; 2008 column = _usedColumns;
2008 } 2009 }
2009 2010
2010 void TerminalView::updateLineProperties() 2011 void TerminalView::updateLineProperties()
2011 { 2012 {
2012 if ( !_screenWindow ) 2013 if ( !_screenWindow )
2013 return; 2014 return;
2014 2015
2015 _lineProperties = _screenWindow->getLineProperties(); 2016 _lineProperties = _screenWindow->getLineProperties();
2016 } 2017 }
2017 2018
2018 void TerminalView::mouseDoubleClickEvent(QMouseEvent* ev) 2019 void TerminalView::mouseDoubleClickEvent(QMouseEvent* ev)
2019 { 2020 {
2020 if ( ev->button() != Qt::LeftButton) return; 2021 if ( ev->button() != Qt::LeftButton) return;
2027 2028
2028 QPoint pos(charColumn,charLine); 2029 QPoint pos(charColumn,charLine);
2029 2030
2030 // pass on double click as two clicks. 2031 // pass on double click as two clicks.
2031 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier)) 2032 if (!_mouseMarks && !(ev->modifiers() & Qt::ShiftModifier))
2032 { 2033 {
2033 // Send just _ONE_ click event, since the first click of the double click 2034 // Send just _ONE_ click event, since the first click of the double click
2034 // was already sent by the click handler 2035 // was already sent by the click handler
2035 emit mouseSignal( 0, 2036 emit mouseSignal( 0,
2036 pos.x()+1, 2037 pos.x()+1,
2037 pos.y()+1 +_scrollBar->value() -_scrollBar->maximum(), 2038 pos.y()+1 +_scrollBar->value() -_scrollBar->maximum(),
2038 0 ); // left button 2039 0 ); // left button
2039 return; 2040 return;
2040 } 2041 }
2041 2042
2042 _screenWindow->clearSelection(); 2043 _screenWindow->clearSelection();
2043 QPoint bgnSel = pos; 2044 QPoint bgnSel = pos;
2044 QPoint endSel = pos; 2045 QPoint endSel = pos;
2045 int i = loc(bgnSel.x(),bgnSel.y()); 2046 int i = loc(bgnSel.x(),bgnSel.y());
2049 _wordSelectionMode = true; 2050 _wordSelectionMode = true;
2050 2051
2051 // find word boundaries... 2052 // find word boundaries...
2052 int selClass = charClass(_image[i].character); 2053 int selClass = charClass(_image[i].character);
2053 { 2054 {
2054 // find the start of the word 2055 // find the start of the word
2055 int x = bgnSel.x(); 2056 int x = bgnSel.x();
2056 while ( ((x>0) || (bgnSel.y()>0 && (_lineProperties[bgnSel.y()-1] & LINE_WRAPPED) )) 2057 while ( ((x>0) || (bgnSel.y()>0 && (_lineProperties[bgnSel.y()-1] & LINE_WRAPPED) ))
2057 && charClass(_image[i-1].character) == selClass ) 2058 && charClass(_image[i-1].character) == selClass )
2058 { 2059 {
2059 i--; 2060 i--;
2060 if (x>0) 2061 if (x>0)
2061 x--; 2062 x--;
2062 else 2063 else
2063 { 2064 {
2064 x=_usedColumns-1; 2065 x=_usedColumns-1;
2065 bgnSel.ry()--; 2066 bgnSel.ry()--;
2066 } 2067 }
2067 } 2068 }
2068 2069
2069 bgnSel.setX(x); 2070 bgnSel.setX(x);
2070 _screenWindow->setSelectionStart( bgnSel.x() , bgnSel.y() , false ); 2071 _screenWindow->setSelectionStart( bgnSel.x() , bgnSel.y() , false );
2071 2072
2072 // find the end of the word 2073 // find the end of the word
2073 i = loc( endSel.x(), endSel.y() ); 2074 i = loc( endSel.x(), endSel.y() );
2074 x = endSel.x(); 2075 x = endSel.x();
2075 while( ((x<_usedColumns-1) || (endSel.y()<_usedLines-1 && (_lineProperties[endSel.y()] & LINE_WRAPPED) )) 2076 while( ((x<_usedColumns-1) || (endSel.y()<_usedLines-1 && (_lineProperties[endSel.y()] & LINE_WRAPPED) ))
2076 && charClass(_image[i+1].character) == selClass ) 2077 && charClass(_image[i+1].character) == selClass )
2077 { 2078 {
2078 i++; 2079 i++;
2079 if (x<_usedColumns-1) 2080 if (x<_usedColumns-1)
2080 x++; 2081 x++;
2081 else 2082 else
2082 { 2083 {
2083 x=0; 2084 x=0;
2084 endSel.ry()++; 2085 endSel.ry()++;
2085 } 2086 }
2086 } 2087 }
2087 2088
2088 endSel.setX(x); 2089 endSel.setX(x);
2089 2090
2090 // In word selection mode don't select @ (64) if at end of word. 2091 // In word selection mode don't select @ (64) if at end of word.
2091 if ( ( QChar( _image[i].character ) == '@' ) && ( ( endSel.x() - bgnSel.x() ) > 0 ) ) 2092 if ( ( QChar( _image[i].character ) == '@' ) && ( ( endSel.x() - bgnSel.x() ) > 0 ) )
2092 endSel.setX( x - 1 ); 2093 endSel.setX( x - 1 );
2093 2094
2094 2095
2095 _actSel = 2; // within selection 2096 _actSel = 2; // within selection
2096 2097
2097 _screenWindow->setSelectionEnd( endSel.x() , endSel.y() ); 2098 _screenWindow->setSelectionEnd( endSel.x() , endSel.y() );
2098 2099
2099 setSelection( _screenWindow->selectedText(_preserveLineBreaks) ); 2100 setSelection( _screenWindow->selectedText(_preserveLineBreaks) );
2100 } 2101 }
2101 2102
2102 _possibleTripleClick=true; 2103 _possibleTripleClick=true;
2103 2104
2104 QTimer::singleShot(QApplication::doubleClickInterval(),this, 2105 QTimer::singleShot(QApplication::doubleClickInterval(),this,
2105 SLOT(tripleClickTimeout())); 2106 SLOT(tripleClickTimeout()));
2111 return; 2112 return;
2112 2113
2113 if ( _mouseMarks ) 2114 if ( _mouseMarks )
2114 _scrollBar->event(ev); 2115 _scrollBar->event(ev);
2115 else 2116 else
2116 { 2117 {
2117 int charLine; 2118 int charLine;
2118 int charColumn; 2119 int charColumn;
2119 getCharacterPosition( ev->pos() , charLine , charColumn ); 2120 getCharacterPosition( ev->pos() , charLine , charColumn );
2120 2121
2121 emit mouseSignal( ev->delta() > 0 ? 4 : 5, 2122 emit mouseSignal( ev->delta() > 0 ? 4 : 5,
2122 charColumn + 1, 2123 charColumn + 1,
2123 charLine + 1 +_scrollBar->value() -_scrollBar->maximum() , 2124 charLine + 1 +_scrollBar->value() -_scrollBar->maximum() ,
2124 0); 2125 0);
2125 } 2126 }
2126 } 2127 }
2127 2128
2128 void TerminalView::tripleClickTimeout() 2129 void TerminalView::tripleClickTimeout()
2129 { 2130 {
2130 _possibleTripleClick=false; 2131 _possibleTripleClick=false;
2149 2150
2150 while (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) ) 2151 while (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) )
2151 _iPntSel.ry()--; 2152 _iPntSel.ry()--;
2152 2153
2153 if (_tripleClickMode == SelectForwardsFromCursor) { 2154 if (_tripleClickMode == SelectForwardsFromCursor) {
2154 // find word boundary start 2155 // find word boundary start
2155 int i = loc(_iPntSel.x(),_iPntSel.y()); 2156 int i = loc(_iPntSel.x(),_iPntSel.y());
2156 int selClass = charClass(_image[i].character); 2157 int selClass = charClass(_image[i].character);
2157 int x = _iPntSel.x(); 2158 int x = _iPntSel.x();
2158 2159
2159 while ( ((x>0) || 2160 while ( ((x>0) ||
2160 (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) ) 2161 (_iPntSel.y()>0 && (_lineProperties[_iPntSel.y()-1] & LINE_WRAPPED) )
2161 ) 2162 )
2162 && charClass(_image[i-1].character) == selClass ) 2163 && charClass(_image[i-1].character) == selClass )
2163 { 2164 {
2164 i--; 2165 i--;
2165 if (x>0) 2166 if (x>0)
2166 x--; 2167 x--;
2167 else 2168 else
2168 { 2169 {
2169 x=_columns-1; 2170 x=_columns-1;
2170 _iPntSel.ry()--; 2171 _iPntSel.ry()--;
2171 } 2172 }
2172 } 2173 }
2173 2174
2174 _screenWindow->setSelectionStart( x , _iPntSel.y() , false ); 2175 _screenWindow->setSelectionStart( x , _iPntSel.y() , false );
2175 _tripleSelBegin = QPoint( x, _iPntSel.y() ); 2176 _tripleSelBegin = QPoint( x, _iPntSel.y() );
2176 } 2177 }
2177 else if (_tripleClickMode == SelectWholeLine) { 2178 else if (_tripleClickMode == SelectWholeLine) {
2178 _screenWindow->setSelectionStart( 0 , _iPntSel.y() , false ); 2179 _screenWindow->setSelectionStart( 0 , _iPntSel.y() , false );
2179 _tripleSelBegin = QPoint( 0, _iPntSel.y() ); 2180 _tripleSelBegin = QPoint( 0, _iPntSel.y() );
2180 } 2181 }
2181 2182
2182 while (_iPntSel.y()<_lines-1 && (_lineProperties[_iPntSel.y()] & LINE_WRAPPED) ) 2183 while (_iPntSel.y()<_lines-1 && (_lineProperties[_iPntSel.y()] & LINE_WRAPPED) )
2183 _iPntSel.ry()++; 2184 _iPntSel.ry()++;
2184 2185
2185 _screenWindow->setSelectionEnd( _columns - 1 , _iPntSel.y() ); 2186 _screenWindow->setSelectionEnd( _columns - 1 , _iPntSel.y() );
2194 2195
2195 bool TerminalView::focusNextPrevChild( bool next ) 2196 bool TerminalView::focusNextPrevChild( bool next )
2196 { 2197 {
2197 if (next) 2198 if (next)
2198 return false; // This disables changing the active part in konqueror 2199 return false; // This disables changing the active part in konqueror
2199 // when pressing Tab 2200 // when pressing Tab
2200 return QWidget::focusNextPrevChild( next ); 2201 return QWidget::focusNextPrevChild( next );
2201 } 2202 }
2202 2203
2203 2204
2204 int TerminalView::charClass(quint16 ch) const 2205 int TerminalView::charClass(quint16 ch) const
2205 { 2206 {
2206 QChar qch=QChar(ch); 2207 QChar qch=QChar(ch);
2207 if ( qch.isSpace() ) return ' '; 2208 if ( qch.isSpace() ) return ' ';
2208 2209
2209 if ( qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive ) ) 2210 if ( qch.isLetterOrNumber() || _wordCharacters.contains(qch, Qt::CaseInsensitive ) )
2210 return 'a'; 2211 return 'a';
2211 2212
2212 // Everything else is weird 2213 // Everything else is weird
2213 return 1; 2214 return 1;
2214 } 2215 }
2215 2216
2216 void TerminalView::setWordCharacters(const QString& wc) 2217 void TerminalView::setWordCharacters(const QString& wc)
2217 { 2218 {
2218 _wordCharacters = wc; 2219 _wordCharacters = wc;
2219 } 2220 }
2220 2221
2221 void TerminalView::setUsesMouse(bool on) 2222 void TerminalView::setUsesMouse(bool on)
2222 { 2223 {
2223 _mouseMarks = on; 2224 _mouseMarks = on;
2224 setCursor( _mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor ); 2225 setCursor( _mouseMarks ? Qt::IBeamCursor : Qt::ArrowCursor );
2225 } 2226 }
2226 bool TerminalView::usesMouse() const 2227 bool TerminalView::usesMouse() const
2227 { 2228 {
2228 return _mouseMarks; 2229 return _mouseMarks;
2229 } 2230 }
2230 2231
2231 /* ------------------------------------------------------------------------- */ 2232 /* ------------------------------------------------------------------------- */
2232 /* */ 2233 /* */
2233 /* Clipboard */ 2234 /* Clipboard */
2237 #undef KeyPress 2238 #undef KeyPress
2238 2239
2239 void TerminalView::emitSelection(bool useXselection,bool appendReturn) 2240 void TerminalView::emitSelection(bool useXselection,bool appendReturn)
2240 { 2241 {
2241 if ( !_screenWindow ) 2242 if ( !_screenWindow )
2242 return; 2243 return;
2243 2244
2244 // Paste Clipboard by simulating keypress events 2245 // Paste Clipboard by simulating keypress events
2245 QString text = QApplication::clipboard()->text(useXselection ? QClipboard::Selection : 2246 QString text = QApplication::clipboard()->text(useXselection ? QClipboard::Selection :
2246 QClipboard::Clipboard); 2247 QClipboard::Clipboard);
2247 if(appendReturn) 2248 if(appendReturn)
2248 text.append("\r"); 2249 text.append("\r");
2249 if ( ! text.isEmpty() ) 2250 if ( ! text.isEmpty() )
2250 { 2251 {
2251 text.replace("\n", "\r"); 2252 text.replace("\n", "\r");
2252 QKeyEvent e(QEvent::KeyPress, 0, Qt::NoModifier, text); 2253 QKeyEvent e(QEvent::KeyPress, 0, Qt::NoModifier, text);
2253 emit keyPressedSignal(&e); // expose as a big fat keypress event 2254 emit keyPressedSignal(&e); // expose as a big fat keypress event
2254 2255
2255 _screenWindow->clearSelection(); 2256 _screenWindow->clearSelection();
2256 } 2257 }
2257 } 2258 }
2258 2259
2259 void TerminalView::setSelection(const QString& t) 2260 void TerminalView::setSelection(const QString& t)
2260 { 2261 {
2261 QApplication::clipboard()->setText(t, QClipboard::Selection); 2262 QApplication::clipboard()->setText(t, QClipboard::Selection);
2262 } 2263 }
2263 2264
2264 void TerminalView::copyClipboard() 2265 void TerminalView::copyClipboard()
2265 { 2266 {
2266 if ( !_screenWindow ) 2267 if ( !_screenWindow )
2267 return; 2268 return;
2268 2269
2269 QString text = _screenWindow->selectedText(_preserveLineBreaks); 2270 QString text = _screenWindow->selectedText(_preserveLineBreaks);
2270 QApplication::clipboard()->setText(text); 2271 QApplication::clipboard()->setText(text);
2271 } 2272 }
2272 2273
2286 /* */ 2287 /* */
2287 /* ------------------------------------------------------------------------- */ 2288 /* ------------------------------------------------------------------------- */
2288 2289
2289 void TerminalView::keyPressEvent( QKeyEvent* event ) 2290 void TerminalView::keyPressEvent( QKeyEvent* event )
2290 { 2291 {
2291 //qDebug("%s %d keyPressEvent and key is %d", __FILE__, __LINE__, event->key()); 2292 //qDebug("%s %d keyPressEvent and key is %d", __FILE__, __LINE__, event->key());
2292 2293
2293 bool emitKeyPressSignal = true; 2294 bool emitKeyPressSignal = true;
2294 2295
2295 // Keyboard-based navigation 2296 // Keyboard-based navigation
2296 if ( event->modifiers() == Qt::ShiftModifier ) 2297 if ( event->modifiers() == Qt::ShiftModifier )
2297 { 2298 {
2298 bool update = true; 2299 bool update = true;
2299 2300
2300 if ( event->key() == Qt::Key_PageUp ) 2301 if ( event->key() == Qt::Key_PageUp )
2301 { 2302 {
2302 //qDebug("%s %d pageup", __FILE__, __LINE__); 2303 //qDebug("%s %d pageup", __FILE__, __LINE__);
2303 _screenWindow->scrollBy( ScreenWindow::ScrollPages , -1 ); 2304 _screenWindow->scrollBy( ScreenWindow::ScrollPages , -1 );
2304 } 2305 }
2305 else if ( event->key() == Qt::Key_PageDown ) 2306 else if ( event->key() == Qt::Key_PageDown )
2306 { 2307 {
2307 //qDebug("%s %d pagedown", __FILE__, __LINE__); 2308 //qDebug("%s %d pagedown", __FILE__, __LINE__);
2308 _screenWindow->scrollBy( ScreenWindow::ScrollPages , 1 ); 2309 _screenWindow->scrollBy( ScreenWindow::ScrollPages , 1 );
2309 } 2310 }
2310 else if ( event->key() == Qt::Key_Up ) 2311 else if ( event->key() == Qt::Key_Up )
2311 { 2312 {
2312 //qDebug("%s %d keyup", __FILE__, __LINE__); 2313 //qDebug("%s %d keyup", __FILE__, __LINE__);
2313 _screenWindow->scrollBy( ScreenWindow::ScrollLines , -1 ); 2314 _screenWindow->scrollBy( ScreenWindow::ScrollLines , -1 );
2314 } 2315 }
2315 else if ( event->key() == Qt::Key_Down ) 2316 else if ( event->key() == Qt::Key_Down )
2316 { 2317 {
2317 //qDebug("%s %d keydown", __FILE__, __LINE__); 2318 //qDebug("%s %d keydown", __FILE__, __LINE__);
2318 _screenWindow->scrollBy( ScreenWindow::ScrollLines , 1 ); 2319 _screenWindow->scrollBy( ScreenWindow::ScrollLines , 1 );
2319 } 2320 }
2320 else { 2321 else {
2321 update = false; 2322 update = false;
2322 } 2323 }
2323 2324
2324 if ( update ) 2325 if ( update )
2325 { 2326 {
2326 //qDebug("%s %d updating", __FILE__, __LINE__); 2327 //qDebug("%s %d updating", __FILE__, __LINE__);
2327 _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() ); 2328 _screenWindow->setTrackOutput( _screenWindow->atEndOfOutput() );
2328 2329
2329 updateLineProperties(); 2330 updateLineProperties();
2330 updateImage(); 2331 updateImage();
2331 2332
2332 // do not send key press to terminal 2333 // do not send key press to terminal
2333 emitKeyPressSignal = false; 2334 emitKeyPressSignal = false;
2334 } 2335 }
2335 } 2336 }
2336 2337
2337 _screenWindow->setTrackOutput( true ); 2338 _screenWindow->setTrackOutput( true );
2338 2339
2339 _actSel=0; // Key stroke implies a screen update, so TerminalDisplay won't 2340 _actSel=0; // Key stroke implies a screen update, so TerminalDisplay won't
2340 // know where the current selection is. 2341 // know where the current selection is.
2341 2342
2342 if (_hasBlinkingCursor) 2343 if (_hasBlinkingCursor)
2343 { 2344 {
2344 _blinkCursorTimer->start(BLINK_DELAY); 2345 _blinkCursorTimer->start(BLINK_DELAY);
2345 if (_cursorBlinking) 2346 if (_cursorBlinking)
2346 blinkCursorEvent(); 2347 blinkCursorEvent();
2347 else 2348 else
2348 _cursorBlinking = false; 2349 _cursorBlinking = false;
2349 } 2350 }
2350 2351
2351 if ( emitKeyPressSignal && !_readonly ) 2352 if ( emitKeyPressSignal && !_readonly )
2352 emit keyPressedSignal(event); 2353 emit keyPressedSignal(event);
2353 2354
2354 if (_readonly) { 2355 if (_readonly) {
2355 event->ignore(); 2356 event->ignore();
2356 } 2357 }
2357 else { 2358 else {
2358 event->accept(); 2359 event->accept();
2359 } 2360 }
2360 } 2361 }
2361 2362
2362 void TerminalView::inputMethodEvent( QInputMethodEvent* event ) 2363 void TerminalView::inputMethodEvent( QInputMethodEvent* event )
2363 { 2364 {
2364 QKeyEvent keyEvent(QEvent::KeyPress,0,Qt::NoModifier,event->commitString()); 2365 QKeyEvent keyEvent(QEvent::KeyPress,0,Qt::NoModifier,event->commitString());
2365 emit keyPressedSignal(&keyEvent); 2366 emit keyPressedSignal(&keyEvent);
2366 2367
2367 _inputMethodData.preeditString = event->preeditString(); 2368 _inputMethodData.preeditString = event->preeditString();
2368 update(preeditRect() | _inputMethodData.previousPreeditRect); 2369 update(preeditRect() | _inputMethodData.previousPreeditRect);
2369 2370
2370 event->accept(); 2371 event->accept();
2371 } 2372 }
2372 QVariant TerminalView::inputMethodQuery( Qt::InputMethodQuery query ) const 2373 QVariant TerminalView::inputMethodQuery( Qt::InputMethodQuery query ) const
2373 { 2374 {
2374 const QPoint cursorPos = _screenWindow ? _screenWindow->cursorPosition() : QPoint(0,0); 2375 const QPoint cursorPos = _screenWindow ? _screenWindow->cursorPosition() : QPoint(0,0);
2375 switch ( query ) 2376 switch ( query )
2376 { 2377 {
2377 case Qt::ImMicroFocus: 2378 case Qt::ImMicroFocus:
2378 return imageToWidget(QRect(cursorPos.x(),cursorPos.y(),1,1)); 2379 return imageToWidget(QRect(cursorPos.x(),cursorPos.y(),1,1));
2379 break; 2380 break;
2380 case Qt::ImFont: 2381 case Qt::ImFont:
2381 return font(); 2382 return font();
2382 break; 2383 break;
2383 case Qt::ImCursorPosition: 2384 case Qt::ImCursorPosition:
2384 // return the cursor position within the current line 2385 // return the cursor position within the current line
2385 return cursorPos.x(); 2386 return cursorPos.x();
2386 break; 2387 break;
2387 case Qt::ImSurroundingText: 2388 case Qt::ImSurroundingText:
2388 { 2389 {
2389 // return the text from the current line 2390 // return the text from the current line
2390 QString lineText; 2391 QString lineText;
2391 QTextStream stream(&lineText); 2392 QTextStream stream(&lineText);
2392 PlainTextDecoder decoder; 2393 PlainTextDecoder decoder;
2393 decoder.begin(&stream); 2394 decoder.begin(&stream);
2394 decoder.decodeLine(&_image[loc(0,cursorPos.y())],_usedColumns,_lineProperties[cursorPos.y()]); 2395 decoder.decodeLine(&_image[loc(0,cursorPos.y())],_usedColumns,_lineProperties[cursorPos.y()]);
2395 decoder.end(); 2396 decoder.end();
2396 return lineText; 2397 return lineText;
2397 } 2398 }
2398 break; 2399 break;
2399 case Qt::ImCurrentSelection: 2400 case Qt::ImCurrentSelection:
2400 return QString(); 2401 return QString();
2401 break; 2402 break;
2402 default: 2403 default:
2403 break; 2404 break;
2404 } 2405 }
2405 2406
2406 return QVariant(); 2407 return QVariant();
2407 } 2408 }
2408 2409
2409 bool TerminalView::event( QEvent *e ) 2410 bool TerminalView::event( QEvent *e )
2410 { 2411 {
2411 if ( e->type() == QEvent::ShortcutOverride ) 2412 if ( e->type() == QEvent::ShortcutOverride )
2412 { 2413 {
2413 QKeyEvent* keyEvent = static_cast<QKeyEvent *>( e ); 2414 QKeyEvent* keyEvent = static_cast<QKeyEvent *>( e );
2414 2415
2415 // a check to see if keyEvent->text() is empty is used 2416 // a check to see if keyEvent->text() is empty is used
2416 // to avoid intercepting the press of the modifier key on its own. 2417 // to avoid intercepting the press of the modifier key on its own.
2417 // 2418 //
2418 // this is important as it allows a press and release of the Alt key 2419 // this is important as it allows a press and release of the Alt key
2419 // on its own to focus the menu bar, making it possible to 2420 // on its own to focus the menu bar, making it possible to
2420 // work with the menu without using the mouse 2421 // work with the menu without using the mouse
2421 if ( (keyEvent->modifiers() == Qt::AltModifier) && 2422 if ( (keyEvent->modifiers() == Qt::AltModifier) &&
2422 !keyEvent->text().isEmpty() ) 2423 !keyEvent->text().isEmpty() )
2423 { 2424 {
2424 keyEvent->accept(); 2425 keyEvent->accept();
2425 return true; 2426 return true;
2426 } 2427 }
2427 2428
2428 // Override any of the following shortcuts because 2429 // Override any of the following shortcuts because
2429 // they are needed by the terminal 2430 // they are needed by the terminal
2430 int keyCode = keyEvent->key() | keyEvent->modifiers(); 2431 int keyCode = keyEvent->key() | keyEvent->modifiers();
2431 switch ( keyCode ) 2432 switch ( keyCode )
2432 { 2433 {
2433 // list is taken from the QLineEdit::event() code 2434 // list is taken from the QLineEdit::event() code
2434 case Qt::Key_Tab: 2435 case Qt::Key_Tab:
2435 case Qt::Key_Delete: 2436 case Qt::Key_Delete:
2436 case Qt::Key_Home: 2437 case Qt::Key_Home:
2437 case Qt::Key_End: 2438 case Qt::Key_End:
2438 case Qt::Key_Backspace: 2439 case Qt::Key_Backspace:
2439 case Qt::Key_Left: 2440 case Qt::Key_Left:
2440 case Qt::Key_Right: 2441 case Qt::Key_Right:
2441 keyEvent->accept(); 2442 keyEvent->accept();
2442 return true; 2443 return true;
2443 } 2444 }
2444 } 2445 }
2445 return QWidget::event( e ); 2446 return QWidget::event( e );
2446 } 2447 }
2447 2448
2448 void TerminalView::setBellMode(int mode) 2449 void TerminalView::setBellMode(int mode)
2449 { 2450 {
2450 _bellMode=mode; 2451 _bellMode=mode;
2451 } 2452 }
2452 2453
2453 void TerminalView::enableBell() 2454 void TerminalView::enableBell()
2454 { 2455 {
2455 _allowBell = true; 2456 _allowBell = true;
2456 } 2457 }
2457 2458
2458 void TerminalView::bell(const QString&) 2459 void TerminalView::bell(const QString&)
2459 { 2460 {
2460 if (_bellMode==NoBell) return; 2461 if (_bellMode==NoBell) return;
2461 2462
2462 //limit the rate at which bells can occur 2463 //limit the rate at which bells can occur
2463 //...mainly for sound effects where rapid bells in sequence 2464 //...mainly for sound effects where rapid bells in sequence
2464 //produce a horrible noise 2465 //produce a horrible noise
2465 if ( _allowBell ) 2466 if ( _allowBell )
2466 { 2467 {
2467 _allowBell = false; 2468 _allowBell = false;
2468 QTimer::singleShot(500,this,SLOT(enableBell())); 2469 QTimer::singleShot(500,this,SLOT(enableBell()));
2469 2470
2470 if (_bellMode==SystemBeepBell) 2471 if (_bellMode==SystemBeepBell)
2471 { 2472 {
2472 // KNotification::beep(); 2473 // KNotification::beep();
2473 } 2474 }
2474 else if (_bellMode==NotifyBell) 2475 else if (_bellMode==NotifyBell)
2475 { 2476 {
2476 // KNotification::event("BellVisible", message,QPixmap(),this); 2477 // KNotification::event("BellVisible", message,QPixmap(),this);
2477 } 2478 }
2478 else if (_bellMode==VisualBell) 2479 else if (_bellMode==VisualBell)
2479 { 2480 {
2480 swapColorTable(); 2481 swapColorTable();
2481 QTimer::singleShot(200,this,SLOT(swapColorTable())); 2482 QTimer::singleShot(200,this,SLOT(swapColorTable()));
2482 } 2483 }
2483 } 2484 }
2484 } 2485 }
2485 2486
2486 void TerminalView::swapColorTable() 2487 void TerminalView::swapColorTable()
2487 { 2488 {
2488 ColorEntry color = _colorTable[1]; 2489 ColorEntry color = _colorTable[1];
2494 2495
2495 void TerminalView::clearImage() 2496 void TerminalView::clearImage()
2496 { 2497 {
2497 // We initialize _image[_imageSize] too. See makeImage() 2498 // We initialize _image[_imageSize] too. See makeImage()
2498 for (int i = 0; i <= _imageSize; i++) 2499 for (int i = 0; i <= _imageSize; i++)
2499 { 2500 {
2500 _image[i].character = ' '; 2501 _image[i].character = ' ';
2501 _image[i].foregroundColor = CharacterColor(COLOR_SPACE_DEFAULT, 2502 _image[i].foregroundColor = CharacterColor(COLOR_SPACE_DEFAULT,
2502 DEFAULT_FORE_COLOR); 2503 DEFAULT_FORE_COLOR);
2503 _image[i].backgroundColor = CharacterColor(COLOR_SPACE_DEFAULT, 2504 _image[i].backgroundColor = CharacterColor(COLOR_SPACE_DEFAULT,
2504 DEFAULT_BACK_COLOR); 2505 DEFAULT_BACK_COLOR);
2505 _image[i].rendition = DEFAULT_RENDITION; 2506 _image[i].rendition = DEFAULT_RENDITION;
2506 } 2507 }
2507 } 2508 }
2508 2509
2509 void TerminalView::calcGeometry() 2510 void TerminalView::calcGeometry()
2510 { 2511 {
2511 _scrollBar->resize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent), 2512 _scrollBar->resize(QApplication::style()->pixelMetric(QStyle::PM_ScrollBarExtent),
2512 contentsRect().height()); 2513 contentsRect().height());
2513 switch(_scrollbarLocation) 2514 switch(_scrollbarLocation)
2514 { 2515 {
2515 case NoScrollBar : 2516 case NoScrollBar :
2516 _leftMargin = DEFAULT_LEFT_MARGIN; 2517 _leftMargin = DEFAULT_LEFT_MARGIN;
2517 _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN; 2518 _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN;
2518 break; 2519 break;
2519 case ScrollBarLeft : 2520 case ScrollBarLeft :
2520 _leftMargin = DEFAULT_LEFT_MARGIN + _scrollBar->width(); 2521 _leftMargin = DEFAULT_LEFT_MARGIN + _scrollBar->width();
2521 _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width(); 2522 _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width();
2522 _scrollBar->move(contentsRect().topLeft()); 2523 _scrollBar->move(contentsRect().topLeft());
2523 break; 2524 break;
2524 case ScrollBarRight: 2525 case ScrollBarRight:
2525 _leftMargin = DEFAULT_LEFT_MARGIN; 2526 _leftMargin = DEFAULT_LEFT_MARGIN;
2526 _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width(); 2527 _contentWidth = contentsRect().width() - 2 * DEFAULT_LEFT_MARGIN - _scrollBar->width();
2527 _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width()-1,0)); 2528 _scrollBar->move(contentsRect().topRight() - QPoint(_scrollBar->width()-1,0));
2528 break; 2529 break;
2529 } 2530 }
2530 2531
2531 _topMargin = DEFAULT_TOP_MARGIN; 2532 _topMargin = DEFAULT_TOP_MARGIN;
2532 _contentHeight = contentsRect().height() - 2 * DEFAULT_TOP_MARGIN + /* mysterious */ 1; 2533 _contentHeight = contentsRect().height() - 2 * DEFAULT_TOP_MARGIN + /* mysterious */ 1;
2533 2534
2534 if (!_isFixedSize) 2535 if (!_isFixedSize)
2535 { 2536 {
2536 // ensure that display is always at least one column wide 2537 // ensure that display is always at least one column wide
2537 _columns = qMax(1,_contentWidth / _fontWidth); 2538 _columns = qMax(1,_contentWidth / _fontWidth);
2538 _usedColumns = qMin(_usedColumns,_columns); 2539 _usedColumns = qMin(_usedColumns,_columns);
2539 2540
2540 // ensure that display is always at least one line high 2541 // ensure that display is always at least one line high
2541 _lines = qMax(1,_contentHeight / _fontHeight); 2542 _lines = qMax(1,_contentHeight / _fontHeight);
2542 _usedLines = qMin(_usedLines,_lines); 2543 _usedLines = qMin(_usedLines,_lines);
2543 } 2544 }
2544 } 2545 }
2545 2546
2546 void TerminalView::makeImage() 2547 void TerminalView::makeImage()
2547 { 2548 {
2548 //qDebug("%s %d makeImage", __FILE__, __LINE__); 2549 //qDebug("%s %d makeImage", __FILE__, __LINE__);
2549 calcGeometry(); 2550 calcGeometry();
2550 2551
2551 // confirm that array will be of non-zero size, since the painting code 2552 // confirm that array will be of non-zero size, since the painting code
2552 // assumes a non-zero array length 2553 // assumes a non-zero array length
2553 Q_ASSERT( _lines > 0 && _columns > 0 ); 2554 Q_ASSERT( _lines > 0 && _columns > 0 );
2569 // will be used for margins, the scrollbar etc. 2570 // will be used for margins, the scrollbar etc.
2570 // we need to allow for this so that '_size' does allow 2571 // we need to allow for this so that '_size' does allow
2571 // enough room for the specified number of columns and lines to fit 2572 // enough room for the specified number of columns and lines to fit
2572 2573
2573 QSize newSize = QSize( columns * _fontWidth , 2574 QSize newSize = QSize( columns * _fontWidth ,
2574 lines * _fontHeight ); 2575 lines * _fontHeight );
2575 2576
2576 if ( newSize != size() ) 2577 if ( newSize != size() )
2577 { 2578 {
2578 _size = newSize; 2579 _size = newSize;
2579 updateGeometry(); 2580 updateGeometry();
2580 } 2581 }
2581 } 2582 }
2582 2583
2583 void TerminalView::setFixedSize(int cols, int lins) 2584 void TerminalView::setFixedSize(int cols, int lins)
2584 { 2585 {
2585 _isFixedSize = true; 2586 _isFixedSize = true;
2589 _lines = qMax(1,lins); 2590 _lines = qMax(1,lins);
2590 _usedColumns = qMin(_usedColumns,_columns); 2591 _usedColumns = qMin(_usedColumns,_columns);
2591 _usedLines = qMin(_usedLines,_lines); 2592 _usedLines = qMin(_usedLines,_lines);
2592 2593
2593 if (_image) 2594 if (_image)
2594 { 2595 {
2595 delete[] _image; 2596 delete[] _image;
2596 makeImage(); 2597 makeImage();
2597 } 2598 }
2598 setSize(cols, lins); 2599 setSize(cols, lins);
2599 QWidget::setFixedSize(_size); 2600 QWidget::setFixedSize(_size);
2600 } 2601 }
2601 2602
2602 QSize TerminalView::sizeHint() const 2603 QSize TerminalView::sizeHint() const
2612 /* --------------------------------------------------------------------- */ 2613 /* --------------------------------------------------------------------- */
2613 2614
2614 void TerminalView::dragEnterEvent(QDragEnterEvent* event) 2615 void TerminalView::dragEnterEvent(QDragEnterEvent* event)
2615 { 2616 {
2616 if (event->mimeData()->hasFormat("text/plain")) 2617 if (event->mimeData()->hasFormat("text/plain"))
2617 event->acceptProposedAction(); 2618 event->acceptProposedAction();
2618 } 2619 }
2619 2620
2620 void TerminalView::dropEvent(QDropEvent* event) 2621 void TerminalView::dropEvent(QDropEvent* event)
2621 { 2622 {
2622 // KUrl::List urls = KUrl::List::fromMimeData(event->mimeData()); 2623 // KUrl::List urls = KUrl::List::fromMimeData(event->mimeData());
2623 2624
2624 QString dropText; 2625 QString dropText;
2625 /* if (!urls.isEmpty()) 2626 /* if (!urls.isEmpty())
2626 { 2627 {
2627 for ( int i = 0 ; i < urls.count() ; i++ ) 2628 for ( int i = 0 ; i < urls.count() ; i++ )
2628 { 2629 {
2629 KUrl url = KIO::NetAccess::mostLocalUrl( urls[i] , 0 ); 2630 KUrl url = KIO::NetAccess::mostLocalUrl( urls[i] , 0 );
2630 QString urlText; 2631 QString urlText;
2648 { 2649 {
2649 dropText = event->mimeData()->text(); 2650 dropText = event->mimeData()->text();
2650 } 2651 }
2651 */ 2652 */
2652 if(event->mimeData()->hasFormat("text/plain")) 2653 if(event->mimeData()->hasFormat("text/plain"))
2653 { 2654 {
2654 emit sendStringToEmu(dropText.toLocal8Bit()); 2655 emit sendStringToEmu(dropText.toLocal8Bit());
2655 } 2656 }
2656 } 2657 }
2657 2658
2658 void TerminalView::doDrag() 2659 void TerminalView::doDrag()
2659 { 2660 {
2660 dragInfo.state = diDragging; 2661 dragInfo.state = diDragging;
2666 // Don't delete the QTextDrag object. Qt will delete it when it's done with it. 2667 // Don't delete the QTextDrag object. Qt will delete it when it's done with it.
2667 } 2668 }
2668 2669
2669 void TerminalView::outputSuspended(bool suspended) 2670 void TerminalView::outputSuspended(bool suspended)
2670 { 2671 {
2671 //create the label when this function is first called 2672 //create the label when this function is first called
2672 if (!_outputSuspendedLabel) 2673 if (!_outputSuspendedLabel)
2673 { 2674 {
2674 //This label includes a link to an English language website 2675 //This label includes a link to an English language website
2675 //describing the 'flow control' (Xon/Xoff) feature found in almost 2676 //describing the 'flow control' (Xon/Xoff) feature found in almost
2676 //all terminal emulators. 2677 //all terminal emulators.
2677 //If there isn't a suitable article available in the target language the link 2678 //If there isn't a suitable article available in the target language the link
2678 //can simply be removed. 2679 //can simply be removed.
2679 _outputSuspendedLabel = new QLabel( ("<qt>Output has been " 2680 _outputSuspendedLabel = new QLabel( ("<qt>Output has been "
2680 "<a href=\"http://en.wikipedia.org/wiki/XON\">suspended</a>" 2681 "<a href=\"http://en.wikipedia.org/wiki/XON\">suspended</a>"
2681 " by pressing Ctrl+S." 2682 " by pressing Ctrl+S."
2682 " Press <b>Ctrl+Q</b> to resume.</qt>"), 2683 " Press <b>Ctrl+Q</b> to resume.</qt>"),
2683 this ); 2684 this );
2684 2685
2685 QPalette palette(_outputSuspendedLabel->palette()); 2686 QPalette palette(_outputSuspendedLabel->palette());
2686 2687
2687 palette.setColor(QPalette::Normal, QPalette::WindowText, QColor(Qt::white)); 2688 palette.setColor(QPalette::Normal, QPalette::WindowText, QColor(Qt::white));
2688 palette.setColor(QPalette::Normal, QPalette::Window, QColor(Qt::black)); 2689 palette.setColor(QPalette::Normal, QPalette::Window, QColor(Qt::black));
2689 // KColorScheme::adjustForeground(palette,KColorScheme::NeutralText); 2690 // KColorScheme::adjustForeground(palette,KColorScheme::NeutralText);
2690 // KColorScheme::adjustBackground(palette,KColorScheme::NeutralBackground); 2691 // KColorScheme::adjustBackground(palette,KColorScheme::NeutralBackground);
2691 _outputSuspendedLabel->setPalette(palette); 2692 _outputSuspendedLabel->setPalette(palette);
2692 _outputSuspendedLabel->setAutoFillBackground(true); 2693 _outputSuspendedLabel->setAutoFillBackground(true);
2693 _outputSuspendedLabel->setBackgroundRole(QPalette::Base); 2694 _outputSuspendedLabel->setBackgroundRole(QPalette::Base);
2694 _outputSuspendedLabel->setFont(QApplication::font()); 2695 _outputSuspendedLabel->setFont(QApplication::font());
2695 _outputSuspendedLabel->setMargin(5); 2696 _outputSuspendedLabel->setMargin(5);
2696 2697
2697 //enable activation of "Xon/Xoff" link in label 2698 //enable activation of "Xon/Xoff" link in label
2698 _outputSuspendedLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse | 2699 _outputSuspendedLabel->setTextInteractionFlags(Qt::LinksAccessibleByMouse |
2699 Qt::LinksAccessibleByKeyboard); 2700 Qt::LinksAccessibleByKeyboard);
2700 _outputSuspendedLabel->setOpenExternalLinks(true); 2701 _outputSuspendedLabel->setOpenExternalLinks(true);
2701 _outputSuspendedLabel->setVisible(false); 2702 _outputSuspendedLabel->setVisible(false);
2702 2703
2703 _gridLayout->addWidget(_outputSuspendedLabel); 2704 _gridLayout->addWidget(_outputSuspendedLabel);
2704 _gridLayout->addItem( new QSpacerItem(0,0,QSizePolicy::Expanding, 2705 _gridLayout->addItem( new QSpacerItem(0,0,QSizePolicy::Expanding,
2705 QSizePolicy::Expanding), 2706 QSizePolicy::Expanding),
2706 1,0); 2707 1,0);
2707 2708
2708 } 2709 }
2709 2710
2710 _outputSuspendedLabel->setVisible(suspended); 2711 _outputSuspendedLabel->setVisible(suspended);
2711 } 2712 }
2712 2713
2713 uint TerminalView::lineSpacing() const 2714 uint TerminalView::lineSpacing() const
2714 { 2715 {
2715 return _lineSpacing; 2716 return _lineSpacing;