2 * Copyright Johannes Sixt
3 * This file is licensed under the GNU General Public License Version 2.
4 * See the file COPYING in the toplevel directory of the source directory.
8 #include <QSocketNotifier>
9 #include <QContextMenuEvent>
10 #include <QFontDatabase>
12 #include <klocalizedstring.h>
16 #include <unistd.h> /* open, close, etc. */
17 #include <sys/ioctl.h>
20 #include <pty.h> /* openpty on Linux */
23 #include <libutil.h> /* openpty on FreeBSD */
25 #ifdef HAVE_UTIL_H /* openpty on NetBSD, OpenBSD */
41 ::fcntl(m_masterfd
, F_SETFL
, O_NDELAY
);
42 m_outNotifier
= new QSocketNotifier(m_masterfd
, QSocketNotifier::Read
);
43 connect(m_outNotifier
, SIGNAL(activated(int)), SLOT(outReceived(int)));
45 m_slavetty
= QString();
63 #ifdef HAVE_FUNC_OPENPTY
64 /* use glibc2's openpty */
67 if (::openpty(&m_masterfd
, &m_slavefd
, 0, 0, 0) == 0) {
68 const char* tname
= ::ttyname(m_slavefd
);
74 m_masterfd
= m_slavefd
= -1;
80 // resort to BSD-style terminals
86 char ptynam
[] = "/dev/ptyxx";
87 char ttynam
[] = "/dev/ttyxx";
88 static const char ptyc3
[] = "pqrstuvwxyzabcde";
89 static const char ptyc4
[] = "0123456789abcdef";
91 // Find a master pty that we can open
92 for (s3
= ptyc3
; *s3
!= 0 && m_masterfd
< 0; s3
++)
94 for (s4
= ptyc4
; *s4
!= 0; s4
++)
96 ptynam
[8] = ttynam
[8] = *s3
;
97 ptynam
[9] = ttynam
[9] = *s4
;
98 if ((m_masterfd
= ::open(ptynam
,O_RDWR
)) >= 0)
100 if (::geteuid() == 0 || ::access(ttynam
,R_OK
|W_OK
) == 0)
112 return m_masterfd
>= 0;
115 void STTY::outReceived(int f
)
119 int n
= ::read(f
, buf
, sizeof(buf
));
121 if (errno
!= EAGAIN
) { /* this is not an error */
122 // ugh! error! somebody disconnect this signal please!
134 TTYWindow::TTYWindow(QWidget
* parent
) :
135 QPlainTextEdit(parent
),
139 setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont
));
141 setWordWrapMode(QTextOption::NoWrap
);
142 setUndoRedoEnabled(false);
143 m_pos
.setPosition(0);
146 TTYWindow::~TTYWindow()
153 QString
TTYWindow::activate()
155 // allocate a pseudo terminal
158 QString ttyName
= m_tty
->slaveTTY();
159 if (ttyName
.isEmpty()) {
160 // failed to allocate terminal
165 connect(m_tty
, SIGNAL(output(char*,int)), SLOT(slotAppend(char*,int)));
170 void TTYWindow::deactivate()
176 void TTYWindow::slotAppend(char* buffer
, int count
)
179 char* start
= buffer
;
182 while (count
> 0 && start
[len
] != '\n' && start
[len
] != '\r') {
187 QString str
= QString::fromLatin1(start
, len
);
188 // replace text in the last line
189 // this selection is non-empty only after a '\r' that was not
190 // followed by a '\n'
191 m_pos
.movePosition(QTextCursor::Right
, QTextCursor::KeepAnchor
, len
);
192 m_pos
.insertText(str
);
196 if (count
> 0 && *start
== '\r') {
199 m_pos
.movePosition(QTextCursor::StartOfLine
);
201 if (count
> 0 && *start
== '\n') {
204 m_pos
.movePosition(QTextCursor::End
);
205 m_pos
.insertText(QString('\n'));
210 void TTYWindow::contextMenuEvent(QContextMenuEvent
*event
)
212 QMenu
* menu
= createStandardContextMenu();
213 menu
->addSeparator();
214 menu
->addAction(i18n("&Clear"),this, SLOT(slotClear()));
215 menu
->exec(event
->globalPos());
219 void TTYWindow::slotClear()
222 m_pos
.movePosition(QTextCursor::End
);
225 #include "ttywnd.moc"