mirror of
https://github.com/QuasarApp/qca.git
synced 2025-05-04 15:09:34 +00:00
console support
svn path=/trunk/kdesupport/qca/; revision=525455
This commit is contained in:
parent
b612a84b44
commit
b412e36aaa
@ -38,6 +38,7 @@
|
||||
#include <QString>
|
||||
#include <QObject>
|
||||
#include "qca_export.h"
|
||||
#include "qca_tools.h"
|
||||
|
||||
namespace QCA
|
||||
{
|
||||
@ -97,6 +98,84 @@ namespace QCA
|
||||
friend class Private;
|
||||
Private *d;
|
||||
};
|
||||
|
||||
class ConsolePrivate;
|
||||
class ConsoleReferencePrivate;
|
||||
class ConsoleReference;
|
||||
|
||||
// note: only one Console object can be created at a time
|
||||
class QCA_EXPORT Console : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum ChannelMode
|
||||
{
|
||||
Read, // stdin
|
||||
ReadWrite // stdin + stdout
|
||||
};
|
||||
|
||||
enum TerminalMode
|
||||
{
|
||||
Default, // use default terminal settings
|
||||
Interactive // char-by-char input, no echo
|
||||
};
|
||||
|
||||
Console(ChannelMode cmode = Read, TerminalMode tmode = Default, QObject *parent = 0);
|
||||
~Console();
|
||||
|
||||
static Console *instance();
|
||||
|
||||
// call shutdown() to get access to unempty buffers
|
||||
void shutdown();
|
||||
QByteArray bytesLeftToRead();
|
||||
QByteArray bytesLeftToWrite();
|
||||
|
||||
private:
|
||||
friend class ConsolePrivate;
|
||||
ConsolePrivate *d;
|
||||
|
||||
friend class ConsoleReference;
|
||||
};
|
||||
|
||||
// note: only one ConsoleReference object can be active at a time
|
||||
class QCA_EXPORT ConsoleReference : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum SecurityMode
|
||||
{
|
||||
SecurityDisabled,
|
||||
SecurityEnabled
|
||||
};
|
||||
|
||||
ConsoleReference(QObject *parent = 0);
|
||||
~ConsoleReference();
|
||||
|
||||
void start(SecurityMode mode = SecurityDisabled);
|
||||
void stop();
|
||||
|
||||
// normal i/o
|
||||
QByteArray read(int bytes = -1);
|
||||
void write(const QByteArray &a);
|
||||
|
||||
// secure i/o
|
||||
QSecureArray readSecure(int bytes = -1);
|
||||
void writeSecure(const QSecureArray &a);
|
||||
|
||||
int bytesAvailable() const;
|
||||
int bytesToWrite() const;
|
||||
|
||||
signals:
|
||||
void readyRead();
|
||||
void bytesWritten(int);
|
||||
void closed();
|
||||
|
||||
private:
|
||||
friend class ConsoleReferencePrivate;
|
||||
ConsoleReferencePrivate *d;
|
||||
|
||||
friend class Console;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -67,7 +67,8 @@ SOURCES += \
|
||||
$$QCA_CPP/qca_securelayer.cpp \
|
||||
$$QCA_CPP/qca_securemessage.cpp \
|
||||
$$QCA_CPP/qca_default.cpp \
|
||||
$$QCA_CPP/support/qpipe.cpp
|
||||
$$QCA_CPP/support/qpipe.cpp \
|
||||
$$QCA_CPP/support/console.cpp
|
||||
|
||||
unix:!mac: {
|
||||
SOURCES += $$QCA_CPP/qca_systemstore_flatfile.cpp
|
||||
|
732
src/support/console.cpp
Normal file
732
src/support/console.cpp
Normal file
@ -0,0 +1,732 @@
|
||||
/*
|
||||
* Copyright (C) 2006 Justin Karneges <justin@affinix.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include "qca_support.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <sys/termios.h>
|
||||
# include <unistd.h>
|
||||
# include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "qpipe.h"
|
||||
|
||||
namespace QCA {
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// SyncThread
|
||||
//----------------------------------------------------------------------------
|
||||
static QByteArray getReturnType(const QMetaObject *obj, const QByteArray &method, const QList<QByteArray> argTypes)
|
||||
{
|
||||
for(int n = obj->methodOffset(); n < obj->methodCount(); ++n)
|
||||
{
|
||||
QMetaMethod m = obj->method(n);
|
||||
QByteArray sig = m.signature();
|
||||
int n = sig.indexOf('(');
|
||||
if(n == -1)
|
||||
continue;
|
||||
QByteArray name = sig.mid(0, n);
|
||||
if(name != method)
|
||||
continue;
|
||||
if(m.parameterTypes() != argTypes)
|
||||
continue;
|
||||
|
||||
return m.typeName();
|
||||
}
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
static bool invokeMethodWithVariants(QObject *obj, const QByteArray &method, const QVariantList &args, QVariant *ret, Qt::ConnectionType type = Qt::AutoConnection)
|
||||
{
|
||||
// QMetaObject::invokeMethod() has a 10 argument maximum
|
||||
if(args.count() > 10)
|
||||
return false;
|
||||
|
||||
QList<QByteArray> argTypes;
|
||||
for(int n = 0; n < args.count(); ++n)
|
||||
argTypes += args[n].typeName();
|
||||
|
||||
// get return type
|
||||
int metatype = 0;
|
||||
QByteArray retTypeName = getReturnType(obj->metaObject(), method, argTypes);
|
||||
if(!retTypeName.isEmpty())
|
||||
{
|
||||
metatype = QMetaType::type(retTypeName.data());
|
||||
if(metatype == 0) // lookup failed
|
||||
return false;
|
||||
}
|
||||
|
||||
QGenericArgument arg[10];
|
||||
for(int n = 0; n < args.count(); ++n)
|
||||
arg[n] = QGenericArgument(args[n].typeName(), args[n].constData());
|
||||
|
||||
QGenericReturnArgument retarg;
|
||||
QVariant retval;
|
||||
if(metatype != 0)
|
||||
{
|
||||
retval = QVariant(metatype, (const void *)0);
|
||||
retarg = QGenericReturnArgument(retval.typeName(), retval.data());
|
||||
}
|
||||
|
||||
if(!QMetaObject::invokeMethod(obj, method.data(), type, retarg, arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], arg[6], arg[7], arg[8], arg[9]))
|
||||
return false;
|
||||
|
||||
if(retval.isValid() && ret)
|
||||
*ret = retval;
|
||||
return true;
|
||||
}
|
||||
|
||||
class SyncThreadAgent;
|
||||
|
||||
class SyncThread : public QThread
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QMutex m;
|
||||
QWaitCondition w;
|
||||
QEventLoop *loop;
|
||||
SyncThreadAgent *agent;
|
||||
bool last_success;
|
||||
QVariant last_ret;
|
||||
|
||||
public:
|
||||
SyncThread(QObject *parent = 0);
|
||||
~SyncThread();
|
||||
|
||||
void start();
|
||||
void stop();
|
||||
|
||||
QVariant call(QObject *obj, const char *method, const QVariantList &args = QVariantList(), bool *ok = 0);
|
||||
|
||||
protected:
|
||||
virtual void run();
|
||||
virtual void atStart() = 0;
|
||||
virtual void atEnd() = 0;
|
||||
|
||||
private slots:
|
||||
void agent_started();
|
||||
void agent_call_ret(bool success, const QVariant &ret);
|
||||
};
|
||||
|
||||
class SyncThreadAgent : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SyncThreadAgent(QObject *parent = 0) : QObject(parent)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "started", Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
signals:
|
||||
void started();
|
||||
void call_ret(bool success, const QVariant &ret);
|
||||
|
||||
public slots:
|
||||
void call_do(QObject *obj, const QByteArray &method, const QVariantList &args)
|
||||
{
|
||||
QVariant ret;
|
||||
bool ok = invokeMethodWithVariants(obj, method, args, &ret, Qt::DirectConnection);
|
||||
emit call_ret(ok, ret);
|
||||
}
|
||||
};
|
||||
|
||||
SyncThread::SyncThread(QObject *parent)
|
||||
:QThread(parent)
|
||||
{
|
||||
qRegisterMetaType<QVariant>("QVariant");
|
||||
qRegisterMetaType<QVariantList>("QVariantList");
|
||||
|
||||
loop = 0;
|
||||
agent = 0;
|
||||
}
|
||||
|
||||
SyncThread::~SyncThread()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void SyncThread::start()
|
||||
{
|
||||
QMutexLocker locker(&m);
|
||||
Q_ASSERT(!loop);
|
||||
QThread::start();
|
||||
w.wait(&m);
|
||||
}
|
||||
|
||||
void SyncThread::stop()
|
||||
{
|
||||
QMutexLocker locker(&m);
|
||||
if(!loop)
|
||||
return;
|
||||
QMetaObject::invokeMethod(loop, "quit");
|
||||
w.wait(&m);
|
||||
wait();
|
||||
}
|
||||
|
||||
QVariant SyncThread::call(QObject *obj, const char *method, const QVariantList &args, bool *ok)
|
||||
{
|
||||
QMutexLocker locker(&m);
|
||||
Q_ASSERT(QMetaObject::invokeMethod(agent, "call_do", Qt::QueuedConnection,
|
||||
Q_ARG(QObject*, obj), Q_ARG(QByteArray, QByteArray(method)), Q_ARG(QVariantList, args)));
|
||||
w.wait(&m);
|
||||
if(ok)
|
||||
*ok = last_success;
|
||||
QVariant v = last_ret;
|
||||
last_ret = QVariant();
|
||||
return v;
|
||||
}
|
||||
|
||||
void SyncThread::run()
|
||||
{
|
||||
m.lock();
|
||||
loop = new QEventLoop;
|
||||
agent = new SyncThreadAgent;
|
||||
connect(agent, SIGNAL(started()), SLOT(agent_started()), Qt::DirectConnection);
|
||||
connect(agent, SIGNAL(call_ret(bool, const QVariant &)), SLOT(agent_call_ret(bool, const QVariant &)), Qt::DirectConnection);
|
||||
loop->exec();
|
||||
m.lock();
|
||||
atEnd();
|
||||
delete agent;
|
||||
delete loop;
|
||||
agent = 0;
|
||||
loop = 0;
|
||||
w.wakeOne();
|
||||
m.unlock();
|
||||
}
|
||||
|
||||
void SyncThread::agent_started()
|
||||
{
|
||||
atStart();
|
||||
w.wakeOne();
|
||||
m.unlock();
|
||||
}
|
||||
|
||||
void SyncThread::agent_call_ret(bool success, const QVariant &ret)
|
||||
{
|
||||
QMutexLocker locker(&m);
|
||||
last_success = success;
|
||||
last_ret = ret;
|
||||
w.wakeOne();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ConsoleWorker
|
||||
//----------------------------------------------------------------------------
|
||||
class ConsoleWorker : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
QPipeEnd in, out;
|
||||
bool started;
|
||||
QByteArray in_left, out_left;
|
||||
|
||||
public:
|
||||
ConsoleWorker(QObject *parent = 0) : QObject(parent), in(this), out(this)
|
||||
{
|
||||
started = false;
|
||||
}
|
||||
|
||||
~ConsoleWorker()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void start(Q_PIPE_ID in_id, Q_PIPE_ID out_id)
|
||||
{
|
||||
Q_ASSERT(!started);
|
||||
|
||||
if(in_id != INVALID_Q_PIPE_ID)
|
||||
{
|
||||
in.take(in_id, QPipeDevice::Read);
|
||||
connect(&in, SIGNAL(readyRead()), SLOT(in_readyRead()));
|
||||
connect(&in, SIGNAL(closed()), SLOT(in_closed()));
|
||||
connect(&in, SIGNAL(error(QCA::QPipeEnd::Error)), SLOT(in_error(QCA::QPipeEnd::Error)));
|
||||
in.enable();
|
||||
}
|
||||
|
||||
if(out_id != INVALID_Q_PIPE_ID)
|
||||
{
|
||||
out.take(out_id, QPipeDevice::Write);
|
||||
connect(&out, SIGNAL(bytesWritten(int)), SLOT(out_bytesWritten(int)));
|
||||
out.enable();
|
||||
}
|
||||
|
||||
started = true;
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
if(!started)
|
||||
return;
|
||||
|
||||
if(in.isValid())
|
||||
in.finalizeAndRelease();
|
||||
if(out.isValid())
|
||||
out.release();
|
||||
|
||||
in_left = in.read();
|
||||
out_left = out.takeBytesToWrite();
|
||||
|
||||
started = false;
|
||||
}
|
||||
|
||||
public slots:
|
||||
void setSecurityEnabled(bool enabled)
|
||||
{
|
||||
in.setSecurityEnabled(enabled);
|
||||
}
|
||||
|
||||
QByteArray read(int bytes = -1)
|
||||
{
|
||||
return in.read(bytes);
|
||||
}
|
||||
|
||||
void write(const QByteArray &a)
|
||||
{
|
||||
out.write(a);
|
||||
}
|
||||
|
||||
QSecureArray readSecure(int bytes = -1)
|
||||
{
|
||||
return in.readSecure(bytes);
|
||||
}
|
||||
|
||||
void writeSecure(const QSecureArray &a)
|
||||
{
|
||||
out.writeSecure(a);
|
||||
}
|
||||
|
||||
int bytesAvailable() const
|
||||
{
|
||||
return in.bytesAvailable();
|
||||
}
|
||||
|
||||
int bytesToWrite() const
|
||||
{
|
||||
return in.bytesToWrite();
|
||||
}
|
||||
|
||||
public:
|
||||
QByteArray takeBytesToRead()
|
||||
{
|
||||
QByteArray a = in_left;
|
||||
in_left.clear();
|
||||
return a;
|
||||
}
|
||||
|
||||
QByteArray takeBytesToWrite()
|
||||
{
|
||||
QByteArray a = out_left;
|
||||
out_left.clear();
|
||||
return a;
|
||||
}
|
||||
|
||||
signals:
|
||||
void readyRead();
|
||||
void bytesWritten(int bytes);
|
||||
void closed();
|
||||
|
||||
private slots:
|
||||
void in_readyRead()
|
||||
{
|
||||
emit readyRead();
|
||||
}
|
||||
|
||||
void out_bytesWritten(int bytes)
|
||||
{
|
||||
emit bytesWritten(bytes);
|
||||
}
|
||||
|
||||
void in_closed()
|
||||
{
|
||||
emit closed();
|
||||
}
|
||||
|
||||
void in_error(QCA::QPipeEnd::Error)
|
||||
{
|
||||
emit closed();
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ConsoleThread
|
||||
//----------------------------------------------------------------------------
|
||||
class ConsoleThread : public SyncThread
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ConsoleWorker *worker;
|
||||
QMutex m;
|
||||
QWaitCondition w;
|
||||
Q_PIPE_ID _in_id, _out_id;
|
||||
QByteArray in_left, out_left;
|
||||
|
||||
ConsoleThread(QObject *parent = 0) : SyncThread(parent)
|
||||
{
|
||||
qRegisterMetaType<QSecureArray>("QSecureArray");
|
||||
}
|
||||
|
||||
~ConsoleThread()
|
||||
{
|
||||
stop();
|
||||
}
|
||||
|
||||
void start(Q_PIPE_ID in_id, Q_PIPE_ID out_id)
|
||||
{
|
||||
_in_id = in_id;
|
||||
_out_id = out_id;
|
||||
SyncThread::start();
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
SyncThread::stop();
|
||||
}
|
||||
|
||||
QVariant mycall(QObject *obj, const char *method, const QVariantList &args = QVariantList())
|
||||
{
|
||||
QVariant ret;
|
||||
bool ok;
|
||||
ret = call(obj, method, args, &ok);
|
||||
Q_ASSERT(ok);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void setSecurityEnabled(bool enabled)
|
||||
{
|
||||
mycall(worker, "setSecurityEnabled", QVariantList() << enabled);
|
||||
}
|
||||
|
||||
QByteArray read(int bytes = -1)
|
||||
{
|
||||
return mycall(worker, "read", QVariantList() << bytes).toByteArray();
|
||||
}
|
||||
|
||||
void write(const QByteArray &a)
|
||||
{
|
||||
mycall(worker, "write", QVariantList() << a);
|
||||
}
|
||||
|
||||
QSecureArray readSecure(int bytes = -1)
|
||||
{
|
||||
return qVariantValue<QSecureArray>(mycall(worker, "readSecure", QVariantList() << bytes));
|
||||
}
|
||||
|
||||
void writeSecure(const QSecureArray &a)
|
||||
{
|
||||
mycall(worker, "writeSecure", QVariantList() << qVariantFromValue<QSecureArray>(a));
|
||||
}
|
||||
|
||||
int bytesAvailable()
|
||||
{
|
||||
return mycall(worker, "bytesAvailable").toInt();
|
||||
}
|
||||
|
||||
int bytesToWrite()
|
||||
{
|
||||
return mycall(worker, "bytesToWrite").toInt();
|
||||
}
|
||||
|
||||
QByteArray takeBytesToRead()
|
||||
{
|
||||
QByteArray a = in_left;
|
||||
in_left.clear();
|
||||
return a;
|
||||
}
|
||||
|
||||
QByteArray takeBytesToWrite()
|
||||
{
|
||||
QByteArray a = out_left;
|
||||
out_left.clear();
|
||||
return a;
|
||||
}
|
||||
|
||||
signals:
|
||||
void readyRead();
|
||||
void bytesWritten(int);
|
||||
void closed();
|
||||
|
||||
protected:
|
||||
virtual void atStart()
|
||||
{
|
||||
worker = new ConsoleWorker;
|
||||
|
||||
// use direct connections here, so that the emits come from
|
||||
// the other thread. we can also connect to our own
|
||||
// signals to avoid having to make slots just to emit.
|
||||
connect(worker, SIGNAL(readyRead()), SIGNAL(readyRead()), Qt::DirectConnection);
|
||||
connect(worker, SIGNAL(bytesWritten(int)), SIGNAL(bytesWritten(int)), Qt::DirectConnection);
|
||||
connect(worker, SIGNAL(closed()), SIGNAL(closed()), Qt::DirectConnection);
|
||||
|
||||
worker->start(_in_id, _out_id);
|
||||
}
|
||||
|
||||
virtual void atEnd()
|
||||
{
|
||||
in_left = worker->takeBytesToRead();
|
||||
out_left = worker->takeBytesToWrite();
|
||||
delete worker;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Console
|
||||
//----------------------------------------------------------------------------
|
||||
class ConsolePrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Console *q;
|
||||
|
||||
bool started;
|
||||
Console::TerminalMode mode;
|
||||
ConsoleThread *thread;
|
||||
ConsoleReference *ref;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
DWORD old_mode;
|
||||
#else
|
||||
struct termios old_term_attr;
|
||||
#endif
|
||||
|
||||
ConsolePrivate(Console *_q) : QObject(_q), q(_q)
|
||||
{
|
||||
started = false;
|
||||
mode = Console::Default;
|
||||
thread = new ConsoleThread(this);
|
||||
}
|
||||
|
||||
~ConsolePrivate()
|
||||
{
|
||||
delete thread;
|
||||
setInteractive(Console::Default);
|
||||
}
|
||||
|
||||
void setInteractive(Console::TerminalMode m)
|
||||
{
|
||||
// no change
|
||||
if(m == mode)
|
||||
return;
|
||||
|
||||
if(m == Console::Interactive)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
|
||||
GetConsoleMode(h, &old_mode);
|
||||
SetConsoleMode(h, old_mode & (~ENABLE_LINE_INPUT & ~ENABLE_ECHO_INPUT));
|
||||
#else
|
||||
int fd = 0; // stdin
|
||||
struct termios attr;
|
||||
tcgetattr(fd, &attr);
|
||||
old_term_attr = attr;
|
||||
|
||||
attr.c_lflag &= ~(ECHO); // turn off the echo flag
|
||||
attr.c_lflag &= ~(ICANON); // no wait for a newline
|
||||
attr.c_cc[VMIN] = 1; // read at least 1 char
|
||||
|
||||
// set the new attributes
|
||||
tcsetattr(fd, TCSAFLUSH, &attr);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
|
||||
SetConsoleMode(h, old_mode);
|
||||
#else
|
||||
int fd = 0; // stdin
|
||||
tcsetattr(fd, TCSANOW, &old_term_attr);
|
||||
#endif
|
||||
}
|
||||
|
||||
mode = m;
|
||||
}
|
||||
};
|
||||
|
||||
static Console *g_console = 0;
|
||||
|
||||
Console::Console(ChannelMode cmode, TerminalMode tmode, QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
Q_ASSERT(g_console == 0);
|
||||
g_console = this;
|
||||
|
||||
d = new ConsolePrivate(this);
|
||||
|
||||
Q_PIPE_ID in = INVALID_Q_PIPE_ID;
|
||||
Q_PIPE_ID out = INVALID_Q_PIPE_ID;
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
in = GetStdHandle(STD_INPUT_HANDLE);
|
||||
#else
|
||||
in = 0;
|
||||
#endif
|
||||
if(cmode == ReadWrite)
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
out = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
#else
|
||||
out = 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
d->setInteractive(tmode);
|
||||
d->thread->start(in, out);
|
||||
}
|
||||
|
||||
Console::~Console()
|
||||
{
|
||||
shutdown();
|
||||
delete d;
|
||||
g_console = 0;
|
||||
}
|
||||
|
||||
Console *Console::instance()
|
||||
{
|
||||
return g_console;
|
||||
}
|
||||
|
||||
void Console::shutdown()
|
||||
{
|
||||
d->thread->stop();
|
||||
}
|
||||
|
||||
QByteArray Console::bytesLeftToRead()
|
||||
{
|
||||
return d->thread->takeBytesToRead();
|
||||
}
|
||||
|
||||
QByteArray Console::bytesLeftToWrite()
|
||||
{
|
||||
return d->thread->takeBytesToWrite();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// ConsoleReference
|
||||
//----------------------------------------------------------------------------
|
||||
class ConsoleReferencePrivate : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ConsoleReference *q;
|
||||
|
||||
Console *console;
|
||||
ConsoleThread *thread;
|
||||
QTimer readTrigger;
|
||||
|
||||
ConsoleReferencePrivate(ConsoleReference *_q) : QObject(_q), q(_q), readTrigger(this)
|
||||
{
|
||||
console = 0;
|
||||
thread = 0;
|
||||
connect(&readTrigger, SIGNAL(timeout()), SLOT(doReadyRead()));
|
||||
readTrigger.setSingleShot(true);
|
||||
}
|
||||
|
||||
private slots:
|
||||
void doReadyRead()
|
||||
{
|
||||
emit q->readyRead();
|
||||
}
|
||||
};
|
||||
|
||||
ConsoleReference::ConsoleReference(QObject *parent)
|
||||
:QObject(parent)
|
||||
{
|
||||
d = new ConsoleReferencePrivate(this);
|
||||
}
|
||||
|
||||
ConsoleReference::~ConsoleReference()
|
||||
{
|
||||
stop();
|
||||
delete d;
|
||||
}
|
||||
|
||||
void ConsoleReference::start(SecurityMode mode)
|
||||
{
|
||||
Q_UNUSED(mode);
|
||||
Console *c = Console::instance();
|
||||
|
||||
// one console reference at a time
|
||||
Q_ASSERT(c->d->ref == 0);
|
||||
|
||||
d->console = c;
|
||||
d->thread = d->console->d->thread;
|
||||
d->console->d->ref = this;
|
||||
|
||||
// enable security? it will last for this active session only
|
||||
if(mode == SecurityEnabled)
|
||||
d->thread->setSecurityEnabled(true);
|
||||
|
||||
connect(d->thread, SIGNAL(readyRead()), SIGNAL(readyRead()));
|
||||
connect(d->thread, SIGNAL(bytesWritten(int)), SIGNAL(bytesWritten(int)));
|
||||
connect(d->thread, SIGNAL(closed()), SIGNAL(closed()));
|
||||
|
||||
if(d->thread->bytesAvailable() > 0)
|
||||
d->readTrigger.start();
|
||||
}
|
||||
|
||||
void ConsoleReference::stop()
|
||||
{
|
||||
d->readTrigger.stop();
|
||||
|
||||
disconnect(d->thread, 0, this, 0);
|
||||
|
||||
// automatically disable security when we go inactive
|
||||
d->thread->setSecurityEnabled(false);
|
||||
|
||||
d->console->d->ref = 0;
|
||||
d->thread = 0;
|
||||
d->console = 0;
|
||||
}
|
||||
|
||||
QByteArray ConsoleReference::read(int bytes)
|
||||
{
|
||||
return d->thread->read(bytes);
|
||||
}
|
||||
|
||||
void ConsoleReference::write(const QByteArray &a)
|
||||
{
|
||||
d->thread->write(a);
|
||||
}
|
||||
|
||||
QSecureArray ConsoleReference::readSecure(int bytes)
|
||||
{
|
||||
return d->thread->readSecure(bytes);
|
||||
}
|
||||
|
||||
void ConsoleReference::writeSecure(const QSecureArray &a)
|
||||
{
|
||||
d->thread->writeSecure(a);
|
||||
}
|
||||
|
||||
int ConsoleReference::bytesAvailable() const
|
||||
{
|
||||
return d->thread->bytesAvailable();
|
||||
}
|
||||
|
||||
int ConsoleReference::bytesToWrite() const
|
||||
{
|
||||
return d->thread->bytesToWrite();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "console.moc"
|
Loading…
x
Reference in New Issue
Block a user