GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
QWinTerminalImpl.cpp
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2011-2017 Michael Goffioul
4 
5 This file is part of QConsole.
6 
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program. If not,
19 see <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #include <QApplication>
24 #include <QClipboard>
25 #include <QColor>
26 #include <QFont>
27 #include <QGridLayout>
28 #include <QPaintEvent>
29 #include <QPainter>
30 #include <QResizeEvent>
31 #include <QScrollBar>
32 #include <QtDebug>
33 #include <QThread>
34 #include <QTimer>
35 #include <QToolTip>
36 #include <QCursor>
37 #include <QMessageBox>
38 #include <QDragEnterEvent>
39 #include <QDropEvent>
40 #include <QUrl>
41 #include <QMimeData>
42 
43 #include <fcntl.h>
44 #include <io.h>
45 #include <stdio.h>
46 #include <stdarg.h>
47 #define WIN32_LEAN_AND_MEAN
48 #if ! defined (_WIN32_WINNT) && ! defined (NTDDI_VERSION)
49 #define _WIN32_WINNT 0x0500
50 #endif
51 #include <windows.h>
52 #include <versionhelpers.h>
53 #include <cstring>
54 #include <csignal>
55 #include <limits>
56 
57 #include "QWinTerminalImpl.h"
58 #include "QTerminalColors.h"
59 
60 // Uncomment to log activity to LOGFILENAME
61 // #define DEBUG_QCONSOLE
62 #define LOGFILENAME "QConsole.log"
63 // Uncomment to create hidden console window
64 #define HIDDEN_CONSOLE
65 
66 #ifdef _MSC_VER
67 # pragma warning(disable : 4996)
68 #endif
69 
70 //////////////////////////////////////////////////////////////////////////////
71 
72 class QConsoleView : public QWidget
73 {
74 public:
75  QConsoleView (QWinTerminalImpl* parent = 0) : QWidget (parent), q (parent) { }
76  ~QConsoleView (void) { }
77 
78 protected:
79  void paintEvent (QPaintEvent* event) { q->viewPaintEvent (this, event); }
80  void resizeEvent (QResizeEvent* event) { q->viewResizeEvent (this, event); }
81 
82 private:
84 };
85 
86 //////////////////////////////////////////////////////////////////////////////
87 
88 class QConsoleThread : public QThread
89 {
90 public:
91  QConsoleThread (QWinTerminalImpl* console) : QThread (console), q (console) { }
92 
93 protected:
94  void run (void)
95  { q->start (); }
96 
97 private:
99 };
100 
101 //////////////////////////////////////////////////////////////////////////////
102 
103 static QString translateKey (QKeyEvent *ev)
104 {
105  QString esc = "\x1b";
106  QString s;
107 
108  if (ev->key () == Qt::Key_Delete)
109  s = esc + "[C\b";
110  else if (!ev->text ().isEmpty ())
111  s = ev->text ();
112  else
113  {
114 
115  switch (ev->key ())
116  {
117  case Qt::Key_Up:
118  s = esc + "[A";
119  break;
120 
121  case Qt::Key_Down:
122  s = esc + "[B";
123  break;
124 
125  case Qt::Key_Right:
126  s = esc + "[C";
127  break;
128 
129  case Qt::Key_Left:
130  s = esc + "[D";
131  break;
132 
133  case Qt::Key_Home:
134  s = esc + "[H";
135  break;
136 
137  case Qt::Key_End:
138  s = esc + "[F";
139  break;
140 
141  case Qt::Key_Insert:
142  s = esc + "[2~";
143  break;
144 
145  case Qt::Key_PageUp:
146  s = esc + "[5~";
147  break;
148 
149  case Qt::Key_PageDown:
150  s = esc + "[6~";
151  break;
152 
153  case Qt::Key_Escape:
154  s = esc;
155  break;
156 
157  default:
158  break;
159  }
160  }
161 
162  return s;
163 }
164 
166 {
167  friend class QWinTerminalImpl;
168 
169 public:
170 
172  {
176  };
177 
178  QConsolePrivate (QWinTerminalImpl* parent, const QString& cmd = QString ());
179  ~QConsolePrivate (void);
180 
181  void updateConsoleSize (bool sync = false, bool allow_smaller_width = false);
182  void syncConsoleParameters (void);
183  void grabConsoleBuffer (CHAR_INFO* buf = 0);
184  void updateHorizontalScrollBar (void);
185  void updateVerticalScrollBar (void);
186  void setHorizontalScrollValue (int value);
187  void setVerticalScrollValue (int value);
188  void updateConsoleView (bool grab = true);
189  void monitorConsole (void);
190  void startCommand (void);
191  void sendConsoleText (const QString& s);
192  QRect cursorRect (void);
193  void selectAll();
194  void selectWord(const QPoint& cellPos);
195  void selectLine(const QPoint& cellPos);
196 
197  void log (const char* fmt, ...);
198 
199  void closeStandardIO (int fd, DWORD stdHandleId, const char* name);
200  void setupStandardIO (DWORD stdHandleId, int fd, const char* name,
201  const char* devName);
202 
203  QPoint posToCell (const QPoint& pt);
204  QString getSelection (void);
205  void updateSelection (void);
206  void clearSelection (void);
207 
208  QColor backgroundColor (void) const;
209  QColor foregroundColor (void) const;
210  QColor selectionColor (void) const;
211  QColor cursorColor (void) const;
212 
213  void setBackgroundColor (const QColor& color);
214  void setForegroundColor (const QColor& color);
215  void setSelectionColor (const QColor& color);
216  void setCursorColor (bool useForegroundColor, const QColor& color);
217  void setScrollBufferSize (int value);
218 
219  void drawTextBackground (QPainter& p, int cx1, int cy1, int cx2, int cy2,
220  int cw, int ch);
221 
222  void drawSelection (QPainter& p, int cx1, int cy1, int cx2, int cy2,
223  int cw, int ch);
224 
225  void drawCursor (QPainter& p);
226 
227  void drawText (QPainter& p, int cx1, int cy1, int cx2, int cy2,
228  int cw, int ch);
229 
230 private:
232 
233 private:
234  QFont m_font;
235  QString m_command;
238  QString m_title;
239 
240  QSize m_charSize;
243  QPoint m_cursorPos;
248 
252 
255 
256  HANDLE m_stdOut;
258  CHAR_INFO* m_buffer;
259  CHAR_INFO* m_tmpBuffer;
260  HANDLE m_process;
261 
264  QScrollBar* m_verticalScrollBar;
267 
268  // The delay in milliseconds between redrawing blinking text.
269  static const int BLINK_DELAY = 500;
270 };
271 
272 static void maybeSwapPoints (QPoint& begin, QPoint& end)
273 {
274  if (end.y () < begin.y ()
275  || (end.y () == begin.y () && end.x () < begin.x ()))
276  qSwap (begin, end);
277 }
278 
279 //////////////////////////////////////////////////////////////////////////////
280 
282  : q (parent), m_command (cmd), m_cursorBlinking (false),
283  m_hasBlinkingCursor (true), m_cursorType (BlockCursor),
284  m_beginSelection (0, 0), m_endSelection (0, 0), m_settingSelection (false),
285  m_process (NULL), m_inWheelEvent (false)
286 {
287  log (NULL);
288 
289  // Possibly detach from any existing console
290  log ("Detaching from existing console (if any)...\n");
291  FreeConsole ();
292  log ("Closing standard IO...\n");
293  closeStandardIO (0, STD_INPUT_HANDLE, "STDIN");
294  closeStandardIO (1, STD_OUTPUT_HANDLE, "STDOUT");
295  closeStandardIO (2, STD_ERROR_HANDLE, "STDERR");
296 
297 #ifdef HIDDEN_CONSOLE
298  HWINSTA hOrigSta, hNewSta;
299 
300  // Create new (hidden) console
301  hOrigSta = GetProcessWindowStation ();
302  hNewSta = CreateWindowStation (NULL, 0, GENERIC_ALL, NULL);
303  log ("Current Windows station: %p.\nNew Windows station: %p.\n", hOrigSta,
304  hNewSta);
305  if (! SetProcessWindowStation (hNewSta))
306  log ("Failed to switch to new Windows station.\n");
307 #endif
308  if (! AllocConsole ())
309  log ("Failed to create new console.\n");
310 #ifdef HIDDEN_CONSOLE
311  if (! SetProcessWindowStation (hOrigSta))
312  log ("Failed to restore original Windows station.\n");
313  if (! CloseWindowStation (hNewSta))
314  log ("Failed to close new Windows station.\n");
315 #endif
316 
317  log ("New (hidden) console created.\n");
318 
319  setupStandardIO (STD_INPUT_HANDLE, 0, "STDIN", "CONIN$");
320  setupStandardIO (STD_OUTPUT_HANDLE, 1, "STDOUT", "CONOUT$");
321  setupStandardIO (STD_ERROR_HANDLE, 2, "STDERR", "CONOUT$");
322 
323  log ("Standard input/output/error set up.\n");
324 
325  *stdin = *(fdopen (0, "rb"));
326  *stdout = *(fdopen (1, "wb"));
327  *stderr = *(fdopen (2, "wb"));
328 
329  log ("POSIX standard streams created.\n");
330 
331  setvbuf (stdin, NULL, _IONBF, 0);
332  setvbuf (stdout, NULL, _IONBF, 0);
333  setvbuf (stderr, NULL, _IONBF, 0);
334 
335  log ("POSIX standard stream buffers adjusted.\n");
336 
337  HANDLE hStdOut = GetStdHandle (STD_OUTPUT_HANDLE);
338 
339  log ("Console allocated: hStdOut: %p\n", hStdOut);
340 
341  m_stdOut = hStdOut;
342  m_consoleWindow = GetConsoleWindow ();
343 
344  // In case the console window hasn't been created hidden...
345 #ifdef HIDDEN_CONSOLE
346  ShowWindow (m_consoleWindow, SW_HIDE);
347 #endif
348 
349  CONSOLE_SCREEN_BUFFER_INFO sbi;
350 
351  GetConsoleScreenBufferInfo (hStdOut, &sbi);
352  m_bufferSize = QSize (sbi.dwSize.X, qMax (sbi.dwSize.Y, (SHORT)500));
353  m_consoleRect = QRect (sbi.srWindow.Left, sbi.srWindow.Top,
354  sbi.srWindow.Right - sbi.srWindow.Left + 1,
355  sbi.srWindow.Bottom - sbi.srWindow.Top + 1);
356  m_cursorPos = QPoint (sbi.dwCursorPosition.X, sbi.dwCursorPosition.Y);
357 
358  log ("Initial console parameters:\n");
359  log (" buffer size: %d x %d\n", m_bufferSize.width (),
360  m_bufferSize.height ());
361  log (" window: (%d, %d) -> (%d, %d) [%d x %d]\n",
362  m_consoleRect.left (), m_consoleRect.top (),
363  m_consoleRect.right (), m_consoleRect.bottom (),
364  m_consoleRect.width (), m_consoleRect.height ());
365 
366  wchar_t titleBuf[260];
367  GetConsoleTitleW (titleBuf, sizeof (titleBuf));
368  q->setWindowTitle (QString::fromWCharArray (titleBuf));
369 
370  m_font.setFamily ("Lucida Console");
371  m_font.setPointSize (9);
372  m_font.setStyleHint (QFont::TypeWriter);
373 
374  m_buffer = m_tmpBuffer = 0;
375 
376  m_consoleView = new QConsoleView (parent);
377  m_horizontalScrollBar = new QScrollBar (Qt::Horizontal, parent);
378  m_verticalScrollBar = new QScrollBar (Qt::Vertical, parent);
379 
380  QGridLayout* l = new QGridLayout (parent);
381  l->setContentsMargins (0, 0, 0, 0);
382  l->setSpacing (0);
383  l->addWidget (m_consoleView, 0, 0);
384  l->addWidget (m_horizontalScrollBar, 1, 0);
385  l->addWidget (m_verticalScrollBar, 0, 1);
386 
387  if (IsWindows7OrGreater ())
388  {
389  SetConsoleCP (65001);
390  SetConsoleOutputCP (65001);
391  }
392 
393  // Choose 15 (0xF) as index into the Windows console color map for the
394  // background and 0 (0x0) as the index for the foreground. This
395  // selection corresponds to the indices used in the foregroundColor,
396  // setForegroundColor, backgroundColor, and SetBackgroundColor
397  // functions.
398 
399  SetConsoleTextAttribute (m_stdOut, 0xF0);
400 
401  // Defaults.
402  setBackgroundColor (Qt::white);
403  setForegroundColor (Qt::black);
404  setSelectionColor (Qt::lightGray);
405  setCursorColor (false, Qt::darkGray);
406 
407  // FIXME -- should we set the palette?
408  QPalette palette (backgroundColor ());
409  m_consoleView->setPalette (palette);
410 
411  m_consoleView->setAutoFillBackground (true);
412 
413  m_consoleView->setFont (m_font);
414  parent->setFocusPolicy (Qt::StrongFocus);
415  parent->winId ();
416 
419 
420  m_consoleWatcher = new QTimer (parent);
421  m_consoleWatcher->setInterval (10);
422  m_consoleWatcher->setSingleShot (false);
423 
424  m_blinkCursorTimer = new QTimer (parent);
425  QObject::connect (m_blinkCursorTimer, SIGNAL (timeout()),
426  q, SLOT (blinkCursorEvent ()));
427 
428  QObject::connect (m_horizontalScrollBar, SIGNAL (valueChanged (int)),
429  q, SLOT (horizontalScrollValueChanged (int)));
430 
431  QObject::connect (m_verticalScrollBar, SIGNAL (valueChanged (int)),
432  q, SLOT (verticalScrollValueChanged (int)));
433 
434  QObject::connect (m_consoleWatcher, SIGNAL (timeout (void)),
435  q, SLOT (monitorConsole (void)));
436 
437  m_consoleWatcher->start ();
438 
439  if (m_command.isEmpty ())
440  m_consoleThread = 0;
441  else
442  {
444  QObject::connect (m_consoleThread, SIGNAL (finished (void)),
445  q, SIGNAL (terminated (void)));
446  m_consoleThread->start ();
447  }
448 }
449 
450 //////////////////////////////////////////////////////////////////////////////
451 
453 {
454  if (m_consoleThread && m_consoleThread->isRunning () && m_process)
455  {
456  TerminateProcess (m_process, (UINT)-1);
457  m_consoleThread->wait ();
458  }
459  if (m_buffer)
460  delete [] m_buffer;
461  if (m_tmpBuffer)
462  delete [] m_tmpBuffer;
463 }
464 
465 //////////////////////////////////////////////////////////////////////////////
466 
467 void QConsolePrivate::setupStandardIO (DWORD stdHandleId, int targetFd,
468  const char* name, const char* devName)
469 {
470  log ("Opening %s...\n", devName);
471 
472  int fd = open (devName, _O_RDWR | _O_BINARY);
473 
474  if (fd != -1)
475  {
476  if (fd != targetFd)
477  {
478  log ("Opened %s is not at target file descriptor %d, "
479  "duplicating...\n", name, targetFd);
480  if (dup2 (fd, targetFd) == -1)
481  log ("Failed to duplicate file descriptor: errno=%d.\n", errno);
482  if (close (fd) == -1)
483  log ("Failed to close original file descriptor: errno=%d.\n",
484  errno);
485  }
486  else
487  log ("%s opened and assigned to file descriptor %d.\n", devName, fd);
488  if (! SetStdHandle (stdHandleId, (HANDLE) _get_osfhandle (targetFd)))
489  log ("Failed to re-assign %s: error=%08x.\n", name, GetLastError ());
490  }
491  else
492  log ("Failed to open %s: errno=%d.\n", devName, errno);
493 }
494 
495 QPoint QConsolePrivate::posToCell (const QPoint& p)
496 {
497  return QPoint (m_consoleRect.left () + p.x () / m_charSize.width (),
498  m_consoleRect.top () + p.y () / m_charSize.height ());
499 }
500 
502 {
503  QString selection;
504 
505  QPoint begin = m_beginSelection;
506  QPoint end = m_endSelection;
507 
508  maybeSwapPoints (begin, end);
509 
510  if (begin != end)
511  {
512  CHAR_INFO* buf;
513  COORD bufSize, bufCoord;
514  SMALL_RECT bufRect;
515  int nr;
516 
517  nr = end.y () - begin.y () + 1;
518  buf = new CHAR_INFO[m_bufferSize.width () * nr];
519  bufSize.X = m_bufferSize.width ();
520  bufSize.Y = nr;
521  bufCoord.X = 0;
522  bufCoord.Y = 0;
523 
524  bufRect.Left = 0;
525  bufRect.Right = m_bufferSize.width ();
526  bufRect.Top = begin.y ();
527  bufRect.Bottom = end.y ();
528 
529  if (ReadConsoleOutput (m_stdOut, buf, bufSize, bufCoord, &bufRect))
530  {
531  int start_pos = begin.x ();
532  int end_pos = (nr - 1) * m_bufferSize.width () + end.x ();
533  int lastNonSpace = -1;
534 
535  for (int i = start_pos; i <= end_pos; i++)
536  {
537  if (i && (i % m_bufferSize.width ()) == 0)
538  {
539  if (lastNonSpace >= 0)
540  selection.truncate (lastNonSpace);
541  selection.append ('\n');
542  lastNonSpace = selection.length ();
543  }
544 
545  QChar c (buf[i].Char.UnicodeChar);
546 
547  selection.append (c);
548  if (! c.isSpace ())
549  lastNonSpace = selection.length ();
550  }
551 
552  if (lastNonSpace >= 0)
553  selection.truncate (lastNonSpace);
554  }
555  }
556 
557  return selection;
558 }
559 
561 {
562  QPoint begin = m_beginSelection;
563  QPoint end = m_endSelection;
564 
565  maybeSwapPoints (begin, end);
566 
567  begin.rx () = 0;
568  end.rx () = m_consoleRect.width ();
569 
570  m_consoleView->update ();
571 }
572 
574 {
575  m_beginSelection = m_endSelection = QPoint ();
576 
577  m_consoleView->update ();
578 }
579 
581 {
582  return m_colors[15];
583 }
584 
586 {
587  return m_colors[0];
588 }
589 
591 {
592  return m_selectionColor;
593 }
594 
595 QColor QConsolePrivate::cursorColor (void) const
596 {
597  return m_cursorColor.isValid () ? m_cursorColor : foregroundColor ();
598 }
599 
600 void QConsolePrivate::setBackgroundColor (const QColor& color)
601 {
602  m_colors[15] = color;
603 
604  QPalette palette (color);
605  m_consoleView->setPalette (palette);
606 }
607 
608 void QConsolePrivate::setForegroundColor (const QColor& color)
609 {
610  m_colors[0] = color;
611 }
612 
613 void QConsolePrivate::setSelectionColor (const QColor& color)
614 {
615  m_selectionColor = color;
616 }
617 
618 void QConsolePrivate::setCursorColor (bool useForegroundColor,
619  const QColor& color)
620 {
621  m_cursorColor = useForegroundColor ? QColor () : color;
622 }
623 
625 {
626  CONSOLE_SCREEN_BUFFER_INFO sbi;
627  GetConsoleScreenBufferInfo (m_stdOut, &sbi);
628 
629  m_bufferSize = QSize (sbi.dwSize.X, (SHORT)value);
630 
631  updateConsoleSize (true);
632 }
633 
634 void QConsolePrivate::drawTextBackground (QPainter& p, int cx1, int cy1,
635  int cx2, int cy2, int cw, int ch)
636 {
637  p.save ();
638 
639  int ascent = p.fontMetrics ().ascent ();
640  int stride = m_consoleRect.width ();
641  int y = ascent + cy1 * ch;;
642 
643  for (int j = cy1; j <= cy2; j++, y += ch)
644  {
645  int len = 0;
646  bool hasChar = false;
647  int x = cx1 * cw;
648  WORD attr = 0;
649 
650  for (int i = cx1; i <= cx2; i++)
651  {
652  CHAR_INFO* ci = &(m_buffer[stride*j+i]);
653 
654  if ((ci->Attributes & 0x00ff) != attr)
655  {
656  // Character attributes changed
657  if (len != 0)
658  {
659  // String buffer not empty -> draw it
660  if (hasChar || (attr & 0x00f0))
661  {
662  if (attr & 0x00f0)
663  p.fillRect (x, y-ascent, len * cw, ch, p.brush ());
664  }
665 
666  x += (len * cw);
667  len = 0;
668  hasChar = false;
669  }
670  // Update current brush and store current attributes
671  attr = (ci->Attributes & 0x00ff);
672  p.setBrush (m_colors[(attr >> 4) & 0x000f]);
673  }
674 
675  // Append current character to the string buffer
676  len++;
677  if (ci->Char.UnicodeChar != L' ')
678  hasChar = true;
679  }
680 
681  if (len != 0 && (hasChar || (attr & 0x00f0)))
682  {
683  // Line end reached, but string buffer not empty -> draw it
684  // No need to update s or x, they will be reset on the next
685  // for-loop iteration
686 
687  if (attr & 0x00f0)
688  p.fillRect (x, y-ascent, len * cw, ch, p.brush ());
689  }
690  }
691 
692  p.restore ();
693 }
694 
696 {
697  m_beginSelection = QPoint (0,0);
698  m_endSelection = QPoint(m_bufferSize.width (),
699  m_cursorPos.y());
700  updateSelection();
701 }
702 
703 void QConsolePrivate::selectWord (const QPoint & cellpos)
704 {
705  QPoint begin = cellpos;
706  QPoint end = cellpos;
707 
708  int stride = m_consoleRect.width ();
709 
710  int verticalScrollOffset = m_consoleRect.top ();
711  int horizontalScrollOffset = m_consoleRect.left ();
712 
713  // get begin, end in buffer offsets
714  begin.ry () -= verticalScrollOffset;
715  end.ry () -= verticalScrollOffset;
716 
717  begin.rx () -= horizontalScrollOffset;
718  end.rx () -= horizontalScrollOffset;
719 
720  // loog at current clicked on char to determinate ig getting space chunk or nonspace chunk
721  if (QChar(m_buffer[begin.y ()*stride + begin.x ()].Char.UnicodeChar).isSpace () == false)
722  {
723  // from current char, go back and fwd to find start and end of block
724  while(begin.x () > 0 &&
725  QChar(m_buffer[begin.y ()*stride + begin.x () -1].Char.UnicodeChar).isSpace() == false)
726  {
727  begin.rx () --;
728  }
729 
730  while(end.x () < m_consoleRect.width () &&
731  QChar(m_buffer[end.y ()*stride + end.x () +1].Char.UnicodeChar).isSpace() == false)
732  {
733  end.rx () ++;
734  }
735  }
736  else
737  {
738  while(begin.x () > 0 &&
739  QChar(m_buffer[begin.y ()*stride + begin.x () -1].Char.UnicodeChar).isSpace())
740  {
741  begin.rx () --;
742  }
743 
744  while(end.x () < m_consoleRect.width () &&
745  QChar(m_buffer[end.y ()*stride + end.x () +1].Char.UnicodeChar).isSpace ())
746  {
747  end.rx () ++;
748  }
749  }
750 
751  // convert console offsets to absolute cell positions
752  begin.ry () += verticalScrollOffset;
753  end.ry () += verticalScrollOffset;
754 
755  begin.rx () += horizontalScrollOffset;
756  end.rx () += horizontalScrollOffset;
757 
758  m_beginSelection = begin;
759  m_endSelection = end;
760 
761  updateSelection ();
762 }
763 
764 void QConsolePrivate::selectLine (const QPoint & cellpos)
765 {
766  m_beginSelection = QPoint (0, cellpos.y ());
767  m_endSelection = QPoint (m_bufferSize.width ()-1, cellpos.y ());
768  updateSelection ();
769 }
770 
771 
772 void QConsolePrivate::drawSelection (QPainter& p, int cx1, int cy1,
773  int cx2, int cy2, int cw, int ch)
774 {
775  p.save ();
776 
777  QPoint begin = m_beginSelection;
778  QPoint end = m_endSelection;
779 
780  bool haveSelection = (begin != end);
781 
782  if (haveSelection)
783  maybeSwapPoints (begin, end);
784 
785  int verticalScrollOffset = m_consoleRect.top ();
786  int horizontalScrollOffset = m_consoleRect.left ();
787 
788  begin.ry () -= verticalScrollOffset;
789  end.ry () -= verticalScrollOffset;
790 
791  begin.rx () -= horizontalScrollOffset;
792  end.rx () -= horizontalScrollOffset;
793 
794  int ascent = p.fontMetrics ().ascent ();
795  int stride = m_consoleRect.width ();
796 
797  int y = ascent + cy1 * ch;;
798  for (int j = cy1; j <= cy2; j++, y += ch)
799  {
800  int charsThisLine = 0;
801  int len = 0;
802  bool hasChar = false;
803  WORD attr = 0;
804 
805  for (int i = cx1; i <= cx2; i++)
806  {
807  CHAR_INFO* ci = &(m_buffer[stride*j+i]);
808 
809  if ((ci->Attributes & 0x00ff) != attr)
810  {
811  // Character attributes changed
812  if (len != 0)
813  {
814  charsThisLine += len;
815  len = 0;
816  hasChar = false;
817  }
818 
819  // Store current attributes
820  attr = (ci->Attributes & 0x00ff);
821  }
822 
823  // Append current character to the string buffer
824  len++;
825  if (ci->Char.UnicodeChar != L' ')
826  hasChar = true;
827  }
828 
829  if (len != 0 && (hasChar || (attr & 0x00f0)))
830  charsThisLine += len;
831 
832  if (haveSelection && j >= begin.y () && j <= end.y ())
833  {
834  int selectionBegin = j == begin.y () ? begin.x (): 0;
835 
836  int len = ((j == end.y () && end.x () < charsThisLine)
837  ? end.x () - selectionBegin + 1
838  : stride - selectionBegin);
839 
840  p.fillRect (selectionBegin * cw, y-ascent, len * cw, ch,
841  selectionColor ());
842  }
843  }
844 
845  p.restore ();
846 }
847 
849 {
850  if (! m_cursorBlinking)
851  {
852  p.save ();
853 
854  QRect rect = cursorRect ();
855  QColor color = cursorColor ();
856 
857  p.setPen (color);
858 
860  {
861  if (q->hasFocus ())
862  p.fillRect (rect, color);
863  else
864  {
865  // draw the cursor outline, adjusting the area so that
866  // it is draw entirely inside 'rect'
867 
868  int penWidth = qMax (1, p.pen().width());
869 
870  p.drawRect (rect.adjusted (penWidth/2, penWidth/2,
871  - penWidth/2 - penWidth%2,
872  - penWidth/2 - penWidth%2));
873  }
874  }
876  {
877  p.drawLine (rect.left (), rect.bottom (),
878  rect.right (), rect.bottom ());
879  }
881  {
882  p.drawLine (rect.left (), rect.top (),
883  rect.left (), rect.bottom ());
884  }
885 
886  p.restore ();
887  }
888 }
889 
890 void QConsolePrivate::drawText (QPainter& p, int cx1, int cy1,
891  int cx2, int cy2, int cw, int ch)
892 {
893  p.save ();
894 
895  p.setFont (m_font);
896  p.setPen (foregroundColor ());
897 
898  QString s;
899  s.reserve (cx2 - cx1 + 1);
900 
901  int ascent = p.fontMetrics ().ascent ();
902  int stride = m_consoleRect.width ();
903 
904  int y = ascent + cy1 * ch;;
905  for (int j = cy1; j <= cy2; j++, y += ch)
906  {
907  // Reset string buffer and starting X coordinate
908  s.clear ();
909  bool hasChar = false;
910  int x = cx1 * cw;
911  WORD attr = 0;
912 
913  for (int i = cx1; i <= cx2; i++)
914  {
915  CHAR_INFO* ci = &(m_buffer[stride*j+i]);
916 
917  if ((ci->Attributes & 0x00ff) != attr)
918  {
919  // Character attributes changed
920  if (! s.isEmpty ())
921  {
922  // String buffer not empty -> draw it
923  if (hasChar || (attr & 0x00f0))
924  p.drawText (x, y, s);
925 
926  x += (s.length () * cw);
927  s.clear ();
928  hasChar = false;
929  }
930  // Update current pen and store current attributes
931  attr = (ci->Attributes & 0x00ff);
932  p.setPen (m_colors[attr & 0x000f]);
933  }
934 
935  // Append current character to the string buffer
936  s.append (ci->Char.UnicodeChar);
937  if (ci->Char.UnicodeChar != L' ')
938  hasChar = true;
939  }
940 
941  if (! s.isEmpty () && (hasChar || (attr & 0x00f0)))
942  {
943  // Line end reached, but string buffer not empty -> draw it
944  // No need to update s or x, they will be reset on the next
945  // for-loop iteration
946 
947  p.drawText (x, y, s);
948  }
949  }
950 
951  p.restore ();
952 }
953 
954 /////////////////////////////////////////////////////////////////////////////
955 
956 void QConsolePrivate::closeStandardIO (int fd, DWORD stdHandleId,
957  const char* name)
958 {
959  if (close (fd) == -1)
960  log ("Failed to close file descriptor %d: errno=%d.\n", fd, errno);
961  if (! CloseHandle (GetStdHandle (stdHandleId)))
962  log ("Failed to close Win32 %s: error=%08x.\n", name, GetLastError ());
963 }
964 
965 //////////////////////////////////////////////////////////////////////////////
966 
967 void QConsolePrivate::log (const char* fmt, ...)
968 {
969 #ifdef DEBUG_QCONSOLE
970  if (fmt)
971  {
972  va_list l;
973  FILE* flog = fopen (LOGFILENAME, "ab");
974 
975  va_start (l, fmt);
976  vfprintf (flog, fmt, l);
977  va_end (l);
978  fclose (flog);
979  }
980  else
981  {
982  // Special case to re-initialize the log file
983  FILE* flog = fopen (LOGFILENAME, "w");
984  fclose (flog);
985  }
986 #else
987  Q_UNUSED (fmt);
988 #endif
989 }
990 
991 //////////////////////////////////////////////////////////////////////////////
992 
993 void QConsolePrivate::updateConsoleSize (bool sync, bool allow_smaller_width)
994 {
995  QFontMetrics fm = m_consoleView->fontMetrics ();
996  QSize winSize = m_consoleView->size ();
997 
998  m_charSize.rwidth () = fm.averageCharWidth ();
999  m_charSize.rheight () = fm.lineSpacing ();
1000 
1001  m_consoleRect.setWidth (winSize.width () / fm.averageCharWidth ());
1002  m_consoleRect.setHeight (winSize.height () / fm.lineSpacing ());
1003 
1004  // Don't shrink the size of the buffer. That way wide lines won't be
1005  // truncated and will reappear if the window is enlarged again later.
1006 
1007  if (allow_smaller_width || m_consoleRect.width () > m_bufferSize.width ())
1008  m_bufferSize.rwidth () = m_consoleRect.width ();
1009 
1010  if (qMax (m_bufferSize.height (), m_consoleRect.height ())
1011  > m_bufferSize.height ())
1012  m_bufferSize.rheight () = qMax (m_bufferSize.height (),
1013  m_consoleRect.height ());
1014 
1015  // Store the terminal size in the environment. When Octave is
1016  // initialized, we ask the command editor (usually readline) to prefer
1017  // using these values rather than querying the terminal so that the
1018  // buffer size can be larger than the size of the window that the
1019  // command editor will actually use.
1020 
1021  qputenv ("LINES", QByteArray::number (m_consoleRect.height ()));
1022  qputenv ("COLUMNS", QByteArray::number (m_consoleRect.width ()));
1023 
1024  // Force the command line editor (usually readline) to notice the
1025  // change in screen size as soon as possible.
1026 
1027  q->setSize (m_consoleRect.height (), m_consoleRect.width ());
1028 
1029  m_consoleRect.moveLeft (0);
1030  if (m_consoleRect.bottom () >= m_bufferSize.height ())
1031  m_consoleRect.moveTop (m_bufferSize.height () - m_consoleRect.height ());
1032 
1033  log ("Console resized:\n");
1034  log (" widget size: %d x %d\n", winSize.width (), winSize.height ());
1035  log (" buffer size: %d x %d\n", m_bufferSize.width (),
1036  m_bufferSize.height ());
1037  log (" window: (%d, %d) -> (%d, %d) [%d x %d]\n",
1038  m_consoleRect.left (), m_consoleRect.top (),
1039  m_consoleRect.right (), m_consoleRect.bottom (),
1040  m_consoleRect.width (), m_consoleRect.height ());
1041 
1042  if (sync)
1044 
1047 }
1048 
1049 //////////////////////////////////////////////////////////////////////////////
1050 
1052 {
1053  CONSOLE_SCREEN_BUFFER_INFO sbi;
1054  HANDLE hStdOut = m_stdOut;
1055 
1056  GetConsoleScreenBufferInfo (hStdOut, &sbi);
1057 
1058  COORD bs;
1059  SMALL_RECT sr;
1060 
1061  bs.X = sbi.dwSize.X;
1062  bs.Y = m_bufferSize.height ();
1063  sr.Left = sbi.srWindow.Left;
1064  sr.Right = sbi.srWindow.Right;
1065  sr.Top = m_consoleRect.top ();
1066  sr.Bottom = m_consoleRect.bottom ();
1067 
1068  if (bs.Y > sbi.dwSize.Y)
1069  {
1070  SetConsoleScreenBufferSize (hStdOut, bs);
1071  SetConsoleWindowInfo (hStdOut, TRUE, &sr);
1072  }
1073  else
1074  {
1075  SetConsoleWindowInfo (hStdOut, TRUE, &sr);
1076  SetConsoleScreenBufferSize (hStdOut, bs);
1077  }
1078 
1079  bs.X = m_bufferSize.width ();
1080  sr.Left = m_consoleRect.left ();
1081  sr.Right = m_consoleRect.right ();
1082 
1083  if (bs.X > sbi.dwSize.X)
1084  {
1085  SetConsoleScreenBufferSize (hStdOut, bs);
1086  SetConsoleWindowInfo (hStdOut, TRUE, &sr);
1087  }
1088  else
1089  {
1090  SetConsoleWindowInfo (hStdOut, TRUE, &sr);
1091  SetConsoleScreenBufferSize (hStdOut, bs);
1092  }
1093 
1094  log ("Sync'ing console parameters:\n");
1095  log (" buffer size: %d x %d\n", bs.X, bs.Y);
1096  log (" window: (%d, %d) -> (%d, %d)\n",
1097  sr.Left, sr.Top, sr.Right, sr.Bottom);
1098 
1099  if (m_buffer)
1100  delete [] m_buffer;
1101  if (m_tmpBuffer)
1102  delete [] m_tmpBuffer;
1103 
1104  int bufSize = m_consoleRect.width () * m_consoleRect.height ();
1105 
1106  m_buffer = new CHAR_INFO[bufSize];
1107  m_tmpBuffer = new CHAR_INFO[bufSize];
1108 }
1109 
1110 //////////////////////////////////////////////////////////////////////////////
1111 
1113 {
1114  COORD bs, bc;
1115  SMALL_RECT r;
1116 
1117  bs.X = m_consoleRect.width ();
1118  bs.Y = m_consoleRect.height ();
1119  bc.X = 0;
1120  bc.Y = 0;
1121 
1122  r.Left = m_consoleRect.left ();
1123  r.Top = m_consoleRect.top ();
1124  r.Right = m_consoleRect.right ();
1125  r.Bottom = m_consoleRect.bottom ();
1126 
1127  if (! ReadConsoleOutput (m_stdOut, (buf ? buf : m_buffer), bs, bc, &r))
1128  qCritical ("cannot read console output");
1129 }
1130 
1131 //////////////////////////////////////////////////////////////////////////////
1132 
1134 {
1135  m_horizontalScrollBar->setMinimum (0);
1136  if (m_bufferSize.width () > m_consoleRect.width ())
1137  m_horizontalScrollBar->setMaximum (m_bufferSize.width () - m_consoleRect.width ());
1138  else
1139  m_horizontalScrollBar->setMaximum (0);
1140  m_horizontalScrollBar->setSingleStep (1);
1141  m_horizontalScrollBar->setPageStep (m_consoleRect.width ());
1142  m_horizontalScrollBar->setValue (m_consoleRect.left ());
1143 
1144  log ("Horizontal scrollbar parameters updated: %d/%d/%d/%d\n",
1145  m_horizontalScrollBar->minimum (),
1146  m_horizontalScrollBar->maximum (),
1147  m_horizontalScrollBar->singleStep (),
1148  m_horizontalScrollBar->pageStep ());
1149 }
1150 
1152 {
1153  m_verticalScrollBar->setMinimum (0);
1154  if (m_bufferSize.height () > m_consoleRect.height ())
1155  m_verticalScrollBar->setMaximum (m_bufferSize.height () - m_consoleRect.height ());
1156  else
1157  m_verticalScrollBar->setMaximum (0);
1158  m_verticalScrollBar->setSingleStep (1);
1159  m_verticalScrollBar->setPageStep (m_consoleRect.height ());
1160  m_verticalScrollBar->setValue (m_consoleRect.top ());
1161 
1162  log ("Vertical scrollbar parameters updated: %d/%d/%d/%d\n",
1163  m_verticalScrollBar->minimum (), m_verticalScrollBar->maximum (),
1164  m_verticalScrollBar->singleStep (), m_verticalScrollBar->pageStep ());
1165 }
1166 
1167 //////////////////////////////////////////////////////////////////////////////
1168 
1170 {
1171  if (value == m_consoleRect.left ())
1172  return;
1173 
1174  SMALL_RECT r;
1175  HANDLE hStdOut = m_stdOut;
1176 
1177  if (value + m_consoleRect.width () > m_bufferSize.width ())
1178  value = m_bufferSize.width () - m_consoleRect.width ();
1179 
1180  r.Left = value;
1181  r.Top = m_consoleRect.top ();
1182  r.Right = value + m_consoleRect.width () - 1;
1183  r.Bottom = m_consoleRect.bottom ();
1184 
1185  log ("Scrolling window horizontally: (%d, %d) -> (%d, %d) [%d x %d]\n",
1186  r.Left, r.Top, r.Right, r.Bottom,
1187  r.Right - r.Left + 1, r.Bottom - r.Top + 1);
1188 
1189  if (SetConsoleWindowInfo (hStdOut, TRUE, &r))
1190  {
1191  m_consoleRect.moveLeft (value);
1192  updateConsoleView ();
1193  }
1194 }
1195 
1197 {
1198  if (value == m_consoleRect.top ())
1199  return;
1200 
1201  SMALL_RECT r;
1202  HANDLE hStdOut = m_stdOut;
1203 
1204  if (value + m_consoleRect.height () > m_bufferSize.height ())
1205  value = m_bufferSize.height () - m_consoleRect.height ();
1206 
1207  r.Left = m_consoleRect.left ();
1208  r.Top = value;
1209  r.Right = m_consoleRect.right ();
1210  r.Bottom = value + m_consoleRect.height () - 1;
1211 
1212  log ("Scrolling window vertically: (%d, %d) -> (%d, %d) [%d x %d]\n",
1213  r.Left, r.Top, r.Right, r.Bottom,
1214  r.Right - r.Left + 1, r.Bottom - r.Top + 1);
1215 
1216  if (SetConsoleWindowInfo (hStdOut, TRUE, &r))
1217  {
1218  m_consoleRect.moveTop (value);
1219  updateConsoleView ();
1220  }
1221 }
1222 
1223 //////////////////////////////////////////////////////////////////////////////
1224 
1226 {
1227  if (grab)
1228  grabConsoleBuffer ();
1229  m_consoleView->update ();
1230  m_consoleWatcher->start ();
1231 }
1232 
1233 //////////////////////////////////////////////////////////////////////////////
1234 
1236 {
1237  CONSOLE_SCREEN_BUFFER_INFO sbi;
1238  HANDLE hStdOut = GetStdHandle (STD_OUTPUT_HANDLE);
1239 
1240  static wchar_t titleBuf[260];
1241 
1242  GetConsoleTitleW (titleBuf, sizeof (titleBuf));
1243  QString title = QString::fromWCharArray (titleBuf);
1244 
1245  if (title != m_title)
1246  {
1247  q->setWindowTitle (title);
1248  emit q->titleChanged (title);
1249  }
1250 
1251  if (GetConsoleScreenBufferInfo (hStdOut, &sbi))
1252  {
1253  if (m_bufferSize.width () != sbi.dwSize.X
1254  || m_bufferSize.height () != sbi.dwSize.Y)
1255  {
1256  // Buffer size changed
1257  m_bufferSize.rwidth () = sbi.dwSize.X;
1258  m_bufferSize.rheight () = sbi.dwSize.Y;
1261  }
1262 
1263  if (m_cursorPos.x () != sbi.dwCursorPosition.X
1264  || m_cursorPos.y () != sbi.dwCursorPosition.Y)
1265  {
1266  // Cursor position changed
1267  m_consoleView->update
1268  ((m_cursorPos.x () - sbi.srWindow.Left) * m_charSize.width (),
1269  (m_cursorPos.y () - sbi.srWindow.Top) * m_charSize.height (),
1270  m_charSize.width (), m_charSize.height ());
1271  m_cursorPos.rx () = sbi.dwCursorPosition.X;
1272  m_cursorPos.ry () = sbi.dwCursorPosition.Y;
1273  m_consoleView->update
1274  ((m_cursorPos.x () - sbi.srWindow.Left) * m_charSize.width (),
1275  (m_cursorPos.y () - sbi.srWindow.Top) * m_charSize.height (),
1276  m_charSize.width (), m_charSize.height ());
1277  }
1278 
1279  if (m_consoleRect.left () != sbi.srWindow.Left
1280  || m_consoleRect.right () != sbi.srWindow.Right
1281  || m_consoleRect.top () != sbi.srWindow.Top
1282  || m_consoleRect.bottom () != sbi.srWindow.Bottom)
1283  {
1284  // Console window changed
1285  m_consoleRect = QRect (sbi.srWindow.Left, sbi.srWindow.Top,
1286  sbi.srWindow.Right - sbi.srWindow.Left + 1,
1287  sbi.srWindow.Bottom - sbi.srWindow.Top + 1);
1290  updateConsoleView ();
1291  return;
1292  }
1293 
1294  if (m_tmpBuffer && m_buffer)
1295  {
1297  if (memcmp (m_tmpBuffer, m_buffer,
1298  sizeof (CHAR_INFO) * m_consoleRect.width () *
1299  m_consoleRect.height ()))
1300  {
1301  // FIXME: compute the area to update based on the
1302  // difference between the 2 buffers.
1303  qSwap (m_buffer, m_tmpBuffer);
1304  updateConsoleView (false);
1305  }
1306  }
1307  }
1308 }
1309 
1310 //////////////////////////////////////////////////////////////////////////////
1311 
1313 {
1314  QString cmd = m_command;
1315 
1316  if (cmd.isEmpty ())
1317  cmd = qgetenv ("COMSPEC").constData ();
1318 
1319  if (! cmd.isEmpty ())
1320  {
1321  STARTUPINFO si;
1322  PROCESS_INFORMATION pi;
1323 
1324  ZeroMemory (&si, sizeof (si));
1325  si.cb = sizeof (si);
1326  ZeroMemory (&pi, sizeof (pi));
1327 
1328  if (CreateProcessW (NULL,
1329  (LPWSTR)cmd.unicode (),
1330  NULL,
1331  NULL,
1332  TRUE,
1333  0,
1334  NULL,
1335  NULL,
1336  &si,
1337  &pi))
1338  {
1339  CloseHandle (pi.hThread);
1340  m_process = pi.hProcess;
1341  WaitForSingleObject (m_process, INFINITE);
1342  CloseHandle (m_process);
1343  m_process = NULL;
1344  }
1345  }
1346 }
1347 
1348 //////////////////////////////////////////////////////////////////////////////
1349 
1351 {
1352  // Send the string in chunks of 512 characters. Each character is
1353  // translated into an equivalent keypress event.
1354 
1355 #define TEXT_CHUNK_SIZE 512
1356 
1357  // clear any selection on inserting text
1358  clearSelection();
1359 
1360  int len = s.length ();
1361  INPUT_RECORD events[TEXT_CHUNK_SIZE];
1362  DWORD nEvents = 0, written;
1363  HANDLE hStdIn = GetStdHandle (STD_INPUT_HANDLE);
1364 
1365  ZeroMemory (events, sizeof (events));
1366 
1367  for (int i = 0; i < len; i++)
1368  {
1369  QChar c = s.at (i);
1370 
1371  if (c == L'\r' || c == L'\n')
1372  {
1373  if (c == L'\r' && i < (len - 1) && s.at (i+1) == L'\n')
1374  i++;
1375 
1376  // add new line
1377  events[nEvents].EventType = KEY_EVENT;
1378  events[nEvents].Event.KeyEvent.bKeyDown = TRUE;
1379  events[nEvents].Event.KeyEvent.wRepeatCount = 1;
1380  events[nEvents].Event.KeyEvent.wVirtualKeyCode =
1381  VK_RETURN;
1382  events[nEvents].Event.KeyEvent.wVirtualScanCode = 0;
1383  events[nEvents].Event.KeyEvent.uChar.UnicodeChar = c.unicode ();
1384  events[nEvents].Event.KeyEvent.dwControlKeyState = 0;
1385  nEvents++;
1386 
1387  WriteConsoleInput (hStdIn, events, nEvents, &written);
1388  nEvents = 0;
1389  ZeroMemory (events, sizeof (events));
1390 
1391  }
1392  else
1393  {
1394  events[nEvents].EventType = KEY_EVENT;
1395  events[nEvents].Event.KeyEvent.bKeyDown = TRUE;
1396  events[nEvents].Event.KeyEvent.wRepeatCount = 1;
1397  events[nEvents].Event.KeyEvent.wVirtualKeyCode =
1398  LOBYTE (VkKeyScan (c.unicode ()));
1399  events[nEvents].Event.KeyEvent.wVirtualScanCode = 0;
1400  events[nEvents].Event.KeyEvent.uChar.UnicodeChar = c.unicode ();
1401  events[nEvents].Event.KeyEvent.dwControlKeyState = 0;
1402  nEvents++;
1403  }
1404 
1405  if (nEvents == TEXT_CHUNK_SIZE
1406  || (nEvents > 0 && i == (len - 1)))
1407  {
1408  WriteConsoleInput (hStdIn, events, nEvents, &written);
1409  nEvents = 0;
1410  ZeroMemory (events, sizeof (events));
1411  }
1412  }
1413 }
1414 
1415 QRect
1417 {
1418  int cw = m_charSize.width ();
1419  int ch = m_charSize.height ();
1420 
1421  return QRect ((m_cursorPos.x () - m_consoleRect.x ()) * cw,
1422  (m_cursorPos.y () - m_consoleRect.y ()) * ch,
1423  cw, ch);
1424 }
1425 
1426 //////////////////////////////////////////////////////////////////////////////
1427 
1429  : QTerminal (parent), d (new QConsolePrivate (this)),
1431 {
1432  installEventFilter (this);
1433 
1434  connect (this, SIGNAL (set_global_shortcuts_signal (bool)),
1435  parent, SLOT (set_global_shortcuts (bool)));
1436  connect (this, SIGNAL (set_global_shortcuts_signal (bool)),
1437  this, SLOT (set_global_shortcuts (bool)));
1438 
1439  connect (this, SIGNAL (set_screen_size_signal (int, int)),
1440  parent, SLOT (set_screen_size (int, int)));
1441 
1442  setAcceptDrops (true);
1443 }
1444 
1445 //////////////////////////////////////////////////////////////////////////////
1446 
1447 QWinTerminalImpl::QWinTerminalImpl (const QString& cmd, QWidget* parent)
1448  : QTerminal (parent), d (new QConsolePrivate (this, cmd))
1449 {
1450 }
1451 
1452 //////////////////////////////////////////////////////////////////////////////
1453 
1455 {
1456  delete d;
1457 }
1458 
1459 void QWinTerminalImpl::mouseMoveEvent (QMouseEvent *event)
1460 {
1461  if (d->m_settingSelection)
1462  {
1463  d->m_endSelection = d->posToCell (event->pos ());
1464 
1465  updateSelection ();
1466  }
1467 }
1468 
1469 void QWinTerminalImpl::mousePressEvent (QMouseEvent *event)
1470 {
1471  if (allowTripleClick)
1472  {
1473  mouseTripleClickEvent (event);
1474  }
1475  else if (event->button () == Qt::LeftButton)
1476  {
1477  d->m_settingSelection = true;
1478 
1479  d->m_beginSelection = d->posToCell (event->pos ());
1480  }
1481 }
1482 
1483 void QWinTerminalImpl::mouseReleaseEvent (QMouseEvent *event)
1484 {
1485  if (event->button () == Qt::LeftButton && d->m_settingSelection)
1486  {
1487  d->m_endSelection = d->posToCell (event->pos ());
1488 
1489  updateSelection ();
1490 
1491  d->m_settingSelection = false;
1492  }
1493 }
1494 
1496 {
1497  if (event->button () == Qt::LeftButton)
1498  {
1499  // doubleclick - select word
1500  d->m_settingSelection = false;
1501 
1502  d->selectWord (d->posToCell (event->pos ()));
1503 
1504  allowTripleClick = true;
1505 
1506  QTimer::singleShot (QApplication::doubleClickInterval (),this,
1507  SLOT (tripleClickTimeout ()));
1508 
1509  }
1510 }
1511 
1513 {
1514  if (event->button () == Qt::LeftButton)
1515  {
1516  d->selectLine (d->posToCell (event->pos ()));
1517  }
1518 }
1519 
1521 {
1522  allowTripleClick = false;
1523 }
1524 
1525 //////////////////////////////////////////////////////////////////////////////
1526 
1528 {
1529  d->updateConsoleSize (true);
1530  d->grabConsoleBuffer ();
1531 }
1532 
1533 //////////////////////////////////////////////////////////////////////////////
1534 
1536 {
1537  QPainter p (w);
1538 
1539  int cw = d->m_charSize.width ();
1540  int ch = d->m_charSize.height ();
1541 
1542  QRect updateRect = event->rect ();
1543 
1544  int cx1 = updateRect.left () / cw;
1545  int cy1 = updateRect.top () / ch;
1546  int cx2 = qMin (d->m_consoleRect.width () - 1, updateRect.right () / cw);
1547  int cy2 = qMin (d->m_consoleRect.height () - 1, updateRect.bottom () / ch);
1548 
1549  if (cx1 > d->m_consoleRect.width () - 1
1550  || cy1 > d->m_consoleRect.height () - 1)
1551  return;
1552 
1553  d->drawTextBackground (p, cx1, cy1, cx2, cy2, cw, ch);
1554  d->drawSelection (p, cx1, cy1, cx2, cy2, cw, ch);
1555  d->drawCursor (p);
1556  d->drawText (p, cx1, cy1, cx2, cy2, cw, ch);
1557 }
1558 
1560 {
1561  if (d->m_hasBlinkingCursor)
1563  else
1564  d->m_cursorBlinking = false;
1565 
1566  d->m_consoleView->update (d->cursorRect ());
1567 }
1568 
1570 {
1571  d->m_hasBlinkingCursor = blink;
1572 
1573  setBlinkingCursorState (blink);
1574 }
1575 
1577 {
1578  if (blink && ! d->m_blinkCursorTimer->isActive ())
1579  d->m_blinkCursorTimer->start (d->BLINK_DELAY);
1580 
1581  if (! blink && d->m_blinkCursorTimer->isActive ())
1582  {
1583  d->m_blinkCursorTimer->stop ();
1584 
1585  if (d->m_cursorBlinking)
1586  blinkCursorEvent ();
1587  }
1588 }
1589 
1590 // Reset width of console buffer and terminal window to be the same.
1591 
1593 {
1594  d->updateConsoleSize (true, true);
1595 }
1596 
1597 //////////////////////////////////////////////////////////////////////////////
1598 
1599 void QWinTerminalImpl::wheelEvent (QWheelEvent* event)
1600 {
1601  if (! d->m_inWheelEvent)
1602  {
1603  // Forward to the scrollbar (avoid recursion)
1604  d->m_inWheelEvent = true;
1605  QApplication::sendEvent (d->m_verticalScrollBar, event);
1606  d->m_inWheelEvent = false;
1607  }
1608 }
1609 
1610 //////////////////////////////////////////////////////////////////////////////
1611 
1613 {
1614  d->setHorizontalScrollValue (value);
1615 }
1616 
1618 {
1619  d->setVerticalScrollValue (value);
1620 }
1621 
1622 //////////////////////////////////////////////////////////////////////////////
1623 
1625 {
1626  d->monitorConsole ();
1627 }
1628 
1630 {
1631  d->updateSelection ();
1632 }
1633 
1634 //////////////////////////////////////////////////////////////////////////////
1635 
1636 void QWinTerminalImpl::focusInEvent (QFocusEvent* event)
1637 {
1638  emit set_global_shortcuts_signal (false); // disable some shortcuts
1639 
1640  setBlinkingCursorState (true);
1641 
1642  QWidget::focusInEvent (event);
1643 }
1644 
1645 void QWinTerminalImpl::focusOutEvent (QFocusEvent* event)
1646 {
1647  emit set_global_shortcuts_signal (true); // re-enable shortcuts
1648 
1649  // Force the cursor to be redrawn.
1650  d->m_cursorBlinking = true;
1651 
1652  setBlinkingCursorState (false);
1653 
1654  QWidget::focusOutEvent (event);
1655 }
1656 
1657 bool QWinTerminalImpl::eventFilter (QObject *obj, QEvent * event)
1658 {
1659  // if a keypress, filter out tab keys so that the next/prev tabbing is
1660  // disabled - but we still need to pass along to the console .
1661  if (event->type () == QEvent::KeyPress)
1662  {
1663  QKeyEvent* k = static_cast<QKeyEvent*>(event);
1664  if (k->key () == Qt::Key_Tab)
1665  {
1666  sendText ("\t");
1667  return true;
1668  }
1669  }
1670  return false;
1671 }
1672 
1673 void QWinTerminalImpl::keyPressEvent (QKeyEvent* event)
1674 {
1675  QString s = translateKey (event);
1676  if (!s.isEmpty ())
1677  sendText (s);
1678 
1679  if (d->m_hasBlinkingCursor)
1680  {
1681  d->m_blinkCursorTimer->start (d->BLINK_DELAY);
1682 
1683  if (d->m_cursorBlinking)
1684  blinkCursorEvent ();
1685  }
1686 
1687  QWidget::keyPressEvent (event);
1688 }
1689 
1690 //////////////////////////////////////////////////////////////////////////////
1691 
1693 {
1694  d->startCommand ();
1695 }
1696 
1697 //////////////////////////////////////////////////////////////////////////////
1698 
1699 void QWinTerminalImpl::sendText (const QString& s)
1700 {
1701  d->sendConsoleText (s);
1702 }
1703 
1705 {
1706  switch (type)
1707  {
1708  case UnderlineCursor:
1710  break;
1711 
1712  case BlockCursor:
1714  break;
1715 
1716  case IBeamCursor:
1718  break;
1719  }
1720 
1721  setBlinkingCursor (blinking);
1722 }
1723 
1724 void QWinTerminalImpl::setBackgroundColor (const QColor& color)
1725 {
1726  d->setBackgroundColor (color);
1727 }
1728 
1729 void QWinTerminalImpl::setForegroundColor (const QColor& color)
1730 {
1731  d->setForegroundColor (color);
1732 }
1733 
1734 void QWinTerminalImpl::setSelectionColor (const QColor& color)
1735 {
1736  d->setSelectionColor (color);
1737 }
1738 
1739 void QWinTerminalImpl::setCursorColor (bool useForegroundColor,
1740  const QColor& color)
1741 {
1742  d->setCursorColor (useForegroundColor, color);
1743 }
1744 
1746 {
1747  d->setScrollBufferSize (value);
1748 }
1749 
1750 
1751 //////////////////////////////////////////////////////////////////////////////
1752 
1754 {
1755  d->m_font = f;
1756  d->m_consoleView->setFont (f);
1757  d->updateConsoleSize (true);
1758 }
1759 
1760 //////////////////////////////////////////////////////////////////////////////
1761 
1762 void QWinTerminalImpl::setSize (int columns, int lines)
1763 {
1764  d->log ("emit set_screen_size_signal (%d, %d)\n", columns, lines);
1765 
1766  emit set_screen_size_signal (columns, lines);
1767 }
1768 
1769 //////////////////////////////////////////////////////////////////////////////
1770 
1772 {
1773  if(!hasFocus()) return;
1774 
1775  QClipboard *clipboard = QApplication::clipboard ();
1776 
1777  QString selection = d->getSelection ();
1778 
1779  if (selection.isEmpty ())
1780  {
1781  if (! _extra_interrupt)
1782  terminal_interrupt ();
1783  }
1784  else
1785  {
1786  clipboard->setText (selection);
1787  emit report_status_message (tr ("copied selection to clipboard"));
1788  }
1789 }
1790 
1791 //////////////////////////////////////////////////////////////////////////////
1792 
1794 {
1795  if(!hasFocus()) return;
1796 
1797  QString text = QApplication::clipboard()->text (QClipboard::Clipboard);
1798 
1799  if (! text.isEmpty ())
1800  sendText (text);
1801 }
1802 
1803 //////////////////////////////////////////////////////////////////////////////
1804 
1806 {
1807  if(!hasFocus()) return;
1808 
1809  d->selectAll();
1810 }
1811 
1812 
1813 
1814 //////////////////////////////////////////////////////////////////////////////
1815 
1817 {
1818  QString selection = d->getSelection ();
1819  return selection;
1820 }
1821 
1822 //////////////////////////////////////////////////////////////////////////////
1823 
1824 void QWinTerminalImpl::dragEnterEvent (QDragEnterEvent *event)
1825 {
1826  if (event->mimeData ()->hasUrls ())
1827  {
1828  event->acceptProposedAction();
1829  }
1830 }
1831 
1832 //////////////////////////////////////////////////////////////////////////////
1833 
1834 void QWinTerminalImpl::dropEvent (QDropEvent *event)
1835 {
1836  QString dropText;
1837 
1838  if (event->mimeData ()->hasUrls ())
1839  {
1840  foreach (QUrl url, event->mimeData ()->urls ())
1841  {
1842  if(dropText.length () > 0)
1843  dropText += "\n";
1844  dropText += url.toLocalFile ();
1845  }
1846  sendText (dropText);
1847  }
1848 }
1849 
1850 //////////////////////////////////////////////////////////////////////////////
1851 
1853 {
1854  _extra_interrupt = extra;
1855 }
QScrollBar * m_verticalScrollBar
#define TEXT_CHUNK_SIZE
int dup2(int old_fd, int new_fd)
Definition: oct-syscalls.cc:50
QConsoleView * m_consoleView
void horizontalScrollValueChanged(int value)
void resizeEvent(QResizeEvent *event)
void setScrollBufferSize(int value)
void setBlinkingCursor(bool blink)
QConsoleThread * m_consoleThread
void updateHorizontalScrollBar(void)
void log(const char *fmt,...)
void focusOutEvent(QFocusEvent *)
friend class QConsoleView
void drawSelection(QPainter &p, int cx1, int cy1, int cx2, int cy2, int cw, int ch)
void setCursorType(CursorType type, bool blinking)
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &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 F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE const F77_DBLE * f
fclose(in)
for large enough k
Definition: lu.cc:606
void selectWord(const QPoint &cellPos)
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a number
Definition: input.cc:871
CHAR_INFO * m_tmpBuffer
void tripleClickTimeout(void)
void terminal_interrupt(void)
Definition: QTerminal.h:113
void updateConsoleView(bool grab=true)
QConsolePrivate(QWinTerminalImpl *parent, const QString &cmd=QString())
void set_global_shortcuts_signal(bool)
void titleChanged(const QString &)
void syncConsoleParameters(void)
void updateSelection(void)
QColor backgroundColor(void) const
friend class QConsoleThread
void terminated(void)
QWinTerminalImpl * q
s
Definition: file-io.cc:2682
void closeStandardIO(int fd, DWORD stdHandleId, const char *name)
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &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 F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
QConsoleColors m_colors
void updateConsoleSize(bool sync=false, bool allow_smaller_width=false)
QWinTerminalImpl * q
void init_terminal_size(void)
void sendConsoleText(const QString &s)
void grabConsoleBuffer(CHAR_INFO *buf=0)
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
void setCursorColor(bool useForegoundColor, const QColor &color)
void setSelectionColor(const QColor &color)
void report_status_message(const QString &)
void set_global_shortcuts(bool focus_out)
Definition: QTerminal.cc:76
static const int BLINK_DELAY
text(const graphics_handle &mh, const graphics_handle &p)
Definition: graphics.h:8570
void verticalScrollValueChanged(int value)
std::complex< double > w(std::complex< double > z, double relerr=0)
QString getSelection(void)
void clearSelection(void)
QConsoleView(QWinTerminalImpl *parent=0)
void setHorizontalScrollValue(int value)
void setForegroundColor(const QColor &color)
double timeout
Definition: graphics.cc:11592
QColor foregroundColor(void) const
is false
Definition: cellfun.cc:398
void mouseReleaseEvent(QMouseEvent *event)
void keyPressEvent(QKeyEvent *)
static QString translateKey(QKeyEvent *ev)
void setScrollBufferSize(int value)
void sendText(const QString &s)
returns the type of the matrix and caches it for future use Called with more than one the function will not attempt to guess the type if it is still unknown This is useful for debugging purposes The possible matrix types depend on whether the matrix is full or and can be one of the following able sis tem and mark type as unknown tem as the structure of the matrix explicitly gives this(Sparse matrices only) tem code
Definition: matrix_type.cc:120
QColor selectionColor(void) const
virtual void start(void)
void paintEvent(QPaintEvent *event)
idx type
Definition: ov.cc:3129
void mouseTripleClickEvent(QMouseEvent *event)
the sparsity preserving column transformation such that that defines the pivoting threshold can be given in which case it defines the c
Definition: lu.cc:138
void focusInEvent(QFocusEvent *)
void set_screen_size_signal(int, int)
QPoint posToCell(const QPoint &pt)
void setSize(int columns, int lines)
std::string url
Definition: urlwrite.cc:337
QConsolePrivate * d
void setBackgroundColor(const QColor &color)
void setBackgroundColor(const QColor &color)
void has_extra_interrupt(bool)
void setBlinkingCursorState(bool blink)
void viewPaintEvent(QConsoleView *, QPaintEvent *)
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
#define INFINITE
Definition: randgamma.cc:89
QColor cursorColor(void) const
p
Definition: lu.cc:138
OCTAVE_EXPORT octave_value_list or N dimensional array whose elements are all equal to the IEEE symbol zero divided by nd tex zero divided by nd ifnottex and any operation involving another NaN value(5+NaN).Note that NaN always compares not equal to NaN(NaN!
QWinTerminalImpl * q
void dropEvent(QDropEvent *event)
void drawTextBackground(QPainter &p, int cx1, int cy1, int cx2, int cy2, int cw, int ch)
void setTerminalFont(const QFont &font)
void viewResizeEvent(QConsoleView *, QResizeEvent *)
bool eventFilter(QObject *obj, QEvent *ev)
void setForegroundColor(const QColor &color)
the element is set to zero In other the statement xample y
Definition: data.cc:5342
QWinTerminalImpl(QWidget *parent=0)
void dragEnterEvent(QDragEnterEvent *event)
void mouseMoveEvent(QMouseEvent *event)
#define LOGFILENAME
void drawText(QPainter &p, int cx1, int cy1, int cx2, int cy2, int cw, int ch)
QConsoleThread(QWinTerminalImpl *console)
void setVerticalScrollValue(int value)
void setSelectionColor(const QColor &color)
void mouseDoubleClickEvent(QMouseEvent *event)
void mousePressEvent(QMouseEvent *event)
static void maybeSwapPoints(QPoint &begin, QPoint &end)
void wheelEvent(QWheelEvent *)
void updateVerticalScrollBar(void)
KeyboardCursorType m_cursorType
void drawCursor(QPainter &p)
void selectLine(const QPoint &cellPos)
void setCursorColor(bool useForegroundColor, const QColor &color)
void setupStandardIO(DWORD stdHandleId, int fd, const char *name, const char *devName)
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &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 F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x
QScrollBar * m_horizontalScrollBar
static const double pi
Definition: lo-specfun.cc:3610