Solaris' ln needs -s -f instead of -sf.
[kdbg.git] / kdbg / ttywnd.cpp
blob4cda21c4ff30298ad289bc8eb1158969b433da21
1 // $Id$
3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include <qsocketnotifier.h>
7 #include <qpopupmenu.h>
8 #include "ttywnd.h"
9 #if QT_VERSION >= 200
10 #include <kglobalsettings.h>
11 #include <klocale.h>
12 #else
13 #include <kapp.h>
14 #endif
16 #include "config.h"
17 #ifdef HAVE_FCNTL_H
18 #include <fcntl.h>
19 #endif
20 #ifdef HAVE_UNISTD_H
21 #include <unistd.h> /* open, close, etc. */
22 #endif
23 #ifdef HAVE_SYS_IOCTL_H
24 #include <sys/ioctl.h>
25 #endif
26 #ifdef HAVE_SYS_STAT_H
27 #include <sys/stat.h>
28 #endif
29 #ifdef HAVE_PTY_H
30 #include <pty.h> /* openpty on Linux */
31 #endif
32 #ifdef HAVE_LIBUTIL_H
33 #include <libutil.h> /* openpty on FreeBSD */
34 #endif
35 #include <errno.h>
37 #include "mydebug.h"
40 STTY::STTY() :
41 QObject(),
42 m_masterfd(-1),
43 m_slavefd(-1),
44 m_outNotifier(0)
46 if (findTTY())
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)));
51 } else {
52 m_slavetty = QString();
56 STTY::~STTY()
58 if (m_outNotifier) {
59 ::close(m_masterfd);
60 if (m_slavefd >= 0)
61 ::close(m_slavefd);
62 delete m_outNotifier;
66 bool STTY::findTTY()
68 m_masterfd = -1;
70 #ifdef HAVE_FUNC_OPENPTY
71 /* use glibc2's openpty */
72 if (m_masterfd < 0)
74 if (::openpty(&m_masterfd, &m_slavefd, 0, 0, 0) == 0) {
75 const char* tname = ::ttyname(m_slavefd);
76 if (tname != 0) {
77 m_slavetty = tname;
78 } else {
79 ::close(m_slavefd);
80 ::close(m_masterfd);
81 m_masterfd = m_slavefd = -1;
85 #endif
87 // resort to BSD-style terminals
88 if (m_masterfd < 0)
90 const char* s3;
91 const char* s4;
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)
109 m_slavetty = ttynam;
110 break;
112 ::close(m_masterfd);
113 m_masterfd = -1;
119 return m_masterfd >= 0;
122 void STTY::outReceived(int f)
124 for (;;) {
125 char buf[1024];
126 int n = ::read(f, buf, sizeof(buf));
127 if (n < 0) {
128 if (errno != EAGAIN) { /* this is not an error */
129 // ugh! error! somebody disconnect this signal please!
130 int e = errno;
131 TRACE(QString().sprintf("error reading tty: %d", e));
133 break;
135 emit output(buf, n);
136 if (n == 0)
137 break;
143 TTYWindow::TTYWindow(QWidget* parent, const char* name) :
144 KTextView(parent, name),
145 m_tty(0)
147 #if QT_VERSION < 200
148 setFont(kapp->fixedFont);
149 setFocusPolicy(StrongFocus);
150 #else
151 setFont(KGlobalSettings::fixedFont());
152 setFocusPolicy(WheelFocus);
153 #endif
154 clear();
156 // create a context menu
157 m_popmenu = new QPopupMenu;
158 m_popmenu->insertItem(i18n("&Clear"), this, SLOT(clear()));
161 TTYWindow::~TTYWindow()
163 if (m_tty)
164 deactivate();
168 QString TTYWindow::activate()
170 // allocate a pseudo terminal
171 m_tty = new STTY;
173 QString ttyName = m_tty->slaveTTY();
174 if (ttyName.isEmpty()) {
175 // failed to allocate terminal
176 delete m_tty;
177 m_tty = 0;
178 return QString();
179 } else {
180 connect(m_tty, SIGNAL(output(char*,int)), SLOT(slotAppend(char*,int)));
181 return ttyName;
185 void TTYWindow::deactivate()
187 delete m_tty;
188 m_tty = 0;
191 void TTYWindow::slotAppend(char* buffer, int count)
193 // is last line visible?
194 bool bottomVisible = lastRowVisible() == m_texts.size()-1;
196 // parse off lines
197 char* start = buffer;
198 while (count > 0) {
199 int len = 0;
200 while (count > 0 && start[len] != '\n') {
201 --count;
202 ++len;
204 if (len > 0) {
205 #if QT_VERSION < 200
206 QString str(start, len+1);
207 #else
208 QString str = QString::fromLatin1(start, len);
209 #endif
210 // update last line
211 str = m_texts[m_texts.size()-1] + str;
212 replaceLine(m_texts.size()-1, str);
213 start += len;
214 len = 0;
216 if (count > 0 && *start == '\n') {
217 insertLine(QString());
218 ++start;
219 --count;
223 // if last row was visible, scroll down to make it visible again
224 if (bottomVisible)
225 setTopCell(m_texts.size()-1);
228 void TTYWindow::clear()
230 m_texts.setSize(0);
231 m_width = 300; m_height = 14; /* Same as in KTextView::KTextView */
232 insertLine(QString());
235 void TTYWindow::mousePressEvent(QMouseEvent* mouseEvent)
237 // Check if right button was clicked.
238 if (mouseEvent->button() == RightButton)
240 if (m_popmenu->isVisible()) {
241 m_popmenu->hide();
242 } else {
243 m_popmenu->popup(mapToGlobal(mouseEvent->pos()));
245 } else {
246 QWidget::mousePressEvent(mouseEvent);
250 #include "ttywnd.moc"