You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/ksirc/puke/controller.cpp

975 lines
25 KiB

#include <config.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <iostream>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <sys/time.h>
#include <sys/un.h>
#include <sys/stat.h>
using namespace std; // iostream.h include cstring which puts strlen into
// std:: namespace, which breaks TQt's strlen() call
// in tqcstring.h (in gcc3's libstdc++)
#include <klibloader.h>
#include <kdebug.h>
#include "controller.h"
#include "../../config.h"
#include "../objFinder.h"
#include "palistbox.h"
#include "pbutton.h"
#include "pframe.h"
#include "pkfiledialog.h"
#include "plabel.h"
#include "playout.h"
#include "plined.h"
#include "plistbox.h"
#include "pmenudta.h"
#include "pmessage.h"
#include "pobject.h"
#include "pobjfinder.h"
#include "ppopmenu.h"
#include "pprogress.h"
#include "ppushbt.h"
#include "ptabdialog.h"
#include "ptablevw.h"
#include "pwidget.h"
#undef DEBUG
uint PukeController::uiBaseWinId = 10; // Gives a little seperation from the controller id
PukeController::PukeController(TQString sock, TQObject *parent, const char *name) : PObject( parent, name )
{
int len, prev_umask;
struct sockaddr_un unix_addr;
running = FALSE; // Running has to be true before we do any work
bClosing = FALSE; // we're not trying to close so set this false.
// Set the umask to something sane that doesn't allow others to take over ksirc
prev_umask = umask(0177);
if(sock.length() == 0){
qsPukeSocket = getenv("HOME");
if(qsPukeSocket.length() == 0){
qsPukeSocket = "/tmp";
}
qsPukeSocket += "/.ksirc.socket";
}
else{
qsPukeSocket = sock;
}
unlink(qsPukeSocket);
iListenFd = socket(AF_UNIX, SOCK_STREAM, 0);
if(iListenFd < 0){
perror("PUKE: Unix Domain Socket create failed");
return;
}
memset(&unix_addr, 0, sizeof(unix_addr));
unix_addr.sun_family = AF_UNIX;
strlcpy(unix_addr.sun_path, qsPukeSocket, sizeof(unix_addr.sun_path));
len = sizeof(unix_addr.sun_family) + qsPukeSocket.length();
#if defined(__FreeBSD__)
if( bind(iListenFd, (struct sockaddr *) &unix_addr, len+1) < 0){
#else
if( bind(iListenFd, (struct sockaddr *) &unix_addr, len) < 0){
#endif
perror("PUKE: Could not bind to Unix Domain Socket");
return;
}
if(listen(iListenFd, 5) < 0){
perror("PUKE: Could not listen for inbound connections");
return;
}
running = TRUE;
fcntl(iListenFd, F_SETFL, O_NONBLOCK); // Set it non-block so that
// accept() never blocks.
qsnListen = new TQSocketNotifier(iListenFd, TQSocketNotifier::Read, this, TQString(name) + "_iListen");
connect(qsnListen, TQT_SIGNAL(activated(int)),
this, TQT_SLOT(NewConnect(int)));
connect(objFind, TQT_SIGNAL(inserted(TQObject *)),
this, TQT_SLOT(slotInserted(TQObject *)));
qidConnectFd.setAutoDelete(TRUE);
qidCommandTable.setAutoDelete(TRUE);
/*
* Setup widget data trees
*/
WidgetList.setAutoDelete(TRUE);
revWidgetList.setAutoDelete(TRUE);
widgetCF.setAutoDelete(TRUE);
/*
* Connect outputMessage to the acutal write buffer function
* outputMessage signals from pobjects are chained until they finally reach us.
*/
connect(this, TQT_SIGNAL(outputMessage(int, PukeMessage *)),
this, TQT_SLOT(writeBuffer(int, PukeMessage *)));
initHdlr(); // Setup message command handlers.
// Set umask back so it doesn't affect dcc's and so forth.
umask(prev_umask);
/*
* We are a PObject so do some init code
*/
// We're always terminate by someone else so set manTerm() right now
manTerm();
setWidget(0x0);
}
void
PukeController::slotInserted(TQObject *obj)
{
emit inserted(obj);
}
PukeController::~PukeController()
{
close(iListenFd);
disconnect(this); // We call disconnect this so don't listen to our own destroy() signal go out
unlink(qsPukeSocket);
}
TQStrList PukeController::allObjects()
{
return objFinder::allObjects();
}
void PukeController::NewConnect(int)
{
int cfd;
ksize_t len = 0;
struct sockaddr_un unix_addr;
cfd = accept(iListenFd, (struct sockaddr *)&unix_addr, &len);
if(cfd < 0){
perror("PUKE: NewConnect fired, but no new connect");
return;
}
fcntl(cfd, F_SETFL, O_NONBLOCK); // Set it non-block so that
// cfd() never blocks.
fdStatus *fds = new fdStatus();
fds->sr = new TQSocketNotifier(cfd, TQSocketNotifier::Read, this);
fds->sw = new TQSocketNotifier(cfd, TQSocketNotifier::Write, this);
connect(fds->sr, TQT_SIGNAL(activated(int)),
this, TQT_SLOT(Traffic(int)));
connect(fds->sw, TQT_SIGNAL(activated(int)),
this, TQT_SLOT(Writeable(int)));
qidConnectFd.insert(cfd, fds);
qsnListen->setEnabled(TRUE);
/*
* Now we add ourselves as a client to the fd so we can process messages going to us
*/
WidgetS *ws = new WidgetS;
ws->pwidget = this;
ws->type = 1;
insertPObject(cfd, ControllerWinId, ws);
}
void PukeController::Writeable(int fd)
{
if(qidConnectFd[fd]){
qidConnectFd[fd]->writeable = TRUE;
qidConnectFd[fd]->sw->setEnabled(FALSE);
//
// Insert buffer flushing code here.
//
}
else{
kdDebug(5008) << "PUKE: Unkonwn fd: " << fd << endl;
}
}
void PukeController::writeBuffer(int fd, PukeMessage *message)
{
if(qidConnectFd[fd]){
// if(qidConnectFd[fd]->writeable == FALSE){
// kdDebug(5008) << "PUKE: Writing to FD that's not writeable: " << fd << endl;
// }
if(message != 0){
int bytes = 0;
message->iHeader = iPukeHeader;
if(message->iTextSize == 0 || message->cArg == 0){
message->iTextSize = 0;
message->cArg = 0;
#ifdef DEBUG
printf("Traffic on: %d <= %d %d %d %d 0x%x\n",
fd,
message->iCommand,
message->iWinId,
message->iArg,
message->iTextSize,
message->cArg);
#endif
bytes = write(fd, message, 5 * sizeof(int));
}
else{
/*
struct OutMessageS {
unsigned int iHeader;
int iCommand;
int iWinId;
int iArg;
int iTextSize;
char cArg[message->iTextSize];
} OutMessage;
OutMessage.iHeader = iPukeHeader;
OutMessage.iCommand = message->iCommand;
OutMessage.iWinId = message->iWinId;
OutMessage.iArg = message->iArg;
OutMessage.iTextSize = message->iTextSize;
memcpy(OutMessage.cArg, message->cArg, OutMessage.iTextSize);
// OutMessage.cArg[OutMessage.iTextSize] = 0; // Don't need to null out the last character
bytes = write(fd, &OutMessage, 5*sizeof(int) + (OutMessage.iTextSize) * sizeof(char));
*/
#ifdef DEBUG
printf("Traffic on: %d <= %d %d %d %d 0x%x\n",
fd,
message->iCommand,
message->iWinId,
message->iArg,
message->iTextSize,
message->cArg);
#endif /* DEBUG */
struct iovec iov[2];
iov[0].iov_base = (char *) message;
iov[0].iov_len = 5*sizeof(int);
iov[1].iov_base = (char *) message->cArg;
iov[1].iov_len = message->iTextSize;
bytes = writev(fd, iov, 2);
}
// kdDebug(5008) << "Wrote: " << bytes << endl;
if(bytes <= 0){
switch(errno){
case EAGAIN: // Don't do anything for try again
break;
// default:
// perror("Puke: write on socket failed");
// Don't call closefd() since deletes are called on write's
// since write is being called from the destructors, etc of
// the widgets. (bad things happend when you call write
// then your return; path ceasaes to exist.
// closefd(fd);
}
}
}
}
else{
closefd(fd);
kdDebug(5008) << "PUKE: Attempt to write to unkown fd:" << fd << endl;
}
}
void PukeController::Traffic(int fd)
{
PukeMessage pm;
int bytes = -1;
memset(&pm, 0, sizeof(pm));
while((bytes = read(fd, &pm, 5*sizeof(int))) > 0){
if(bytes != 5*sizeof(int)){
kdDebug(5008) << "Short message, Got: " << bytes << " Wanted: " << sizeof(PukeMessage) << " NULL Padded" << endl;
}
#ifdef DEBUG
printf("Traffic on: %d => %d %d %d %d",
fd,
pm.iCommand,
pm.iWinId,
pm.iArg,
pm.iTextSize);
if(pm.iCommand == 0x0){
abort();
}
#endif /* DEBUG */
if(pm.iHeader != iPukeHeader){
qWarning("Invalid packet received, discarding!");
return;
}
if(pm.iTextSize > 0){
pm.cArg = new char[pm.iTextSize + 1];
read(fd, pm.cArg, pm.iTextSize * sizeof(char));
pm.cArg[pm.iTextSize] = 0x0; // Null terminate the string.
// printf(" %s\n", pm.cArg);
}
else {
pm.cArg = 0;
// printf("\n");
}
MessageDispatch(fd, &pm);
delete[] pm.cArg; // Free up cArg is used
memset(&pm, 0, 5*sizeof(int));
}
if(bytes <= 0){ // Shutdown the socket!
switch(errno){
case EAGAIN: // Don't do anything for try again
break;
// case 0:
// break; // We just read nothing, don't panic
case EIO:
case EISDIR:
case EBADF:
case EINVAL:
case EFAULT:
default:
// perror("PukeController: read failed");
closefd(fd);
close(fd);
}
}
else{
qidConnectFd[fd]->sr->setEnabled(TRUE);
}
}
void PukeController::ServMessage(TQString, int, TQString)
{
}
// Message Dispatcher is in messagedispatcher.cpp
void PukeController::MessageDispatch(int fd, PukeMessage *pm)
{
try {
/*
* Get the object id, this may produce a errorNuSuchWidget
*/
PObject *obj = id2pobject(fd, pm->iWinId);
/*
* Call the message hanlder for the widget
*/
obj->messageHandler(fd, pm);
}
catch(errorNoSuchWidget &err){
PukeMessage pmRet;
pmRet.iCommand = PUKE_INVALID;
pmRet.iWinId = pm->iWinId;
pmRet.iArg = 0;
pmRet.iTextSize = 0;
emit outputMessage(fd, &pmRet);
return;
}
catch (errorCommandFailed &err){
PukeMessage pmRet;
pmRet.iCommand = err.command();
pmRet.iWinId = pm->iWinId;
pmRet.iArg = err.iarg();
pmRet.iTextSize = 0;
emit outputMessage(fd, &pmRet);
return;
}
}
void PukeController::initHdlr()
{
widgetCreate *wc;
wc = new widgetCreate;
wc->wc = PWidget::createWidget;
widgetCF.insert(PWIDGET_WIDGET, wc);
wc = new widgetCreate;
wc->wc = PObject::createWidget;
widgetCF.insert(PWIDGET_OBJECT, wc);
wc = new widgetCreate;
wc->wc = PLayout::createWidget;
widgetCF.insert(POBJECT_LAYOUT, wc);
wc = new widgetCreate;
wc->wc = PFrame::createWidget;
widgetCF.insert(PWIDGET_FRAME, wc);
wc = new widgetCreate;
wc->wc = PLineEdit::createWidget;
widgetCF.insert(PWIDGET_LINED, wc);
wc = new widgetCreate;
wc->wc = PButton::createWidget;
widgetCF.insert(PWIDGET_BUTTON, wc);
wc = new widgetCreate;
wc->wc = PPushButton::createWidget;
widgetCF.insert(PWIDGET_PUSHBT, wc);
wc = new widgetCreate;
wc->wc = PProgress::createWidget;
widgetCF.insert(PWIDGET_KSPROGRESS, wc);
wc = new widgetCreate;
wc->wc = PTableView::createWidget;
widgetCF.insert(PWIDGET_TABLEVW, wc);
wc = new widgetCreate;
wc->wc = PListBox::createWidget;
widgetCF.insert(PWIDGET_LISTBOX, wc);
wc = new widgetCreate;
wc->wc = PLabel::createWidget;
widgetCF.insert(PWIDGET_LABEL, wc);
wc = new widgetCreate;
wc->wc = PPopupMenu::createWidget;
widgetCF.insert(PWIDGET_POPMENU, wc);
wc = new widgetCreate;
wc->wc = PAListBox::createWidget;
widgetCF.insert(PWIDGET_ALISTBOX, wc);
wc = new widgetCreate;
wc->wc = PTabDialog::createWidget;
widgetCF.insert(PWIDGET_TABDIALOG, wc);
wc = new widgetCreate;
wc->wc = PKFileDialog::createWidget;
widgetCF.insert(PWIDGET_KFILEDIALOG, wc);
wc = new widgetCreate;
wc->wc = PObjFinder::createWidget;
widgetCF.insert(PWIDGET_OBJFINDER, wc);
// Each function handler gets an entry in the qidCommandTable
commandStruct *cs;
// Invalid is the default invalid handler
cs = new commandStruct;
cs->cmd = &PukeController::hdlrPukeInvalid;
cs->library = 0;
qidCommandTable.insert(PUKE_INVALID, cs);
// Setup's handled by the setup handler
cs = new commandStruct;
cs->cmd = &PukeController::hdlrPukeSetup;
cs->library = 0;
qidCommandTable.insert(PUKE_SETUP, cs);
// We don't receive PUKE_SETUP_ACK's we send them.
cs = new commandStruct;
cs->cmd = &PukeController::hdlrPukeInvalid;
cs->library = 0;
qidCommandTable.insert(PUKE_SETUP_ACK, cs);
cs = new commandStruct;
cs->cmd = &PukeController::hdlrPukeEcho;
cs->library = 0;
qidCommandTable.insert(PUKE_ECHO, cs);
// Fetch widget gets the requested widget from the ServerController
cs = new commandStruct;
cs->cmd = &PukeController::hdlrPukeFetchWidget;
cs->library = 0;
qidCommandTable.insert(PUKE_FETCHWIDGET, cs);
// Fetch widget gets the requested widget from the ServerController
cs = new commandStruct;
cs->cmd = &PukeController::hdlrPukeDumpTree;
cs->library = 0;
qidCommandTable.insert(PUKE_DUMPTREE, cs);
// Fetch widget gets the requested widget from the ServerController
cs = new commandStruct;
cs->cmd = &PukeController::hdlrPukeDeleteWidget;
cs->library = 0;
qidCommandTable.insert(PUKE_WIDGET_DELETE, cs);
}
// Start message handlers
void PukeController::hdlrPukeInvalid(int fd, PukeMessage *)
{
PukeMessage pmOut;
memset(&pmOut, 0, sizeof(pmOut));
this->writeBuffer(fd, &pmOut);
}
void PukeController::hdlrPukeSetup(int fd, PukeMessage *pm)
{
PukeMessage pmOut;
memset(&pmOut, 0, sizeof(pmOut));
pmOut.iCommand = PUKE_SETUP_ACK;
pmOut.iArg = 1;
if((strlen(pm->cArg) > 0) &&
(this->qidConnectFd[fd] != NULL)){
this->qidConnectFd[fd]->server = qstrdup(pm->cArg);
pmOut.iWinId = pm->iWinId;
pmOut.iArg = sizeof(PukeMessage) - sizeof(char *);
}
this->writeBuffer(fd, &pmOut);
}
void PukeController::hdlrPukeEcho(int fd, PukeMessage *pm)
{
PukeMessage pmOut;
memcpy(&pmOut, pm, sizeof(PukeMessage));
pmOut.iCommand = PUKE_ECHO_ACK;
pmOut.iWinId = pm->iWinId;
pmOut.iArg = pm->iArg;
this->writeBuffer(fd, &pmOut);
}
void PukeController::hdlrPukeDumpTree(int fd, PukeMessage *pm)
{
objFinder::dumpTree();
PukeMessage pmOut;
memcpy(&pmOut, pm, sizeof(PukeMessage));
pmOut.iCommand = -pm->iCommand;
pmOut.iWinId = pm->iWinId;
pmOut.iArg = pm->iArg;
this->writeBuffer(fd, &pmOut);
}
void PukeController::hdlrPukeFetchWidget(int fd, PukeMessage *pm)
{
widgetId wIret;
/*
* The parent widget ID and type are packed into the iArg
* the pattern is 2 shorts.
*/
int iParent=-1, iType=-1;
char rand[50],name[50];
int found = sscanf(pm->cArg, "%d\t%d\t%49s\t%49s", &iParent, &iType, rand, name);
if(found != 4){
throw(errorCommandFailed(PUKE_INVALID,6));
}
uiBaseWinId++; // Get a new base win id
// wIret holds the current widget id for the new widget
wIret.iWinId = uiBaseWinId;
wIret.fd = fd;
// CreateArgs arg = CreateArgs(this, pm, &wIret, parent)
CreateArgs arg(this, pm, &wIret, 0);
// Let's go looking for the widget
// Match any class with the right name
TQObject *obj = 0x0;
if(parent() && (strcmp(name, parent()->name()) == 0)){
obj = parent();
}
else {
obj = objFinder::find(name, 0x0);
if(obj == 0){
wIret.fd = 0;
wIret.iWinId = 0;
throw(errorCommandFailed(PUKE_INVALID,5));
}
}
arg.fetchedObj = obj;
WidgetS *ws = new WidgetS;
ws->pwidget = (widgetCF[iType]->wc)(arg);
if (ws->pwidget->hasError())
{
throw(errorCommandFailed(PUKE_INVALID, 0));
}
ws->type = iType;
connect(ws->pwidget, TQT_SIGNAL(outputMessage(int, PukeMessage*)),
this, TQT_SIGNAL(outputMessage(int, PukeMessage*)));
// insertPBoject(fd, uiBaseWinId, ws);
// The widget list has to exist since we have ourselves in the list
// WidgetList[wIret.fd]->insert(wIret.iWinId, ws);
insertPObject(wIret.fd, wIret.iWinId, ws);
PukeMessage pmRet;
pmRet.iCommand = PUKE_WIDGET_CREATE_ACK;
pmRet.iWinId = wIret.iWinId;
pmRet.iArg = 0;
pmRet.iTextSize = pm->iTextSize;
pmRet.cArg = pm->cArg;
emit outputMessage(fd, &pmRet);
}
void PukeController::hdlrPukeDeleteWidget(int fd, PukeMessage *pm)
{
widgetId wI;
wI.fd = fd;
wI.iWinId = pm->iWinId;
if(pm->iWinId == ControllerWinId) // Don't try and delete ourselves
throw(errorCommandFailed(PUKE_INVALID, INVALID_DEL_NO_CONTROL));
/*
TQIntDict<WidgetS> *qidWS = WidgetList[fd];
if(qidWS == 0){
kdDebug(5008) << "WidgetRunner:: no such set of widget descriptors?" << endl;
throw(errorCommandFailed(PUKE_INVALID, INVALID_DEL_NO_SUCH_CONNECTION));
}
if(qidWS->find(wI.iWinId)){
// Remove the list item then delete the widget. This will stop
// the destroyed signal from trying to remove it again.
PObject *pw = qidWS->find(wI.iWinId)->pwidget;
qidWS->remove(wI.iWinId);
delete pw; pw = 0;
pmRet.iCommand = PUKE_WIDGET_DELETE_ACK;
}
else {
qWarning("WidgetRunner: no such widget: %d", wI.iWinId);
throw(errorCommandFailed(PUKE_INVALID, INVALID_DEL_NO_SUCH_WIDGET));
}
*/
if(checkWidgetId(&wI) == FALSE){
qWarning("WidgetRunner: no such widget: %d", wI.iWinId);
throw(errorCommandFailed(PUKE_INVALID, INVALID_DEL_NO_SUCH_WIDGET));
}
WidgetList[fd]->find(wI.iWinId)->pwidget->manTerm();
delete WidgetList[fd]->find(wI.iWinId)->pwidget;
PukeMessage pmRet = *pm;
pmRet.iCommand = PUKE_WIDGET_DELETE_ACK;
emit outputMessage(fd, &pmRet);
}
void PukeController::closefd(int fd)
{
if(bClosing == TRUE)
return;
bClosing = TRUE;
if(qidConnectFd[fd] == NULL){
kdDebug(5008) << "PukeController: Connect table NULL, closed twice?" << endl;
return;
}
// Shutof the listener before closing the socket, just in case.
qidConnectFd[fd]->sr->setEnabled(FALSE); // Shut them off
qidConnectFd[fd]->sw->setEnabled(FALSE);
delete qidConnectFd[fd]->sr;
delete qidConnectFd[fd]->sw;
qidConnectFd[fd]->server.truncate(0);
qidConnectFd.remove(fd);
close(fd);
/*
* Now let's remove all traces of the widgets
*/
TQIntDict<WidgetS> *qidWS = WidgetList[fd];
if(qidWS == 0){
kdDebug(5008) << "WidgetRunner:: Close called twice?" << endl;
bClosing = FALSE;
return;
}
qidWS->remove(PUKE_CONTROLLER);
do {
TQIntDictIterator<WidgetS> it(*qidWS);
if(it.count() == 0){
kdDebug(5008) << "WidgetRunner: nothing left to delete\n" << endl;
break;
}
PObject *po = 0x0;
while(it.current()){
/*
* Delete all the layouts first
*
*/
if(it.current()->type == POBJECT_LAYOUT){
po = it.current()->pwidget;
break;
}
++it;
}
if(po != 0x0){
po->manTerm();
delete po;
continue;
}
/*
* reset
*/
it.toFirst();
po = it.current()->pwidget;
po->manTerm();
delete po;
} while (qidWS->count() > 0);
WidgetList.remove(fd);
bClosing = FALSE;
}
bool PukeController::checkWidgetId(widgetId *pwi)
{
if(WidgetList[pwi->fd] != NULL)
if(WidgetList[pwi->fd]->find(pwi->iWinId) != NULL)
return TRUE;
return FALSE;
}
PObject *PukeController::id2pobject(widgetId *pwi){
if(checkWidgetId(pwi) == TRUE){
return WidgetList[pwi->fd]->find(pwi->iWinId)->pwidget;
}
throw(errorNoSuchWidget(*pwi));
return 0; // never reached
}
PObject *PukeController::id2pobject(int fd, int iWinId){
widgetId wi;
wi.fd = fd;
wi.iWinId = iWinId;
return id2pobject(&wi);
}
PWidget *PukeController::id2pwidget(widgetId *pwi){
PObject *obj = id2pobject(pwi);
if(obj->widget()->isWidgetType())
return (PWidget *) obj;
else
throw(errorNoSuchWidget(*pwi));
return NULL;
}
void PukeController::insertPObject(int fd, int iWinId, WidgetS *obj){
// If no widget list exists for this fd, create one
if(WidgetList[fd] == NULL){
TQIntDict<WidgetS> *qidWS = new TQIntDict<WidgetS>;
qidWS->setAutoDelete(TRUE);
WidgetList.insert(fd, qidWS);
}
// Set main widget structure list
WidgetList[fd]->insert(iWinId, obj);
// Set reverse list used durring delete to remove the widget
widgetId *pwi = new widgetId;
pwi->fd = fd;
pwi->iWinId = iWinId;
char key[keySize];
memset(key, 0, keySize);
sprintf(key, "%p", obj->pwidget);
revWidgetList.insert(key, pwi);
// Now connect to the destroyed signal so we can remove the object from the lists
// Once it is deleted
connect(obj->pwidget, TQT_SIGNAL(destroyed()),
this, TQT_SLOT(pobjectDestroyed()));
}
void PukeController::pobjectDestroyed(){
char key[keySize];
memset(key, 0, keySize);
sprintf(key, "%p", this->sender());
widgetId *pwi = revWidgetList[key];
if(pwi == NULL){
kdDebug(5008) << "Someone broke the rules for pwi: " << pwi->fd << ", " << pwi->iWinId << endl;
return;
}
if(checkWidgetId(pwi) == TRUE){
WidgetList[pwi->fd]->remove(pwi->iWinId);
}
else {
kdDebug(5008) << "Someone stole pwi: " << pwi->fd << ", " << pwi->iWinId << endl;
}
pwi = 0x0; // remove deletes pwi
revWidgetList.remove(key);
}
void PukeController::messageHandler(int fd, PukeMessage *pm) {
widgetId wI, wIret;
wI.fd = fd;
wI.iWinId = pm->iWinId;
commandStruct *cs;
cs = qidCommandTable[pm->iCommand];
if(cs != NULL){
(this->*(cs->cmd))(fd,pm);
}
else if(pm->iCommand == PUKE_WIDGET_CREATE){
wIret = wI;
wIret.iWinId = createWidget(wI, pm).iWinId; // Create the acutal pw
PukeMessage pmRet;
pmRet.iCommand = PUKE_WIDGET_CREATE_ACK;
pmRet.iWinId = wIret.iWinId;
pmRet.iArg = 0;
pmRet.cArg = strdup(pm->cArg);
pmRet.iTextSize = strlen(pm->cArg);
emit outputMessage(fd, &pmRet);
free(pmRet.cArg);
}
else if(pm->iCommand == PUKE_WIDGET_LOAD){
PukeMessage pmRet = *pm;
KLibrary *library;
PObject *(*wc)(CreateArgs &ca);
widgetCreate *wC;
if(widgetCF[pm->iArg]){
pmRet.iCommand = -pm->iCommand;
pmRet.iTextSize = 0;
emit outputMessage(fd, &pmRet);
return;
}
if(pm->iTextSize == 0){
emit(errorCommandFailed(-pm->iCommand, 1));
return;
}
TQString libName = "ksirc/lib"+TQString::fromLatin1(pm->cArg);
if (libName.right(3) == ".so")
libName = libName.left(libName.length()-2)+"la";
library = KLibLoader::self()->library(libName);
if (!library) {
emit(errorCommandFailed(-pm->iCommand, 1));
return;
}
wc = (PObject *(*)(CreateArgs &ca) )
library->symbol("createWidget");
wC = new widgetCreate;
wC->wc = wc;
wC->library = library;
widgetCF.insert(pm->iArg, wC);
pmRet.iCommand = -pm->iCommand;
pmRet.iTextSize = 0;
emit outputMessage(fd, &pmRet);
}
else if(pm->iCommand == PUKE_WIDGET_UNLOAD){
if(widgetCF[pm->iArg]){
// delete widgetCF[pm->iArg]->library;
widgetCF.remove(pm->iArg);
pm->iCommand = -pm->iCommand;
emit outputMessage(fd, pm);
}
}
else{
if(checkWidgetId(&wI) == TRUE){
WidgetList[wI.fd]->find(wI.iWinId)->pwidget->messageHandler(fd, pm);
}
else{
PukeMessage pmRet;
pmRet.iCommand = PUKE_INVALID;
pmRet.iWinId = wI.iWinId;
pmRet.iArg = 0;
pmRet.iTextSize = 0;
emit outputMessage(fd, &pmRet);
}
}
}
widgetId PukeController::createWidget(widgetId wI, PukeMessage *pm)
{
widgetId wIret;
PWidget *parent = 0; // Defaults to no parent
WidgetS *ws = new WidgetS;
/*
* The parent widget ID and type are packed into the iArg
* the pattern is 2 shorts.
*/
int iParent, iType;
int found = sscanf(pm->cArg, "%d\t%d", &iParent, &iType);
if(found != 2)
throw(errorCommandFailed(PUKE_INVALID,7));
wI.iWinId = iParent; // wI is the identifier for the parent widget
if(widgetCF[iType] == NULL){ // No such widget, bail out.
wIret.fd = 0;
wIret.iWinId = 0;
throw(errorCommandFailed(PUKE_INVALID,1));
}
uiBaseWinId++; // Get a new base win id
// wIret holds the current widget id for the new widget
wIret.iWinId = uiBaseWinId;
wIret.fd = wI.fd;
if(checkWidgetId(&wI) == TRUE){
PObject *obj = WidgetList[wI.fd]->find(wI.iWinId)->pwidget;
if(obj->widget()->isWidgetType() == FALSE){
throw(errorCommandFailed(PUKE_INVALID, 0));
}
parent = (PWidget *) obj;
}
// CreateArgs arg = CreateArgs(this, pm, &wIret, parent)
CreateArgs arg(this, pm, &wIret, parent);
ws->pwidget = (widgetCF[iType]->wc)(arg);
if (ws->pwidget->hasError())
{
throw(errorCommandFailed(PUKE_INVALID, 0));
}
ws->type = iType;
connect(ws->pwidget, TQT_SIGNAL(outputMessage(int, PukeMessage*)),
this, TQT_SIGNAL(outputMessage(int, PukeMessage*)));
// insertPBoject(fd, uiBaseWinId, ws);
// The widget list has to exist since we have ourselves in the list
insertPObject(wIret.fd, wIret.iWinId, ws);
// WidgetList[wIret.fd]->insert(wIret.iWinId, ws);
return wIret;
}
#include "controller.moc"