1/* Copyright (C) 2008 e_k (e_k@users.sourceforge.net)
2
3 This library is free software; you can redistribute it and/or
4 modify it under the terms of the GNU Library General Public
5 License as published by the Free Software Foundation; either
6 version 2 of the License, or (at your option) any later version.
7
8 This library is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 Library General Public License for more details.
12
13 You should have received a copy of the GNU Library General Public License
14 along with this library; see the file COPYING.LIB. If not, write to
15 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 Boston, MA 02110-1301, USA.
17*/
18
19#include <QLayout>
20#include <QBoxLayout>
21#include <QtDebug>
22#include <QDir>
23#include <QMessageBox>
24
25#include "ColorTables.h"
26#include "Session.h"
27#include "Screen.h"
28#include "ScreenWindow.h"
29#include "Emulation.h"
30#include "TerminalDisplay.h"
31#include "KeyboardTranslator.h"
32#include "ColorScheme.h"
33#include "SearchBar.h"
34#include "qtermwidget.h"
35
36
37#define STEP_ZOOM 1
38
39using namespace Konsole;
40
41void *createTermWidget(int startnow, void *parent)
42{
43 return (void*) new QTermWidget(startnow, (QWidget*)parent);
44}
45
46struct TermWidgetImpl {
47 TermWidgetImpl(QWidget* parent = 0);
48
49 TerminalDisplay *m_terminalDisplay;
50 Session *m_session;
51
52 Session* createSession(QWidget* parent);
53 TerminalDisplay* createTerminalDisplay(Session *session, QWidget* parent);
54};
55
56TermWidgetImpl::TermWidgetImpl(QWidget* parent)
57{
58 this->m_session = createSession(parent);
59 this->m_terminalDisplay = createTerminalDisplay(this->m_session, parent);
60}
61
62
63Session *TermWidgetImpl::createSession(QWidget* parent)
64{
65 Session *session = new Session(parent);
66
67 session->setTitle(Session::NameRole, QLatin1String("QTermWidget"));
68
69 /* Thats a freaking bad idea!!!!
70 * /bin/bash is not there on every system
71 * better set it to the current $SHELL
72 * Maybe you can also make a list available and then let the widget-owner decide what to use.
73 * By setting it to $SHELL right away we actually make the first filecheck obsolete.
74 * But as iam not sure if you want to do anything else ill just let both checks in and set this to $SHELL anyway.
75 */
76 //session->setProgram("/bin/bash");
77
78 session->setProgram(QString::fromLocal8Bit(qgetenv("SHELL")));
79
80
81
82 QStringList args = QStringList(QString());
83 session->setArguments(args);
84 session->setAutoClose(true);
85
86 session->setCodec(QTextCodec::codecForName("UTF-8"));
87
88 session->setFlowControlEnabled(true);
89 session->setHistoryType(HistoryTypeBuffer(1000));
90
91 session->setDarkBackground(true);
92
93 session->setKeyBindings(QString());
94 return session;
95}
96
97TerminalDisplay *TermWidgetImpl::createTerminalDisplay(Session *session, QWidget* parent)
98{
99// TerminalDisplay* display = new TerminalDisplay(this);
100 TerminalDisplay* display = new TerminalDisplay(parent);
101
102 display->setBellMode(TerminalDisplay::NotifyBell);
103 display->setTerminalSizeHint(true);
104 display->setTripleClickMode(TerminalDisplay::SelectWholeLine);
105 display->setTerminalSizeStartup(true);
106
107 display->setRandomSeed(session->sessionId() * 31);
108
109 return display;
110}
111
112
113QTermWidget::QTermWidget(int startnow, QWidget *parent)
114 : QWidget(parent)
115{
116 init(startnow);
117}
118
119QTermWidget::QTermWidget(QWidget *parent)
120 : QWidget(parent)
121{
122 init(1);
123}
124
125void QTermWidget::selectionChanged(bool textSelected)
126{
127 emit copyAvailable(textSelected);
128}
129
130void QTermWidget::find()
131{
132 search(true, false);
133}
134
135void QTermWidget::findNext()
136{
137 search(true, true);
138}
139
140void QTermWidget::findPrevious()
141{
142 search(false, false);
143}
144
145void QTermWidget::search(bool forwards, bool next)
146{
147 int startColumn, startLine;
148
149 if (next) // search from just after current selection
150 {
151 m_impl->m_terminalDisplay->screenWindow()->screen()->getSelectionEnd(startColumn, startLine);
152 startColumn++;
153 }
154 else // search from start of current selection
155 {
156 m_impl->m_terminalDisplay->screenWindow()->screen()->getSelectionStart(startColumn, startLine);
157 }
158
159 qDebug() << "current selection starts at: " << startColumn << startLine;
160 qDebug() << "current cursor position: " << m_impl->m_terminalDisplay->screenWindow()->cursorPosition();
161
162 QRegExp regExp(m_searchBar->searchText());
163 regExp.setPatternSyntax(m_searchBar->useRegularExpression() ? QRegExp::RegExp : QRegExp::FixedString);
164 regExp.setCaseSensitivity(m_searchBar->matchCase() ? Qt::CaseSensitive : Qt::CaseInsensitive);
165
166 HistorySearch *historySearch =
167 new HistorySearch(m_impl->m_session->emulation(), regExp, forwards, startColumn, startLine, this);
168 connect(historySearch, SIGNAL(matchFound(int, int, int, int)), this, SLOT(matchFound(int, int, int, int)));
169 connect(historySearch, SIGNAL(noMatchFound()), this, SLOT(noMatchFound()));
170 connect(historySearch, SIGNAL(noMatchFound()), m_searchBar, SLOT(noMatchFound()));
171 historySearch->search();
172}
173
174
175void QTermWidget::matchFound(int startColumn, int startLine, int endColumn, int endLine)
176{
177 ScreenWindow* sw = m_impl->m_terminalDisplay->screenWindow();
178 qDebug() << "Scroll to" << startLine;
179 sw->scrollTo(startLine);
180 sw->setTrackOutput(false);
181 sw->notifyOutputChanged();
182 sw->setSelectionStart(startColumn, startLine - sw->currentLine(), false);
183 sw->setSelectionEnd(endColumn, endLine - sw->currentLine());
184}
185
186void QTermWidget::noMatchFound()
187{
188 m_impl->m_terminalDisplay->screenWindow()->clearSelection();
189}
190
191int QTermWidget::getShellPID()
192{
193 return m_impl->m_session->processId();
194}
195
196void QTermWidget::changeDir(const QString & dir)
197{
198 /*
199 this is a very hackish way of trying to determine if the shell is in
200 the foreground before attempting to change the directory. It may not
201 be portable to anything other than Linux.
202 */
203 QString strCmd;
204 strCmd.setNum(getShellPID());
205 strCmd.prepend(QLatin1String("ps -j "));
206 strCmd.append(QLatin1String(" | tail -1 | awk '{ print $5 }' | grep -q \\+"));
207 int retval = system(strCmd.toStdString().c_str());
208
209 if (!retval) {
210 QString cmd = QLatin1String("cd ") + dir + QLatin1Char('\n');
211 sendText(cmd);
212 }
213}
214
215QSize QTermWidget::sizeHint() const
216{
217 QSize size = m_impl->m_terminalDisplay->sizeHint();
218 size.rheight() = 150;
219 return size;
220}
221
222void QTermWidget::setTerminalSizeHint(bool on)
223{
224 m_impl->m_terminalDisplay->setTerminalSizeHint(on);
225}
226
227bool QTermWidget::terminalSizeHint()
228{
229 return m_impl->m_terminalDisplay->terminalSizeHint();
230}
231
232void QTermWidget::startShellProgram()
233{
234 if ( m_impl->m_session->isRunning() ) {
235 return;
236 }
237
238 m_impl->m_session->run();
239}
240
241void QTermWidget::startTerminalTeletype()
242{
243 if ( m_impl->m_session->isRunning() ) {
244 return;
245 }
246
247 m_impl->m_session->runEmptyPTY();
248 // redirect data from TTY to external recipient
249 connect( m_impl->m_session->emulation(), SIGNAL(sendData(const char *,int)),
250 this, SIGNAL(sendData(const char *,int)) );
251}
252
253void QTermWidget::init(int startnow)
254{
255 m_layout = new QVBoxLayout();
256 m_layout->setMargin(0);
257 setLayout(m_layout);
258
259 // translations
260 // First check $XDG_DATA_DIRS. This follows the implementation in libqtxdg
261 QString d = QFile::decodeName(qgetenv("XDG_DATA_DIRS"));
262 QStringList dirs = d.split(QLatin1Char(':'), QString::SkipEmptyParts);
263 if (dirs.isEmpty()) {
264 dirs.append(QString::fromLatin1("/usr/local/share"));
265 dirs.append(QString::fromLatin1("/usr/share"));
266 }
267 dirs.append(QFile::decodeName(TRANSLATIONS_DIR));
268
269 m_translator = new QTranslator(this);
270
271 for (const QString& dir : dirs) {
272 qDebug() << "Trying to load translation file from dir" << dir;
273 if (m_translator->load(QLocale::system(), QLatin1String("qtermwidget"), QLatin1String(QLatin1String("_")), dir)) {
274 qApp->installTranslator(m_translator);
275 qDebug() << "Translations found in" << dir;
276 break;
277 }
278 }
279
280 m_impl = new TermWidgetImpl(this);
281 m_layout->addWidget(m_impl->m_terminalDisplay);
282
283 connect(m_impl->m_session, SIGNAL(bellRequest(QString)), m_impl->m_terminalDisplay, SLOT(bell(QString)));
284 connect(m_impl->m_terminalDisplay, SIGNAL(notifyBell(QString)), this, SIGNAL(bell(QString)));
285
286 connect(m_impl->m_session, SIGNAL(activity()), this, SIGNAL(activity()));
287 connect(m_impl->m_session, SIGNAL(silence()), this, SIGNAL(silence()));
288 connect(m_impl->m_session, &Session::profileChangeCommandReceived, this, &QTermWidget::profileChanged);
289 connect(m_impl->m_session, &Session::receivedData, this, &QTermWidget::receivedData);
290
291 // That's OK, FilterChain's dtor takes care of UrlFilter.
292 UrlFilter *urlFilter = new UrlFilter();
293 connect(urlFilter, &UrlFilter::activated, this, &QTermWidget::urlActivated);
294 m_impl->m_terminalDisplay->filterChain()->addFilter(urlFilter);
295
296 m_searchBar = new SearchBar(this);
297 m_searchBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
298 connect(m_searchBar, SIGNAL(searchCriteriaChanged()), this, SLOT(find()));
299 connect(m_searchBar, SIGNAL(findNext()), this, SLOT(findNext()));
300 connect(m_searchBar, SIGNAL(findPrevious()), this, SLOT(findPrevious()));
301 m_layout->addWidget(m_searchBar);
302 m_searchBar->hide();
303
304 if (startnow && m_impl->m_session) {
305 m_impl->m_session->run();
306 }
307
308 this->setFocus( Qt::OtherFocusReason );
309 this->setFocusPolicy( Qt::WheelFocus );
310 m_impl->m_terminalDisplay->resize(this->size());
311
312 this->setFocusProxy(m_impl->m_terminalDisplay);
313 connect(m_impl->m_terminalDisplay, SIGNAL(copyAvailable(bool)),
314 this, SLOT(selectionChanged(bool)));
315 connect(m_impl->m_terminalDisplay, SIGNAL(termGetFocus()),
316 this, SIGNAL(termGetFocus()));
317 connect(m_impl->m_terminalDisplay, SIGNAL(termLostFocus()),
318 this, SIGNAL(termLostFocus()));
319 connect(m_impl->m_terminalDisplay, SIGNAL(keyPressedSignal(QKeyEvent *)),
320 this, SIGNAL(termKeyPressed(QKeyEvent *)));
321// m_impl->m_terminalDisplay->setSize(80, 40);
322
323 QFont font = QApplication::font();
324 font.setFamily(QLatin1String("Monospace"));
325 font.setPointSize(10);
326 font.setStyleHint(QFont::TypeWriter);
327 setTerminalFont(font);
328 m_searchBar->setFont(font);
329
330 setScrollBarPosition(NoScrollBar);
331 setKeyboardCursorShape(Emulation::KeyboardCursorShape::BlockCursor);
332
333 m_impl->m_session->addView(m_impl->m_terminalDisplay);
334
335 connect(m_impl->m_session, SIGNAL(resizeRequest(QSize)), this, SLOT(setSize(QSize)));
336 connect(m_impl->m_session, SIGNAL(finished()), this, SLOT(sessionFinished()));
337 connect(m_impl->m_session, &Session::titleChanged, this, &QTermWidget::titleChanged);
338 connect(m_impl->m_session, &Session::cursorChanged, this, &QTermWidget::cursorChanged);
339}
340
341
342QTermWidget::~QTermWidget()
343{
344 delete m_impl;
345 emit destroyed();
346}
347
348
349void QTermWidget::setTerminalFont(const QFont &font)
350{
351 m_impl->m_terminalDisplay->setVTFont(font);
352}
353
354QFont QTermWidget::getTerminalFont()
355{
356 return m_impl->m_terminalDisplay->getVTFont();
357}
358
359void QTermWidget::setTerminalOpacity(qreal level)
360{
361 m_impl->m_terminalDisplay->setOpacity(level);
362}
363
364void QTermWidget::setTerminalBackgroundImage(QString backgroundImage)
365{
366 m_impl->m_terminalDisplay->setBackgroundImage(backgroundImage);
367}
368
369void QTermWidget::setShellProgram(const QString &progname)
370{
371 if (!m_impl->m_session)
372 return;
373 m_impl->m_session->setProgram(progname);
374}
375
376void QTermWidget::setWorkingDirectory(const QString& dir)
377{
378 if (!m_impl->m_session)
379 return;
380 m_impl->m_session->setInitialWorkingDirectory(dir);
381}
382
383QString QTermWidget::workingDirectory()
384{
385 if (!m_impl->m_session)
386 return QString();
387
388#ifdef Q_OS_LINUX
389 // Christian Surlykke: On linux we could look at /proc/<pid>/cwd which should be a link to current
390 // working directory (<pid>: process id of the shell). I don't know about BSD.
391 // Maybe we could just offer it when running linux, for a start.
392 QDir d(QString::fromLatin1("/proc/%1/cwd").arg(getShellPID()));
393 if (!d.exists())
394 {
395 qDebug() << "Cannot find" << d.dirName();
396 goto fallback;
397 }
398 return d.canonicalPath();
399#endif
400
401fallback:
402 // fallback, initial WD
403 return m_impl->m_session->initialWorkingDirectory();
404}
405
406void QTermWidget::setArgs(const QStringList &args)
407{
408 if (!m_impl->m_session)
409 return;
410 m_impl->m_session->setArguments(args);
411}
412
413void QTermWidget::setTextCodec(QTextCodec *codec)
414{
415 if (!m_impl->m_session)
416 return;
417 m_impl->m_session->setCodec(codec);
418}
419
420void QTermWidget::setColorScheme(const QString& origName)
421{
422 const ColorScheme *cs = 0;
423
424 const bool isFile = QFile::exists(origName);
425 const QString& name = isFile ?
426 QFileInfo(origName).baseName() :
427 origName;
428
429 // avoid legacy (int) solution
430 if (!availableColorSchemes().contains(name))
431 {
432 if (isFile)
433 {
434 if (ColorSchemeManager::instance()->loadCustomColorScheme(origName))
435 cs = ColorSchemeManager::instance()->findColorScheme(name);
436 else
437 qWarning () << Q_FUNC_INFO
438 << "cannot load color scheme from"
439 << origName;
440 }
441
442 if (!cs)
443 cs = ColorSchemeManager::instance()->defaultColorScheme();
444 }
445 else
446 cs = ColorSchemeManager::instance()->findColorScheme(name);
447
448 if (! cs)
449 {
450 QMessageBox::information(this,
451 tr("Color Scheme Error"),
452 tr("Cannot load color scheme: %1").arg(name));
453 return;
454 }
455 ColorEntry table[TABLE_COLORS];
456 cs->getColorTable(table);
457 m_impl->m_terminalDisplay->setColorTable(table);
458}
459
460QStringList QTermWidget::availableColorSchemes()
461{
462 QStringList ret;
463 const auto allColorSchemes = ColorSchemeManager::instance()->allColorSchemes();
464 for (const ColorScheme* cs : allColorSchemes)
465 ret.append(cs->name());
466 return ret;
467}
468
469void QTermWidget::addCustomColorSchemeDir(const QString& custom_dir)
470{
471 ColorSchemeManager::instance()->addCustomColorSchemeDir(custom_dir);
472}
473
474void QTermWidget::setSize(const QSize &size)
475{
476 m_impl->m_terminalDisplay->setSize(size.width(), size.height());
477}
478
479void QTermWidget::setHistorySize(int lines)
480{
481 if (lines < 0)
482 m_impl->m_session->setHistoryType(HistoryTypeFile());
483 else
484 m_impl->m_session->setHistoryType(HistoryTypeBuffer(lines));
485}
486
487void QTermWidget::setScrollBarPosition(ScrollBarPosition pos)
488{
489 m_impl->m_terminalDisplay->setScrollBarPosition(pos);
490}
491
492void QTermWidget::scrollToEnd()
493{
494 m_impl->m_terminalDisplay->scrollToEnd();
495}
496
497void QTermWidget::sendText(const QString &text)
498{
499 m_impl->m_session->sendText(text);
500}
501
502void QTermWidget::resizeEvent(QResizeEvent*)
503{
504//qDebug("global window resizing...with %d %d", this->size().width(), this->size().height());
505 m_impl->m_terminalDisplay->resize(this->size());
506}
507
508
509void QTermWidget::sessionFinished()
510{
511 emit finished();
512}
513
514void QTermWidget::bracketText(QString& text)
515{
516 m_impl->m_terminalDisplay->bracketText(text);
517}
518
519void QTermWidget::copyClipboard()
520{
521 m_impl->m_terminalDisplay->copyClipboard();
522}
523
524void QTermWidget::pasteClipboard()
525{
526 m_impl->m_terminalDisplay->pasteClipboard();
527}
528
529void QTermWidget::pasteSelection()
530{
531 m_impl->m_terminalDisplay->pasteSelection();
532}
533
534void QTermWidget::setZoom(int step)
535{
536 QFont font = m_impl->m_terminalDisplay->getVTFont();
537
538 font.setPointSize(font.pointSize() + step);
539 setTerminalFont(font);
540}
541
542void QTermWidget::zoomIn()
543{
544 setZoom(STEP_ZOOM);
545}
546
547void QTermWidget::zoomOut()
548{
549 setZoom(-STEP_ZOOM);
550}
551
552void QTermWidget::setKeyBindings(const QString & kb)
553{
554 m_impl->m_session->setKeyBindings(kb);
555}
556
557void QTermWidget::clear()
558{
559 m_impl->m_session->emulation()->reset();
560 m_impl->m_session->refresh();
561 m_impl->m_session->clearHistory();
562}
563
564void QTermWidget::setFlowControlEnabled(bool enabled)
565{
566 m_impl->m_session->setFlowControlEnabled(enabled);
567}
568
569QStringList QTermWidget::availableKeyBindings()
570{
571 return KeyboardTranslatorManager::instance()->allTranslators();
572}
573
574QString QTermWidget::keyBindings()
575{
576 return m_impl->m_session->keyBindings();
577}
578
579void QTermWidget::toggleShowSearchBar()
580{
581 m_searchBar->isHidden() ? m_searchBar->show() : m_searchBar->hide();
582}
583
584bool QTermWidget::flowControlEnabled(void)
585{
586 return m_impl->m_session->flowControlEnabled();
587}
588
589void QTermWidget::setFlowControlWarningEnabled(bool enabled)
590{
591 if (flowControlEnabled()) {
592 // Do not show warning label if flow control is disabled
593 m_impl->m_terminalDisplay->setFlowControlWarningEnabled(enabled);
594 }
595}
596
597void QTermWidget::setEnvironment(const QStringList& environment)
598{
599 m_impl->m_session->setEnvironment(environment);
600}
601
602void QTermWidget::setMotionAfterPasting(int action)
603{
604 m_impl->m_terminalDisplay->setMotionAfterPasting((Konsole::MotionAfterPasting) action);
605}
606
607int QTermWidget::historyLinesCount()
608{
609 return m_impl->m_terminalDisplay->screenWindow()->screen()->getHistLines();
610}
611
612int QTermWidget::screenColumnsCount()
613{
614 return m_impl->m_terminalDisplay->screenWindow()->screen()->getColumns();
615}
616
617int QTermWidget::screenLinesCount()
618{
619 return m_impl->m_terminalDisplay->screenWindow()->screen()->getLines();
620}
621
622void QTermWidget::setSelectionStart(int row, int column)
623{
624 m_impl->m_terminalDisplay->screenWindow()->screen()->setSelectionStart(column, row, true);
625}
626
627void QTermWidget::setSelectionEnd(int row, int column)
628{
629 m_impl->m_terminalDisplay->screenWindow()->screen()->setSelectionEnd(column, row);
630}
631
632void QTermWidget::getSelectionStart(int& row, int& column)
633{
634 m_impl->m_terminalDisplay->screenWindow()->screen()->getSelectionStart(column, row);
635}
636
637void QTermWidget::getSelectionEnd(int& row, int& column)
638{
639 m_impl->m_terminalDisplay->screenWindow()->screen()->getSelectionEnd(column, row);
640}
641
642QString QTermWidget::selectedText(bool preserveLineBreaks)
643{
644 return m_impl->m_terminalDisplay->screenWindow()->screen()->selectedText(preserveLineBreaks);
645}
646
647void QTermWidget::setMonitorActivity(bool monitor)
648{
649 m_impl->m_session->setMonitorActivity(monitor);
650}
651
652void QTermWidget::setMonitorSilence(bool monitor)
653{
654 m_impl->m_session->setMonitorSilence(monitor);
655}
656
657void QTermWidget::setSilenceTimeout(int seconds)
658{
659 m_impl->m_session->setMonitorSilenceSeconds(seconds);
660}
661
662Filter::HotSpot* QTermWidget::getHotSpotAt(const QPoint &pos) const
663{
664 int row = 0, column = 0;
665 m_impl->m_terminalDisplay->getCharacterPosition(pos, row, column);
666 return getHotSpotAt(row, column);
667}
668
669Filter::HotSpot* QTermWidget::getHotSpotAt(int row, int column) const
670{
671 return m_impl->m_terminalDisplay->filterChain()->hotSpotAt(row, column);
672}
673
674QList<QAction*> QTermWidget::filterActions(const QPoint& position)
675{
676 return m_impl->m_terminalDisplay->filterActions(position);
677}
678
679int QTermWidget::getPtySlaveFd() const
680{
681 return m_impl->m_session->getPtySlaveFd();
682}
683
684void QTermWidget::setKeyboardCursorShape(KeyboardCursorShape shape)
685{
686 m_impl->m_terminalDisplay->setKeyboardCursorShape(shape);
687}
688
689void QTermWidget::setBlinkingCursor(bool blink)
690{
691 m_impl->m_terminalDisplay->setBlinkingCursor(blink);
692}
693
694void QTermWidget::setBidiEnabled(bool enabled)
695{
696 m_impl->m_terminalDisplay->setBidiEnabled(enabled);
697}
698
699bool QTermWidget::isBidiEnabled()
700{
701 return m_impl->m_terminalDisplay->isBidiEnabled();
702}
703
704QString QTermWidget::title() const
705{
706 QString title = m_impl->m_session->userTitle();
707 if (title.isEmpty())
708 title = m_impl->m_session->title(Konsole::Session::NameRole);
709 return title;
710}
711
712QString QTermWidget::icon() const
713{
714 QString icon = m_impl->m_session->iconText();
715 if (icon.isEmpty())
716 icon = m_impl->m_session->iconName();
717 return icon;
718}
719
720bool QTermWidget::isTitleChanged() const
721{
722 return m_impl->m_session->isTitleChanged();
723}
724
725void QTermWidget::setAutoClose(bool autoClose)
726{
727 m_impl->m_session->setAutoClose(autoClose);
728}
729
730void QTermWidget::cursorChanged(Konsole::Emulation::KeyboardCursorShape cursorShape, bool blinkingCursorEnabled)
731{
732 // TODO: A switch to enable/disable DECSCUSR?
733 setKeyboardCursorShape(cursorShape);
734 setBlinkingCursor(blinkingCursorEnabled);
735}
736
737void QTermWidget::setMargin(int margin)
738{
739 m_impl->m_terminalDisplay->setMargin(margin);
740}
741
742int QTermWidget::getMargin() const
743{
744 return m_impl->m_terminalDisplay->margin();
745}
746