Add a UnixSignalHandler class. It emits a Qt signal when a Unix signal is

handled.

Use the UnixSignalHandler to detect terminal resizing.  The client doesn't
do anything with the terminal size yet.  It should send the size to the
server.
This commit is contained in:
Ryan Prichard 2011-11-12 18:21:11 -08:00
parent af5a742e57
commit b491fd6378
5 changed files with 124 additions and 2 deletions

View File

@ -14,7 +14,9 @@ CONFIG -= app_bundle
TEMPLATE = app
SOURCES += main.cc \
UnixClient.cc
UnixClient.cc \
UnixSignalHandler.cc
HEADERS += \
UnixClient.h
UnixClient.h \
UnixSignalHandler.h

View File

@ -1,9 +1,12 @@
#include "UnixClient.h"
#include "UnixSignalHandler.h"
#include <stdio.h>
#include <stdlib.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <QSocketNotifier>
#include <QCoreApplication>
#include <QTcpSocket>
@ -28,6 +31,11 @@ UnixClient::UnixClient(QTcpSocket *socket, QObject *parent) :
connect(socket, SIGNAL(readyRead()), SLOT(socketReadyRead()));
connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(socketBytesWritten()));
connect(socket, SIGNAL(disconnected()), SLOT(socketDisconnected()));
// Detect terminal resizing.
UnixSignalHandler *ush = new UnixSignalHandler(SIGWINCH, this);
connect(ush, SIGNAL(signaled(int)), SLOT(terminalResized()));
terminalResized();
}
UnixClient::~UnixClient()
@ -72,6 +80,14 @@ void UnixClient::restoreTerminalMode(termios original)
qFatal("error restoring terminal mode");
}
void UnixClient::terminalResized()
{
winsize sz;
ioctl(STDIN_FILENO, TIOCGWINSZ, &sz);
//printf("%d %d\r\n", sz.ws_col, sz.ws_row);
// TODO: Notify the server that the terminal has resized.
}
void UnixClient::socketDisconnected()
{
printf("Connection terminated\r\n");

View File

@ -22,6 +22,7 @@ private:
signals:
private slots:
void terminalResized();
void socketDisconnected();
void terminalReadActivated();
void socketBytesWritten();

View File

@ -0,0 +1,68 @@
// Handles Unix signals in a Qt program.
//
// TODO: Are Qt programs automatically multi-threaded? I don't think they
// are... I wonder if this code works OK in a multi-threaded program.
#include "UnixSignalHandler.h"
#include <QSocketNotifier>
#include <signal.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
UnixSignalHandler *UnixSignalHandler::handlers[_NSIG];
UnixSignalHandler::UnixSignalHandler(int signum, QObject *parent) :
QObject(parent), m_signum(signum)
{
Q_ASSERT(m_signum < _NSIG);
if (handlers[m_signum] != NULL)
qFatal("Signal handler for signal %d is already registered.", m_signum);
handlers[m_signum] = this;
int pipeFd[2];
if (pipe2(pipeFd, O_NONBLOCK | O_CLOEXEC) != 0)
qFatal("Could not create signal %d pipe", m_signum);
m_pipeReadFd = pipeFd[0];
m_pipeWriteFd = pipeFd[1];
m_sn = new QSocketNotifier(m_pipeReadFd, QSocketNotifier::Read, this);
connect(m_sn, SIGNAL(activated(int)), SLOT(pipeReadActivated()));
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = UnixSignalHandler::signalHandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags |= SA_RESTART;
if (sigaction(m_signum, &sa, &m_oldsa) != 0)
qFatal("sigaction for signal %d failed", m_signum);
}
UnixSignalHandler::~UnixSignalHandler()
{
sigaction(m_signum, &m_oldsa, NULL);
// TODO: If there is data on the pipe, maybe we could emit the Qt signal
// here.
close(m_pipeReadFd);
close(m_pipeWriteFd);
handlers[m_signum] = NULL;
}
void UnixSignalHandler::pipeReadActivated()
{
m_sn->setEnabled(false);
char dummy;
read(m_pipeReadFd, &dummy, 1);
emit signaled(m_signum);
m_sn->setEnabled(true);
}
void UnixSignalHandler::signalHandler(int signum)
{
if (handlers[signum] != 0) {
char dummy = 0;
write(handlers[signum]->m_pipeWriteFd, &dummy, 1);
}
}

View File

@ -0,0 +1,35 @@
#ifndef UNIXSIGNALHANDLER_H
#define UNIXSIGNALHANDLER_H
#include <QObject>
#include <signal.h>
class QSocketNotifier;
class UnixSignalHandler : public QObject
{
Q_OBJECT
public:
explicit UnixSignalHandler(int signum, QObject *parent = 0);
~UnixSignalHandler();
signals:
void signaled(int signum);
public slots:
private slots:
void pipeReadActivated();
private:
static void signalHandler(int signum);
static UnixSignalHandler *handlers[_NSIG];
QSocketNotifier *m_sn;
int m_signum;
int m_pipeReadFd;
int m_pipeWriteFd;
struct sigaction m_oldsa;
};
#endif // UNIXSIGNALHANDLER_H