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