When an item having the current item is taken out from the tree,
[kdbg.git] / kdbg / ttywnd.cpp
blob3a1c06d3614a2443b0f287cbc0c4f60d42649ad5
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 */
31 #endif
32 #include <errno.h>
34 #include "mydebug.h"
37 STTY::STTY() :
38 QObject(),
39 m_masterfd(-1),
40 m_slavefd(-1),
41 m_outNotifier(0)
43 if (findTTY())
45 ::fcntl(m_masterfd, F_SETFL, O_NDELAY);
46 m_outNotifier = new QSocketNotifier(m_masterfd, QSocketNotifier::Read);
47 connect(m_outNotifier, SIGNAL(activated(int)), SLOT(outReceived(int)));
48 } else {
49 m_slavetty = QString();
53 STTY::~STTY()
55 if (m_outNotifier) {
56 ::close(m_masterfd);
57 if (m_slavefd >= 0)
58 ::close(m_slavefd);
59 delete m_outNotifier;
63 bool STTY::findTTY()
65 m_masterfd = -1;
67 #ifdef HAVE_FUNC_OPENPTY
68 /* use glibc2's openpty */
69 if (m_masterfd < 0)
71 if (::openpty(&m_masterfd, &m_slavefd, 0, 0, 0) == 0) {
72 const char* tname = ::ttyname(m_slavefd);
73 if (tname != 0) {
74 m_slavetty = tname;
75 } else {
76 ::close(m_slavefd);
77 ::close(m_masterfd);
78 m_masterfd = m_slavefd = -1;
82 #endif
84 // resort to BSD-style terminals
85 if (m_masterfd < 0)
87 const char* s3;
88 const char* s4;
90 char ptynam[] = "/dev/ptyxx";
91 char ttynam[] = "/dev/ttyxx";
92 static const char ptyc3[] = "pqrstuvwxyzabcde";
93 static const char ptyc4[] = "0123456789abcdef";
95 // Find a master pty that we can open
96 for (s3 = ptyc3; *s3 != 0 && m_masterfd < 0; s3++)
98 for (s4 = ptyc4; *s4 != 0; s4++)
100 ptynam[8] = ttynam[8] = *s3;
101 ptynam[9] = ttynam[9] = *s4;
102 if ((m_masterfd = ::open(ptynam,O_RDWR)) >= 0)
104 if (::geteuid() == 0 || ::access(ttynam,R_OK|W_OK) == 0)
106 m_slavetty = ttynam;
107 break;
109 ::close(m_masterfd);
110 m_masterfd = -1;
116 return m_masterfd >= 0;
119 void STTY::outReceived(int f)
121 for (;;) {
122 char buf[1024];
123 int n = ::read(f, buf, sizeof(buf));
124 if (n < 0) {
125 if (errno != EAGAIN) { /* this is not an error */
126 // ugh! error! somebody disconnect this signal please!
127 int e = errno;
128 TRACE(QString().sprintf("error reading tty: %d", e));
130 break;
132 emit output(buf, n);
133 if (n == 0)
134 break;
140 TTYWindow::TTYWindow(QWidget* parent, const char* name) :
141 KTextView(parent, name),
142 m_tty(0)
144 #if QT_VERSION < 200
145 setFont(kapp->fixedFont);
146 #else
147 setFont(KGlobalSettings::fixedFont());
148 #endif
149 clear();
150 setFocusPolicy(StrongFocus);
152 // create a context menu
153 m_popmenu = new QPopupMenu;
154 m_popmenu->insertItem(i18n("&Clear"), this, SLOT(clear()));
157 TTYWindow::~TTYWindow()
159 if (m_tty)
160 deactivate();
164 QString TTYWindow::activate()
166 // allocate a pseudo terminal
167 m_tty = new STTY;
169 QString ttyName = m_tty->slaveTTY();
170 if (ttyName.isEmpty()) {
171 // failed to allocate terminal
172 delete m_tty;
173 m_tty = 0;
174 return QString();
175 } else {
176 connect(m_tty, SIGNAL(output(char*,int)), SLOT(slotAppend(char*,int)));
177 return ttyName;
181 void TTYWindow::deactivate()
183 delete m_tty;
184 m_tty = 0;
187 void TTYWindow::slotAppend(char* buffer, int count)
189 // is last line visible?
190 bool bottomVisible = lastRowVisible() == m_texts.size()-1;
192 // parse off lines
193 char* start = buffer;
194 while (count > 0) {
195 int len = 0;
196 while (count > 0 && start[len] != '\n') {
197 --count;
198 ++len;
200 if (len > 0) {
201 #if QT_VERSION < 200
202 QString str(start, len+1);
203 #else
204 QString str = QString::fromLatin1(start, len);
205 #endif
206 // update last line
207 str = m_texts[m_texts.size()-1] + str;
208 replaceLine(m_texts.size()-1, str);
209 start += len;
210 len = 0;
212 if (count > 0 && *start == '\n') {
213 insertLine(QString());
214 ++start;
215 --count;
219 // if last row was visible, scroll down to make it visible again
220 if (bottomVisible)
221 setTopCell(m_texts.size()-1);
224 void TTYWindow::clear()
226 m_texts.setSize(0);
227 m_width = 300; m_height = 14; /* Same as in KTextView::KTextView */
228 insertLine(QString());
231 void TTYWindow::mousePressEvent(QMouseEvent* mouseEvent)
233 // Check if right button was clicked.
234 if (mouseEvent->button() == RightButton)
236 if (m_popmenu->isVisible()) {
237 m_popmenu->hide();
238 } else {
239 m_popmenu->popup(mapToGlobal(mouseEvent->pos()));
241 } else {
242 QWidget::mousePressEvent(mouseEvent);
246 #include "ttywnd.moc"