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