Mercurial > octave-nkf
view gui/src/terminal/kptydevice.cpp @ 13646:2e1f54803758
Lowered size limits for subwindows.
author | Jacob Dawid <jacob.dawid@googlemail.com> |
---|---|
date | Tue, 23 Aug 2011 18:06:45 +0200 |
parents | bad5cb3cfe20 |
children |
line wrap: on
line source
/* This file is part of the KDE libraries Copyright (C) 2007 Oswald Buddenhagen <ossi@kde.org> Copyright (C) 2010 KDE e.V. <kde-ev-board@kde.org> Author Adriaan de Groot <groot@kde.org> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kptydevice.h" #include "kpty_p.h" #define i18n #include <QtCore/QSocketNotifier> #include <unistd.h> #include <errno.h> #include <signal.h> #include <termios.h> #include <fcntl.h> #include <sys/ioctl.h> #define PTY_BYTES_AVAILABLE TIOCINQ ////////////////// // private data // ////////////////// // Lifted from Qt. I don't think they would mind. ;) // Re-lift again from Qt whenever a proper replacement for pthread_once appears static void qt_ignore_sigpipe () { static QBasicAtomicInt atom = Q_BASIC_ATOMIC_INITIALIZER (0); if (atom.testAndSetRelaxed (0, 1)) { struct sigaction noaction; memset (&noaction, 0, sizeof (noaction)); noaction.sa_handler = SIG_IGN; sigaction (SIGPIPE, &noaction, 0); } } #define NO_INTR(ret,func) do { ret = func; } while (ret < 0 && errno == EINTR) bool KPtyDevicePrivate::_k_canRead () { Q_Q (KPtyDevice); qint64 readBytes = 0; int available; if (!::ioctl (q->masterFd (), PTY_BYTES_AVAILABLE, (char *) &available)) { char *ptr = readBuffer.reserve (available); // Useless block braces except in Solaris { NO_INTR (readBytes, read (q->masterFd (), ptr, available)); } if (readBytes < 0) { readBuffer.unreserve (available); q->setErrorString (i18n ("Error reading from PTY")); return false; } readBuffer.unreserve (available - readBytes); // *should* be a no-op } if (!readBytes) { readNotifier->setEnabled (false); return false; } else { if (!emittedReadyRead) { emittedReadyRead = true; emit q->readyRead (); emittedReadyRead = false; } return true; } } bool KPtyDevicePrivate::_k_canWrite () { Q_Q (KPtyDevice); writeNotifier->setEnabled (false); if (writeBuffer.isEmpty ()) return false; qt_ignore_sigpipe (); int wroteBytes; NO_INTR (wroteBytes, write (q->masterFd (), writeBuffer.readPointer (), writeBuffer.readSize ())); if (wroteBytes < 0) { q->setErrorString (i18n ("Error writing to PTY")); return false; } writeBuffer.free (wroteBytes); if (!emittedBytesWritten) { emittedBytesWritten = true; emit q->bytesWritten (wroteBytes); emittedBytesWritten = false; } if (!writeBuffer.isEmpty ()) writeNotifier->setEnabled (true); return true; } #ifndef timeradd // Lifted from GLIBC #define timeradd(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \ if ((result)->tv_usec >= 1000000) { \ ++(result)->tv_sec; \ (result)->tv_usec -= 1000000; \ } \ } while (0) #define timersub(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \ if ((result)->tv_usec < 0) { \ --(result)->tv_sec; \ (result)->tv_usec += 1000000; \ } \ } while (0) #endif bool KPtyDevicePrivate::doWait (int msecs, bool reading) { Q_Q (KPtyDevice); struct timeval tv, *tvp; if (msecs < 0) tvp = 0; else { tv.tv_sec = msecs / 1000; tv.tv_usec = (msecs % 1000) * 1000; tvp = &tv; } while (reading ? readNotifier->isEnabled () : !writeBuffer.isEmpty ()) { fd_set rfds; fd_set wfds; FD_ZERO (&rfds); FD_ZERO (&wfds); if (readNotifier->isEnabled ()) FD_SET (q->masterFd (), &rfds); if (!writeBuffer.isEmpty ()) FD_SET (q->masterFd (), &wfds); switch (select (q->masterFd () + 1, &rfds, &wfds, 0, tvp)) { case -1: if (errno == EINTR) break; return false; case 0: q->setErrorString (i18n ("PTY operation timed out")); return false; default: if (FD_ISSET (q->masterFd (), &rfds)) { bool canRead = _k_canRead (); if (reading && canRead) return true; } if (FD_ISSET (q->masterFd (), &wfds)) { bool canWrite = _k_canWrite (); if (!reading) return canWrite; } break; } } return false; } void KPtyDevicePrivate::finishOpen (QIODevice::OpenMode mode) { Q_Q (KPtyDevice); q->QIODevice::open (mode); fcntl (q->masterFd (), F_SETFL, O_NONBLOCK); readBuffer.clear (); readNotifier = new QSocketNotifier (q->masterFd (), QSocketNotifier::Read, q); writeNotifier = new QSocketNotifier (q->masterFd (), QSocketNotifier::Write, q); QObject::connect (readNotifier, SIGNAL (activated (int)), q, SLOT (_k_canRead ())); QObject::connect (writeNotifier, SIGNAL (activated (int)), q, SLOT (_k_canWrite ())); readNotifier->setEnabled (true); } KPtyDevice::KPtyDevice (QObject * parent): QIODevice (parent), KPty (new KPtyDevicePrivate (this)) { } KPtyDevice::~KPtyDevice () { close (); } bool KPtyDevice::open (OpenMode mode) { Q_D (KPtyDevice); if (masterFd () >= 0) return true; if (!KPty::open ()) { setErrorString (i18n ("Error opening PTY")); return false; } d->finishOpen (mode); return true; } bool KPtyDevice::open (int fd, OpenMode mode) { Q_D (KPtyDevice); if (!KPty::open (fd)) { setErrorString (i18n ("Error opening PTY")); return false; } d->finishOpen (mode); return true; } void KPtyDevice::close () { Q_D (KPtyDevice); if (masterFd () < 0) return; delete d->readNotifier; delete d->writeNotifier; QIODevice::close (); KPty::close (); } bool KPtyDevice::canReadLine () const { Q_D (const KPtyDevice); return QIODevice::canReadLine () || d->readBuffer.canReadLine (); } bool KPtyDevice::atEnd () const { Q_D (const KPtyDevice); return QIODevice::atEnd () && d->readBuffer.isEmpty (); } qint64 KPtyDevice::bytesAvailable () const { Q_D (const KPtyDevice); return QIODevice::bytesAvailable () + d->readBuffer.size (); } qint64 KPtyDevice::bytesToWrite () const { Q_D (const KPtyDevice); return d->writeBuffer.size (); } // protected qint64 KPtyDevice::readData (char *data, qint64 maxlen) { Q_D (KPtyDevice); return d->readBuffer.read (data, (int) qMin < qint64 > (maxlen, KMAXINT)); } // protected qint64 KPtyDevice::readLineData (char *data, qint64 maxlen) { Q_D (KPtyDevice); return d->readBuffer.readLine (data, (int) qMin < qint64 > (maxlen, KMAXINT)); } // protected qint64 KPtyDevice::writeData (const char *data, qint64 len) { Q_D (KPtyDevice); Q_ASSERT (len <= KMAXINT); d->writeBuffer.write (data, len); d->writeNotifier->setEnabled (true); return len; }