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