summaryrefslogtreecommitdiffstats
path: root/ksirc/puke/HOWTO-PUKE.pod
diff options
context:
space:
mode:
Diffstat (limited to 'ksirc/puke/HOWTO-PUKE.pod')
-rw-r--r--ksirc/puke/HOWTO-PUKE.pod325
1 files changed, 325 insertions, 0 deletions
diff --git a/ksirc/puke/HOWTO-PUKE.pod b/ksirc/puke/HOWTO-PUKE.pod
new file mode 100644
index 00000000..cf44e77e
--- /dev/null
+++ b/ksirc/puke/HOWTO-PUKE.pod
@@ -0,0 +1,325 @@
+=head1 OVERVIEW
+
+This document describes how to write puke addons and additional
+widgets. It assumes a good knowledge of C++, perl and X/Qt workings
+under Linux.
+
+=head1 1. Description and Background
+
+=over 6
+
+Puke's a generic protocol allowing dsirc to communicate with ksirc.
+Communications works over a unix domain socket between multiple
+client dsirc process's to a single ksirc process. All communications
+is done via a variable length message with the following layout:
+
+=begin text
+
+struct PukeMessage {
+unsigned int iHeader;
+int iCommand;
+int iWinId;
+int iArg;
+int iTextSize;
+char *cArg;
+}
+
+=end text
+
+None of the fields except for iCommand, iWinId and iHeader have any restrictions
+on their content and may contain arbitrary values. iCommand and iWinId must
+contain an int and it used by ksirc to determine the destination and
+handler of the actual command. (and of course it's meaning). iHeader is a
+fixed pattern used to identify the start of a header message should it loose
+syncronization. The current pattern used it 2863311530, which is:
+10101010101010101010101010101010.
+
+=item Internal handling by kSirc:
+
+Messages are received by a generic handler, PukeController where the message
+is passed to the iWinId's messageDipatcher for final processing. The
+iWinId of 1 through 10 are reserved for internal use, and 1 is
+currently set at the window ID for the PukeController itself.
+
+Connect a signal to PukeControllers writeBuffer (signal's generally
+called outputMessage) and pass the fd and PukeMessage to be sent to
+the client. No parsing of the output message is done.
+
+=item Internal handling by dsirc:
+
+All received messages are handled by an internal callback methods. 3
+sets of callbacks are checked for handlers in the following order:
+
+$PUKE_HANDLER{$cmd}{$winid}
+$PUKE_HANDLER{-$cmd}{$winid}
+$PUKE_DEF_HANDLER{$cmd}
+
+If no handler is found an error is printed.
+
+Output is handled by the PukeSendMessage function. PBase defines an
+alternate routine sendMessage which should be a lot friendlier.
+
+=head1 2. How to create a new widget
+
+There are 2 parts to creating a widget, the C++ code and the
+supporting perl5-oop object.
+
+=head2 2.1 C++ Widget code
+
+The C++ code must be able to hand all required settings and messages
+for the widget. Each new widget iherites it's parent and so forth
+allowing for a nice oop layout. The widget structure the author is
+following is the same as Qt's. Their seems to work well, why
+re-invent the wheel?
+
+=item 2.1.1 General Layout, etc
+
+Figure where your new widget goes in the heirachy. If it's a simple
+Qt widget, I recommend using their existing layout. Man pages list
+what widgets inherit what.
+
+The general idea behind the widget layout should be to be to provide
+all the functionality of the widget to dsirc perl script. Incoming
+messages are handled via the messageHandler and ALL messages should
+return an ACK with current state info.
+
+New widgets are created as shared objects and loaded on the fly. This
+means you don't need to recompile ksirc to use new widgets etc.
+
+Generally you'll have to inherit PWidget at a minimum.
+
+Functions you HAVE TO overrite:
+
+B<1. createWidget>
+
+This function creates a new widget of your type and returns a
+*PWidget.
+
+B<2. messageHandler>
+
+This function receives ALL your commands.
+
+B<3. widget() and setWidget(YourWidget *)>
+
+These set and return your widget.
+
+
+If you care about inheritance, which you should, all these functions
+should be virtual. (Since we are using pointers to PWidget's
+everywhere, it's a good bet you want your children's overriden
+functions called, not yours)
+
+The structure internally will have to hold a local copy of the widget,
+and connect to it's destroy signal so you can know when it has been
+destroyed.
+
+=item 2.1.2 createWidget
+
+createWidget is defined as:
+
+PWidget *createWidget(widgetId *pwi, PWidget *parent);
+
+It is called everytime a new widget of yours is required. The
+widgetId will be the identifier for your widget and must be kept for
+all future commands. PWidget::setWidgetId(pwi) should be called to
+set the widget id. The *parent is the parent of the current widget.
+Generally PWidget->widget() is passed to the contructor of your
+widget. If it's 0, there is no parent. Simeplfied code for a the
+PFrame is:
+
+=begin text
+
+extern "C" {
+PWidget *createWidget(widgetId *pwi, PWIdget *parent);
+}
+
+PWidget *createWidget(widgetId *pwi, PWIdget *parent){
+ QFrame *f;
+ PFrame *pf = new PFrame(parent);
+ if(parent != 0){
+ f = new QFrame(parent->widget());
+ }
+ else{
+ f = new QPFrame();
+ }
+ pf->setWidget(f);
+ pf->setWidgetId(pwi);
+ return pf;
+}
+
+=end text
+
+Note: you have to check parent for null since calling NULL->widget()
+results in Bad Things (tm).
+
+=item 2.1.3 messageHandler
+
+This receives all commands, etc. It should process required commands,
+if a command is unkown pass it to the parent. PFrame example:
+
+=begin text
+
+class PFrame : public PWidget
+...
+void messageHandler(int fd, PukeMessage *pm);
+...
+
+void PFrame::messageHandler(int fd, PukeMessage *pm) {
+ PukeMessage pmRet;
+ switch(pm->iCommand){
+ case PUKE_QFRAME_SET_FRAME:
+ widget()->setFrameStyle(pm->iArg);
+ pmRet.iCommand = PUKE_QFRAME_SET_FRAME_ACK;
+ pmRet.iWinId = pm->iWinId;
+ pmRet.iArg = widget()->frameStyle();
+ pmRet.cArg[0] = 0;
+ emit outputMessage(fd, &pmRet);
+ break;
+ default:
+ PWidget::messageHandler(fd, pm);
+ }
+}
+
+=end text
+
+=item 2.1.4 widget and setWidget
+
+Both these functions should be overriden and return your widget type,
+and set your widget. For setWidget you should connect required
+signals and eventFilters you are using.
+
+Make sure to call the parents setWidget in setWidget so it can connect
+filters etc.
+
+BEWARE: You might get the widget into setWidget being null (from the
+destructor).
+
+Another PFrame example (APE ;) ):
+
+=begin text
+void PFrame::setWidget(QFrame *_f)
+{
+ frame = _f;
+ PWidget::setWidget(_f);
+
+}
+
+
+QFrame *PFrame::widget()
+{
+ return frame;
+}
+
+=end text
+
+=item 2.1.5 Destructor
+
+Ok, unfortunaly since we have this internal widget floating arround
+the destructor has to a little maigc.
+
+Call the destructor as such:
+
+delete widget();
+setWidget(0);
+
+This will clear the widget from now and all parents and delete it.
+you never want it deleted twice. (deleting 0 won't hurt)
+
+=head2 2.2 The Perl code
+
+Most of the perl oop is pretty straight forward, command simply issue
+a require sendMessage and off everything goes. There's one problem.
+
+You can't get information back on the current read cycle. Huh? I can
+hear most people saying. It means say someone wanted to do $widget =
+$widget->height() and you didn't have the height information locally,
+there's no way to get the information and return it to them. Why? You
+issue a sendMessage(...) but until dsirc returns to the main select()
+loop, we never know there's more to read. We can't return to the main
+select loop until we return from our current function. What does this
+mean? We have to store all the information locally.
+
+This also brings up another intresting aspect. Sometimes a widget may
+depend on a prior command before it can complete. This is the purpose
+of canRun function, and onNext. It's use will have to be explained
+latter.
+
+To help with this problem, pbase.pm sets up a fairly complicated set
+of message and event queues. Be warned when you issue a sendMessage,
+it might not get sent right away.
+
+I'll provide example bellow of how I've done certain functions, this
+is certainly not the only way to do it. Feel free to use any format
+you like aslong as it get's the job done.
+
+Ok, so how do we do this?
+
+=item 2.2.1 Perl oop? where do I start?
+
+Read the perltoot and perlobj man pages.
+
+=item 2.2.2 What to inherit etc.
+
+You probably want to inherit the same object as your C function does.
+At very least you'll want to inherit PWidget.
+
+=item 2.2.3 new and DESTROY
+
+Your new function should look something like (APE?):
+
+=begin text
+
+sub new {
+ my $class = shift;
+ my $self = $class->SUPER::new($class, @_);
+
+ $self->{widgetType} = $::PWIDGET_FRAME;
+
+ if($class eq 'PFrame'){
+ $self->create();
+ }
+
+ return $self;
+}
+
+=end text
+
+$self is the blessed variable and it returned from the super class.
+You should always do it this way. Setting widgetType defines the type
+of widget, and needs to be set before calling create.
+
+If we are creating an object of our own class we call create() which
+acutally sends out the correct creation messages, etc. You can
+override the create function, but do be warned it might not be a good
+idea. Make sure you understand what and how it does it first!
+
+=item 2.2.4 sendMessage
+
+sendMessage is the main form of communicating with kSirc. Generable
+arguments are:
+
+=begin text
+
+sendMessage('iCommand' => command number,
+ 'iArg' => interger argument,
+ 'cArg' => character string,
+ 'CallBack' => pointer to sub, generally sub{...}
+ );
+
+=end text
+
+You'll note it's a hash so order doesn't count. The callback is a 1
+shot call back (should be) so don't count on it getting hit twice.
+The call back's first argument will be a \%ARGS with the return
+arguments.
+
+=item 2.2.5 Final notes on perl
+
+Most of the function calls will just send out messages, etc. For call
+backs the general form I've found works well is: sub {$self->blah()}.
+
+=head1 3. Interfacing with the kSirc's main windows and functions
+
+NOT implemented yet.
+
+=back