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.
7 #include <qsocketnotifier.h>
8 #include <qpopupmenu.h>
10 #include <kglobalsettings.h>
18 #include <unistd.h> /* open, close, etc. */
20 #ifdef HAVE_SYS_IOCTL_H
21 #include <sys/ioctl.h>
23 #ifdef HAVE_SYS_STAT_H
27 #include <pty.h> /* openpty on Linux */
30 #include <libutil.h> /* openpty on FreeBSD */
32 #ifdef HAVE_UTIL_H /* openpty on NetBSD, OpenBSD */
48 ::fcntl(m_masterfd
, F_SETFL
, O_NDELAY
);
49 m_outNotifier
= new QSocketNotifier(m_masterfd
, QSocketNotifier::Read
);
50 connect(m_outNotifier
, SIGNAL(activated(int)), SLOT(outReceived(int)));
52 m_slavetty
= QString();
70 #ifdef HAVE_FUNC_OPENPTY
71 /* use glibc2's openpty */
74 if (::openpty(&m_masterfd
, &m_slavefd
, 0, 0, 0) == 0) {
75 const char* tname
= ::ttyname(m_slavefd
);
81 m_masterfd
= m_slavefd
= -1;
87 // resort to BSD-style terminals
93 char ptynam
[] = "/dev/ptyxx";
94 char ttynam
[] = "/dev/ttyxx";
95 static const char ptyc3
[] = "pqrstuvwxyzabcde";
96 static const char ptyc4
[] = "0123456789abcdef";
98 // Find a master pty that we can open
99 for (s3
= ptyc3
; *s3
!= 0 && m_masterfd
< 0; s3
++)
101 for (s4
= ptyc4
; *s4
!= 0; s4
++)
103 ptynam
[8] = ttynam
[8] = *s3
;
104 ptynam
[9] = ttynam
[9] = *s4
;
105 if ((m_masterfd
= ::open(ptynam
,O_RDWR
)) >= 0)
107 if (::geteuid() == 0 || ::access(ttynam
,R_OK
|W_OK
) == 0)
119 return m_masterfd
>= 0;
122 void STTY::outReceived(int f
)
126 int n
= ::read(f
, buf
, sizeof(buf
));
128 if (errno
!= EAGAIN
) { /* this is not an error */
129 // ugh! error! somebody disconnect this signal please!
141 TTYWindow::TTYWindow(QWidget
* parent
, const char* name
) :
142 QTextEdit(parent
, name
),
146 setFont(KGlobalSettings::fixedFont());
148 setAutoFormatting(AutoNone
);
149 setTextFormat(PlainText
);
153 TTYWindow::~TTYWindow()
160 QString
TTYWindow::activate()
162 // allocate a pseudo terminal
165 QString ttyName
= m_tty
->slaveTTY();
166 if (ttyName
.isEmpty()) {
167 // failed to allocate terminal
172 connect(m_tty
, SIGNAL(output(char*,int)), SLOT(slotAppend(char*,int)));
177 void TTYWindow::deactivate()
184 * Note that it is necessary to track the horizontal position explicitly
185 * since if the user modifies the selected text in the window, the cursor
186 * position changes, too.
188 void TTYWindow::slotAppend(char* buffer
, int count
)
191 char* start
= buffer
;
194 while (count
> 0 && start
[len
] != '\n' && start
[len
] != '\r') {
199 QString str
= QString::fromLatin1(start
, len
);
200 // replace text in the last line
201 int para
= paragraphs()-1;
202 // this selection is non-empty only after a '\r' that was not
203 // followed by a '\n'
204 setSelection(para
, m_hPos
, para
, m_hPos
+len
, 1);
205 removeSelectedText(1);
206 insertAt(str
, para
, m_hPos
);
211 if (count
> 0 && *start
== '\r') {
216 if (count
> 0 && *start
== '\n') {
225 QPopupMenu
* TTYWindow::createPopupMenu(const QPoint
& pos
)
227 QPopupMenu
* menu
= QTextEdit::createPopupMenu(pos
);
228 menu
->insertSeparator();
229 menu
->insertItem(i18n("&Clear"), this, SLOT(slotClear()));
233 void TTYWindow::slotClear()
239 #include "ttywnd.moc"