RE: GII event system

1999-10-22 Thread Dmitry Semenov

Hi

I just got one device which will be not so good to drive with your
conception of dividing space and click data:
This is touch screen.  I think you used bank machines or something like that
:)

Best Regards. Dmitry

-Original Message-
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]]
Sent: Friday, October 22, 1999 3:05 AM
To: [EMAIL PROTECTED]
Subject: Re: GII event system



Hi !

 1. Mouse is a human input device, as well as others pointing device.
 Practically buttons are related to mouse position and usual human expects
 reasonable button action right in place where he has clicked it.

Yes. This however does not mean, that the driver producing the "clicks" has
to know anything about the driver producing the moves.

This is why the moves and clicks are separate. Please note, that it is
possible to mix relative and absolute pointer events. A simple example of
that would be keyboard emulated mouse (which only makes sense as relative
events) on a absolute-mouse target like X.

 What have we do with GII. Something like that collecting:
 pmove1 abs
 pbutton
 pmove2 abs
 will do
 (pmove1.x +pmove2.x)/2 and the same for y.

??? What ?

I'll sketch how a LibGGI mouse handling routine for a system that expects to
work with absolute coordinates is intended to look like:

{
  static int mousex,mousey;
  ...

  ggiEventPoll(vis, emKey|emPointer, NULL);
  events = ggiEventsQueued(vis, emKey|emPointer);

  while (events--) {
ggiEventRead(vis, event, emKey|emPointer);

switch(event.any.type) {
  case evPtrButtonPress:
switch(event.pbutton.button) {
  case GII_PBUTTON_FIRST:
do_something_as_appropriate(mousex,mousey);
break;
  case GII_PBUTTON_SECOND:
...
}
break;
  case evPtrButtonRelease:
... if needed ...
break;
  case evPtrAbsolute:
mousex = event.pmove.x;
mousey = event.pmove.y;
break;
  case evPtrRelative:
mousex += event.pmove.x;
mousey += event.pmove.y;
break;
}
/* Constrain mouse in any case */
if (mousex  0) mousex = 0;
if (mousey  0) mousey = 0;
if (mousex  xmax) mousex = xmax;
if (mousey  ymax) mousey = ymax;

  } /* while */
}

As you can see, this nicely symmetriyes the cases of abs and rel events.
Basically the same can be done for apps that expect relative events, though
those might get trouble on absolute input data when trying to "keep turning
left" or similar.

 Was it good? It is no good, at least because gii client software is not
 right place to do it.

To do what ? (pmove1.x +pmove2.x)/2 ? There is no reasonable place to do
such a calculation at all. To make sense at all, you would have to make a
weighted mean based on the time between the individual event's timestamps.
There is no assumption of something like a linear motion between points
between move events, and for sure no assumption, that the click happens in
the middle of that.

The expected behaviour is, that the above used mousex,mousey variables
express the correct position of the pointer, when a click comes in.

If the mouse was moved between the last move and the click, the driver is
expected to send another move and then the click to correctly position the
pointer before transmitting the click.

 Why do I need to keep every pmove message until get
 pbutton and pmove again? That is not pretty at least.

You don't. See above. In case that delivers incorrect results, we have a bug
in a driver or backend and need to fix the driver or flame the backend
authors.

 I understand  that it is my task to determinate correct click place in
case
 of relative move messages and I do. But I really hope I will be able to
 avoid mouse cursor software emulation(what I have done because of no
choice)
 and to forget about relative messages for pointing device like mouse  in
the
 future when GGI will take care about hardware cursor.

GGI will never take away the information you get from the input device.
While we may provide a method to place a hardware sprite on the display,
thus allowing to easily make up a mouse pointer, this will not influence
the pointer data sent from the input device.

 I repeat ones more I am discussing only about the case when cursor
 generation is not my task.

I still do not get what cursor generation has to do with input handling.

There are some applications that would be pretty unhappy, if we converted
all input to absolute pointer events. Guess why the X target has the
relmouse mode ...

 In the depth My question was why after calling  poll(I call it with 0 time
 delay)  the queued function  shows only one message we have inside of
 queue but actually there are many (inside of some internal buffers).

If that is the case, this is a bug and should be fixed.

 I think poll function really poll only one message for each message type
 per one call, does not it?

No. It should check and queue all attached in

GII event system

1999-10-21 Thread Dmitry Semenov

1. Why GII gii_event.pbutton does not have cursor coordinate information in
case of GII buffering and sending data which have absolute cursor position(x
target and may be future fb target with hardware cursor).
2. Why GII does not use button data in case of sending pmove event?
3. I found some strange behavior inside of GII.
-I poll GII one time
-I read all events queued inside GII in my internal buffer with keeping
only onepmove message inside of my buffer
-I read one message from my buffer.
-I move my cursor in case of pmove data
-I call  ggUSleep(10);
-I see funny effect on the screen:
my cursor making always is to late :) It looks like GII buffer can not
giveme back all messages by one polling.

if I do poll and read queued messages like this:

while(Poll()); instead of one polling

where Poll is something like this. (DO not forget I do not save reputed
pmove messages. I cleaned that code to save space.)

bool wipGII::Poll()
{
bool r=false;
timeval val;
val.tv_sec=0;
val.tv_usec=0;
ggiEventPoll(graph-vis, emAll, val);
for (int n=ggiEventsQueued(graph-vis, emAll); n; n--)
{
   ggiEventRead(graph-vis, ev[(unsigned char)(ev_ptr+ev_qty)], emAll);
if (ev_qty!=0xff) ev_qty++; else ev_ptr++;
r=true;
}
return r;
}

I've found no problem with my cursor.

Thank you
Dmitry



Re: GII event system

1999-10-21 Thread becka

Hi !

 1. Why GII gii_event.pbutton does not have cursor coordinate information 

Because the buttons and the pointer position are not related in any way
theoretically. Using the mapper filters, you can push "mouse buttons" on 
the keyboard and vice versa ...

 in case of GII buffering and sending data which have absolute cursor 
 position (x target and may be future fb target with hardware cursor).

? I don't get you here. What has absoluet cursor position to do with buttons ?

 2. Why GII does not use button data in case of sending pmove event?

Same reason, see above.

 3. I found some strange behavior inside of GII.
   -I poll GII one time
   -I read all events queued inside GII in my internal buffer with keeping
  only one pmove message inside of my buffer
   -I read one message from my buffer.
   -I move my cursor in case of pmove data
   -I call  ggUSleep(10);
   -I see funny effect on the screen:
my cursor making always is to late :) It looks like GII buffer can not
give me back all messages by one polling.
 
 if I do poll and read queued messages like this:
 
 while(Poll()); instead of one polling
 where Poll is something like this [... snip ...]
 I've found no problem with my cursor.

Hmm - I get you right, that gii events are kept queued inside gii when you 
try to read them - right ?

Well, there is a possible simple explanation:

ggiPoll unblocks _as_soon_as_ one of the associated FDs gets readable. Now, 
if the Mouse e.g. first sends a Pointer-update-packet or similar, this gets 
read into LibGGI immediately during the poll. The poll then unblocks, as data 
is available. At that point, there is only the first sent event from the 
mouse available. The mouse keeps sending data, but the LibGII poll routine 
has already terminated, as it terminates as soon as the first event gets 
readable.

For such situations, where this behaviour is undesireable, as there are long 
delays between frames, it might make sense to use something like

while(ggiPoll()) { 
do_the_evenht_reading();
eventually_wait_a_short_grace_time(); 
}

This allows for "slow" devices that do not instantaneously deliver all data.
What mouse do you have ? we might want to check the driver, if it does the 
expected thing, which is to loop in its poll handler as long as data is 
incoming.

CU, Andy

-- 
Andreas Beck  |  Email :  [EMAIL PROTECTED]



RE: GII event system

1999-10-21 Thread Dmitri Semenov

Hi
Thanks for your reply
1. Mouse is a human input device, as well as others pointing device.
Practically buttons are related to mouse position and usual human expects
reasonable button action right in place where he has clicked it. What have
we do with GII. Something like that
collecting:
pmove1 abs
pbutton
pmove2 abs
will do
(pmove1.x +pmove2.x)/2 and the same for y.
Was it good? It is no good, at least because gii client software is not
right place to do it. Why do I need to keep every pmove message until get
pbutton and pmove again? That is not pretty at least.

I understand  that it is my task to determinate correct click place in case
of relative move messages and I do. But I really hope I will be able to
avoid mouse cursor software emulation(what I have done because of no choice)
and to forget about relative messages for pointing device like mouse  in the
future when GGI will take care about hardware cursor.

Also I do not see any problem with "Using the mapper filters, you can push
"mouse buttons" on the keyboard and vice versa ..."
For example Button can be the "reset button" on the computer instead of left
or middle mouse button, but if human thinks that that one has functionality
related to the mouse cursor it should be and We have to have xyz closure to
the click place inside of point device driver. I repeat ones more I am
discussing only about the case when cursor generation is not my task.

2. Please refer my old mail. I already found the way how to live together
with poll, and read functions :) In the depth My question was why after
calling  poll(I call it with 0 time delay)  the queued function  shows only
one message we have inside of queue but actually there are many(inside of
some internal buffers). I think poll function really poll only one message
for each message type per one call, does not it?
Using of gii like this:

poll
n=queued
while(n--) read

is bad in case of i have some internal buffers and some other cases.

Actually I have to do following code to have all last messages
n=0;
do
{
while(n--) read;
poll()
}
while (n=queued);

It seems a strange for me behavior like that I expected that after Poll funk
Queued will report all messages from internal buffers.


Best regards, Dmitry Semenov

-Original Message-
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]]
Sent: Thursday, October 21, 1999 18:02
To: [EMAIL PROTECTED]
Subject: Re: GII event system



Hi !

 1. Why GII gii_event.pbutton does not have cursor coordinate information

Because the buttons and the pointer position are not related in any way
theoretically. Using the mapper filters, you can push "mouse buttons" on
the keyboard and vice versa ...

 in case of GII buffering and sending data which have absolute cursor
 position (x target and may be future fb target with hardware cursor).

? I don't get you here. What has absoluet cursor position to do with buttons
?

 2. Why GII does not use button data in case of sending pmove event?

Same reason, see above.

 3. I found some strange behavior inside of GII.
   -I poll GII one time
   -I read all events queued inside GII in my internal buffer with keeping
  only one pmove message inside of my buffer
   -I read one message from my buffer.
   -I move my cursor in case of pmove data
   -I call  ggUSleep(10);
   -I see funny effect on the screen:
my cursor making always is to late :) It looks like GII buffer can not
give me back all messages by one polling.

 if I do poll and read queued messages like this:

 while(Poll()); instead of one polling
 where Poll is something like this [... snip ...]
 I've found no problem with my cursor.

Hmm - I get you right, that gii events are kept queued inside gii when you
try to read them - right ?

Well, there is a possible simple explanation:

ggiPoll unblocks _as_soon_as_ one of the associated FDs gets readable. Now,
if the Mouse e.g. first sends a Pointer-update-packet or similar, this gets
read into LibGGI immediately during the poll. The poll then unblocks, as
data
is available. At that point, there is only the first sent event from the
mouse available. The mouse keeps sending data, but the LibGII poll routine
has already terminated, as it terminates as soon as the first event gets
readable.

For such situations, where this behaviour is undesireable, as there are long
delays between frames, it might make sense to use something like

while(ggiPoll())

do_the_evenht_reading();
eventually_wait_a_short_grace_time();
}

This allows for "slow" devices that do not instantaneously deliver all data.
What mouse do you have ? we might want to check the driver, if it does the
expected thing, which is to loop in its poll handler as long as data is
incoming.

CU, Andy

--
Andreas Beck  |  Email :  [EMAIL PROTECTED]



Re: GII event system

1999-10-21 Thread Andreas Beck

Hi !

 1. Mouse is a human input device, as well as others pointing device.
 Practically buttons are related to mouse position and usual human expects
 reasonable button action right in place where he has clicked it. 

Yes. This however does not mean, that the driver producing the "clicks" has
to know anything about the driver producing the moves.

This is why the moves and clicks are separate. Please note, that it is
possible to mix relative and absolute pointer events. A simple example of
that would be keyboard emulated mouse (which only makes sense as relative
events) on a absolute-mouse target like X.

 What have we do with GII. Something like that collecting:
 pmove1 abs
 pbutton
 pmove2 abs
 will do
 (pmove1.x +pmove2.x)/2 and the same for y.

??? What ?

I'll sketch how a LibGGI mouse handling routine for a system that expects to
work with absolute coordinates is intended to look like:

{
  static int mousex,mousey;
  ...

  ggiEventPoll(vis, emKey|emPointer, NULL);
  events = ggiEventsQueued(vis, emKey|emPointer);   

  while (events--) {
ggiEventRead(vis, event, emKey|emPointer);

switch(event.any.type) {
  case evPtrButtonPress:
switch(event.pbutton.button) {
  case GII_PBUTTON_FIRST:
do_something_as_appropriate(mousex,mousey);
break;
  case GII_PBUTTON_SECOND:
...
}
break;
  case evPtrButtonRelease:
... if needed ...
break;
  case evPtrAbsolute:
mousex = event.pmove.x;
mousey = event.pmove.y;
break;
  case evPtrRelative:
mousex += event.pmove.x;
mousey += event.pmove.y;
break;
}
/* Constrain mouse in any case */
if (mousex  0) mousex = 0;
if (mousey  0) mousey = 0;
if (mousex  xmax) mousex = xmax;
if (mousey  ymax) mousey = ymax;

  } /* while */
}

As you can see, this nicely symmetriyes the cases of abs and rel events.
Basically the same can be done for apps that expect relative events, though
those might get trouble on absolute input data when trying to "keep turning
left" or similar.

 Was it good? It is no good, at least because gii client software is not
 right place to do it. 

To do what ? (pmove1.x +pmove2.x)/2 ? There is no reasonable place to do
such a calculation at all. To make sense at all, you would have to make a 
weighted mean based on the time between the individual event's timestamps.
There is no assumption of something like a linear motion between points
between move events, and for sure no assumption, that the click happens in
the middle of that.

The expected behaviour is, that the above used mousex,mousey variables
express the correct position of the pointer, when a click comes in.

If the mouse was moved between the last move and the click, the driver is
expected to send another move and then the click to correctly position the
pointer before transmitting the click.

 Why do I need to keep every pmove message until get
 pbutton and pmove again? That is not pretty at least.

You don't. See above. In case that delivers incorrect results, we have a bug
in a driver or backend and need to fix the driver or flame the backend
authors.

 I understand  that it is my task to determinate correct click place in case
 of relative move messages and I do. But I really hope I will be able to
 avoid mouse cursor software emulation(what I have done because of no choice)
 and to forget about relative messages for pointing device like mouse  in the
 future when GGI will take care about hardware cursor.

GGI will never take away the information you get from the input device.
While we may provide a method to place a hardware sprite on the display,
thus allowing to easily make up a mouse pointer, this will not influence 
the pointer data sent from the input device.

 I repeat ones more I am discussing only about the case when cursor 
 generation is not my task.

I still do not get what cursor generation has to do with input handling.

There are some applications that would be pretty unhappy, if we converted
all input to absolute pointer events. Guess why the X target has the
relmouse mode ...

 In the depth My question was why after calling  poll(I call it with 0 time 
 delay)  the queued function  shows only one message we have inside of 
 queue but actually there are many (inside of some internal buffers). 

If that is the case, this is a bug and should be fixed.

 I think poll function really poll only one message for each message type 
 per one call, does not it?

No. It should check and queue all attached inputs, and all inputs should
read their sources until they are drained.

 It seems a strange for me behavior like that I expected that after Poll funk
 Queued will report all messages from internal buffers.

Yes. This is the intended behaviour.

However it could well be, that it is not correctly implemented in all
targets. If you could send some code that clearly shows the problem together
with the 

Re: GII event system

1999-10-21 Thread Marcus Sundberg

Andreas Beck wrote:
  In the depth My question was why after calling  poll(I call it with 0 time
  delay)  the queued function  shows only one message we have inside of
  queue but actually there are many (inside of some internal buffers).
 
 If that is the case, this is a bug and should be fixed.
 
  I think poll function really poll only one message for each message type
  per one call, does not it?
 
 No. It should check and queue all attached inputs, and all inputs should
 read their sources until they are drained.

Well, this is only a problem for broken or really strange apps, but
I think we should still provide a way around it:

Let gq be the number of events queued in LibGII and kq be the number
of events queued in the kernel.
Initial state: gq = 0, kq = 3
giiEventPoll() is called == fetches all events == gq = 3; kq = 0;
giiEventRead() is called, but only twice == gq = 1; kq = 0;
Now the user moves the mouse arround == gq = 1; kq = 5;
giiEventPoll() is called == as gq  0 no events are fetched from kq
into gq. This is 100% correct due to performance reasons, BUT:
When giiEventsQueued() is called and returns the number of events in
the queue you get 1 allthough there are more events that could be
read.

My suggestion is that we add a new function
int giiQueuedAfterPoll(struct gii_input *inp, gii_event_mask mask);
which will first poll all relevant input sources, regardless of the
number of events queued, and then return the number of events available.

When I think of it we should definitely add this function, because
it will allow the following common code:

struct timeval tv = { 0, 0};
if (giiEventPoll(inp, mask, tv)) {
n = giiEventsQueued(inp, mask);
while (n--) {
giiEventRead(inp, ev, mask);
process_event(%ev);
}
}

to be replaced with:

n = giiQueuedAfterPoll(inp, mask);
while (n--) {
giiEventRead(inp, ev, mask);
process_event(%ev);
}

Unless there are any objections or suggestions for a better name
I'll add this function to LibGII (and it's companion in LibGGI).

//Marcus
-- 
---+
Marcus Sundberg| http://www.stacken.kth.se/~mackan/
 Royal Institute of Technology |   Phone: +46 707 295404
   Stockholm, Sweden   |   E-Mail: [EMAIL PROTECTED]



RE: GII event system

1999-10-21 Thread Dmitry Semenov

Hi
Ok,
1. Anyway that is no so big problem if you do not want to keep space data
together with buttons.
As I got from you message you can guaranty last pmove message(s) contains
right data for the determination of  pointer position in the time of
clicking. It's more than enough. By the way my code is looks like the same
of yours except I avoid of calling 3rd party libraries directly and I use
own wrappers. My experience showed me that code for really good system has
to be not depended from any other library(thats funny when I see MFC
programmers who made software(and own brain) absolutely mot portable). I
make semi-embedded software like navigational systems, marine simulators.
Ask me how many libraries graphics libraries and input system I changed for
the last 10 years? A lot of. Know I can just make one more wrapper over
existing libraries and keep my other code just untouchable.

Absent of space data and click data made me a little confused because GGI is
the first library I have seen making this dividing :)

2. Event generation has not so many to do with cursor generation. But If GGI
library do not provide cursor monitoring and generation of it the GGI users
have to do this job manually. IMHO it will be nice for many users of really
nice GGI, if GGI will work together with GII to provide mouse cursor
monitoring when GGI will get hardware cursor access.

3. Marcus already gave some explanation for the Poll. Thanks.  May be letter
it will good to show my code as one more gui development system using GGI.

Best regards, Dmitry

-Original Message-
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]]
Sent: Friday, October 22, 1999 3:05 AM
To: [EMAIL PROTECTED]
Subject: Re: GII event system



Hi !

 1. Mouse is a human input device, as well as others pointing device.
 Practically buttons are related to mouse position and usual human expects
 reasonable button action right in place where he has clicked it.

Yes. This however does not mean, that the driver producing the "clicks" has
to know anything about the driver producing the moves.

This is why the moves and clicks are separate. Please note, that it is
possible to mix relative and absolute pointer events. A simple example of
that would be keyboard emulated mouse (which only makes sense as relative
events) on a absolute-mouse target like X.

 What have we do with GII. Something like that collecting:
 pmove1 abs
 pbutton
 pmove2 abs
 will do
 (pmove1.x +pmove2.x)/2 and the same for y.

??? What ?

I'll sketch how a LibGGI mouse handling routine for a system that expects to
work with absolute coordinates is intended to look like:

{
  static int mousex,mousey;
  ...

  ggiEventPoll(vis, emKey|emPointer, NULL);
  events = ggiEventsQueued(vis, emKey|emPointer);

  while (events--) {
ggiEventRead(vis, event, emKey|emPointer);

switch(event.any.type) {
  case evPtrButtonPress:
switch(event.pbutton.button) {
  case GII_PBUTTON_FIRST:
do_something_as_appropriate(mousex,mousey);
break;
  case GII_PBUTTON_SECOND:
...
}
break;
  case evPtrButtonRelease:
... if needed ...
break;
  case evPtrAbsolute:
mousex = event.pmove.x;
mousey = event.pmove.y;
break;
  case evPtrRelative:
mousex += event.pmove.x;
mousey += event.pmove.y;
break;
}
/* Constrain mouse in any case */
if (mousex  0) mousex = 0;
if (mousey  0) mousey = 0;
if (mousex  xmax) mousex = xmax;
if (mousey  ymax) mousey = ymax;

  } /* while */
}

As you can see, this nicely symmetriyes the cases of abs and rel events.
Basically the same can be done for apps that expect relative events, though
those might get trouble on absolute input data when trying to "keep turning
left" or similar.

 Was it good? It is no good, at least because gii client software is not
 right place to do it.

To do what ? (pmove1.x +pmove2.x)/2 ? There is no reasonable place to do
such a calculation at all. To make sense at all, you would have to make a
weighted mean based on the time between the individual event's timestamps.
There is no assumption of something like a linear motion between points
between move events, and for sure no assumption, that the click happens in
the middle of that.

The expected behaviour is, that the above used mousex,mousey variables
express the correct position of the pointer, when a click comes in.

If the mouse was moved between the last move and the click, the driver is
expected to send another move and then the click to correctly position the
pointer before transmitting the click.

 Why do I need to keep every pmove message until get
 pbutton and pmove again? That is not pretty at least.

You don't. See above. In case that delivers incorrect results, we have a bug
in a driver or backend and need to fix the driver or flame the backend
authors.

 I understand  that it is my task to determinate

RE: GII event system

1999-10-21 Thread Dmitry Semenov

Dear Marcus

Well, this is only a problem for broken or really strange apps, but
I think we should still provide a way around it:

This is of semantic problem. IMHO When I  call something like Poll at first
and GetQueued I expect (very deep inside of my mind) to get all events
"already" buffered by an input library.  As I told it was not a problem. It
seemed strange to me behavior like that because it is different from
expected by me.

Of course software uses only GII buffering will never understand this
problem. But Any software uses own buffering immediately get it. You can ask
me why do I need to use own buffer? Let se some my explanation provided to
Andreas under topic 1.

Thanks
Dmitry

-Original Message-
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]]On Behalf Of Marcus
Sundberg
Sent: Friday, October 22, 1999 8:19 AM
To: [EMAIL PROTECTED]
Subject: Re: GII event system



Andreas Beck wrote:
  In the depth My question was why after calling  poll(I call it with 0
time
  delay)  the queued function  shows only one message we have inside of
  queue but actually there are many (inside of some internal buffers).

 If that is the case, this is a bug and should be fixed.

  I think poll function really poll only one message for each message type
  per one call, does not it?

 No. It should check and queue all attached inputs, and all inputs should
 read their sources until they are drained.

Well, this is only a problem for broken or really strange apps, but
I think we should still provide a way around it:

Let gq be the number of events queued in LibGII and kq be the number
of events queued in the kernel.
Initial state: gq = 0, kq = 3
giiEventPoll() is called == fetches all events == gq = 3; kq = 0;
giiEventRead() is called, but only twice == gq = 1; kq = 0;
Now the user moves the mouse arround == gq = 1; kq = 5;
giiEventPoll() is called == as gq  0 no events are fetched from kq
into gq. This is 100% correct due to performance reasons, BUT:
When giiEventsQueued() is called and returns the number of events in
the queue you get 1 allthough there are more events that could be
read.

My suggestion is that we add a new function
int giiQueuedAfterPoll(struct gii_input *inp, gii_event_mask mask);
which will first poll all relevant input sources, regardless of the
number of events queued, and then return the number of events available.

When I think of it we should definitely add this function, because
it will allow the following common code:

struct timeval tv = { 0, 0};
if (giiEventPoll(inp, mask, tv)) {
n = giiEventsQueued(inp, mask);
while (n--) {
giiEventRead(inp, ev, mask);
process_event(%ev);
}
}

to be replaced with:

n = giiQueuedAfterPoll(inp, mask);
while (n--) {
giiEventRead(inp, ev, mask);
process_event(%ev);
}

Unless there are any objections or suggestions for a better name
I'll add this function to LibGII (and it's companion in LibGGI).

//Marcus
--
---+
Marcus Sundberg| http://www.stacken.kth.se/~mackan/
 Royal Institute of Technology |   Phone: +46 707 295404
   Stockholm, Sweden   |   E-Mail: [EMAIL PROTECTED]