[GRASS5] hunting KDE/Xdriver redraw problem

Hi all,

currently Glynn and me are hunting a KDE/Xdriver problem related to the new
auto-redraw feature of Xdriver. Perhaps someone here has a hint for us...

If displaying a raster map and one or more vector maps, now resize the GRASS
monitor with a mouse, sometimes the vector maps disappear (so auto-redraw
doesn't work properly). The raster map is mostly there. This only appears on
KDE while Xdriver runs well on GNOME windows manager.

Difference between KDE and GNOME:
- KDE immediately redraws window contents when resizing
- GNOME waits until the mouse button is released (only shows
   a moving frame without contents, then redraws contents after
   window got settled)

The KDE way leads to problems. Adding a sleep(1) before redrawing helps
a bit but isn't perfect. Any other ideas? Could we catch the
mouse-button-release event and then redraw?

And: The problem only seems to appear, when resizing, while the redraw
is ongoing (means: two resizes quickly following each other). Perhaps
the redraw order is confused: vector first, then raster which would make
the vectors invisible?

Out of ideas for this,

Markus

----------------------------------------
If you want to unsubscribe from GRASS Development Team mailing list write to:
minordomo@geog.uni-hannover.de with
subject 'unsubscribe grass5'

On Tue, May 15, 2001 at 10:42:11PM +0100, Markus Neteler wrote:

Hi all,

currently Glynn and me are hunting a KDE/Xdriver problem related to the new
auto-redraw feature of Xdriver. Perhaps someone here has a hint for us...

If displaying a raster map and one or more vector maps, now resize the GRASS
monitor with a mouse, sometimes the vector maps disappear (so auto-redraw
doesn't work properly). The raster map is mostly there. This only appears on
KDE while Xdriver runs well on GNOME windows manager.
Difference between KDE and GNOME:
- KDE immediately redraws window contents when resizing
- GNOME waits until the mouse button is released (only shows
   a moving frame without contents, then redraws contents after
   window got settled)

The KDE way leads to problems. Adding a sleep(1) before redrawing helps
a bit but isn't perfect. Any other ideas? Could we catch the
mouse-button-release event and then redraw?

And: The problem only seems to appear, when resizing, while the redraw
is ongoing (means: two resizes quickly following each other). Perhaps
the redraw order is confused: vector first, then raster which would make
the vectors invisible?

I don't remember if I committed some changes I was working on regarding
processing Xevents, but the scenario is like:

If the window manager uses a rubber-band box for moving/resizing
windows, then it only generates one Expose event. If the window manager
uses opaque moving/resizing it is likely to queue up a whole bunch of
Expose events. Ahh, I see that should be handled...

Now, on the pad thing, what I see is at the end of handleResizeEvent()
there are two forks() and one waitpid(). Inside the inner fork is a
loop that shells out the items from PAD. So, if I'm understanding
correctly, the second fork() returns in the parent which then does
exit(0) whereby the waitpid() returns and the function finishes. The
inner forked process is meanwhile trying to shell out the PAD items, but
if another resize event comes in while the shelled commands are pending,
then a second go around of this occurs. However in the second go
around, some pad items never get redrawn (and hence added to the PAD
again). If you add a third resize while the second is running, you
really start to lose pad items. I just tested this and indeed I lose
the vector if I do three resizes (where there's one large raster and one
vector originally). So we have a race going on (go speed racer!).

I don't see any easy solution. Maybe that's why someone way back when
decided a resize event would clear the screen and the pad contents...

Hmm, what if there was a way to handle the resize without deleting the
pad contents? I don't know if this would work (probably not): In
theory, when a drawing command is shelled out on the resize, a new pad
item should be added that is identical to the old pad item. So, what if
adding a pad item first checked if it matched an existing item. If so,
it just increments a counter for that item. Periodically (say, in
do_events()) we look at the pad list to see if all of the counts are the
same. If they aren't, then some commands were lost and need to be
recreated. Hmm, no I guess you'd never lose commands in that
scenario. They'd just end up drawn all weird and the server would never
know.

Hmm, maybe having a "saved" pad and a "current" pad? I'll stop now :wink:

--
Eric G. Miller <egm2@jps.net>

----------------------------------------
If you want to unsubscribe from GRASS Development Team mailing list write to:
minordomo@geog.uni-hannover.de with
subject 'unsubscribe grass5'

Eric G. Miller wrote:

> currently Glynn and me are hunting a KDE/Xdriver problem related to the new
> auto-redraw feature of Xdriver. Perhaps someone here has a hint for us...
>
> If displaying a raster map and one or more vector maps, now resize the GRASS
> monitor with a mouse, sometimes the vector maps disappear (so auto-redraw
> doesn't work properly). The raster map is mostly there. This only appears on
> KDE while Xdriver runs well on GNOME windows manager.
> Difference between KDE and GNOME:
> - KDE immediately redraws window contents when resizing
> - GNOME waits until the mouse button is released (only shows
> a moving frame without contents, then redraws contents after
> window got settled)
>
> The KDE way leads to problems. Adding a sleep(1) before redrawing helps
> a bit but isn't perfect. Any other ideas? Could we catch the
> mouse-button-release event and then redraw?
>
> And: The problem only seems to appear, when resizing, while the redraw
> is ongoing (means: two resizes quickly following each other). Perhaps
> the redraw order is confused: vector first, then raster which would make
> the vectors invisible?

I don't remember if I committed some changes I was working on regarding
processing Xevents, but the scenario is like:

If the window manager uses a rubber-band box for moving/resizing
windows, then it only generates one Expose event. If the window manager
uses opaque moving/resizing it is likely to queue up a whole bunch of
Expose events. Ahh, I see that should be handled...

Do you mean ConfigureNotify?

Now, on the pad thing, what I see is at the end of handleResizeEvent()
there are two forks() and one waitpid(). Inside the inner fork is a
loop that shells out the items from PAD. So, if I'm understanding
correctly, the second fork() returns in the parent which then does
exit(0) whereby the waitpid() returns and the function finishes.

Actually, it's the short-lived child of the first fork() that is
reaped by waitpid; the parent process has to get back to event
processing otherwise you get deadlock.

The
inner forked process is meanwhile trying to shell out the PAD items, but
if another resize event comes in while the shelled commands are pending,
then a second go around of this occurs. However in the second go
around, some pad items never get redrawn (and hence added to the PAD
again). If you add a third resize while the second is running, you
really start to lose pad items. I just tested this and indeed I lose
the vector if I do three resizes (where there's one large raster and one
vector originally). So we have a race going on (go speed racer!).

I'm pretty sure that this is it; resize events won't be handled while
a client is connected, but they will be handled between clients.

I don't see any easy solution. Maybe that's why someone way back when
decided a resize event would clear the screen and the pad contents...

Hmm, what if there was a way to handle the resize without deleting the
pad contents? I don't know if this would work (probably not): In
theory, when a drawing command is shelled out on the resize, a new pad
item should be added that is identical to the old pad item. So, what if
adding a pad item first checked if it matched an existing item. If so,
it just increments a counter for that item. Periodically (say, in
do_events()) we look at the pad list to see if all of the counts are the
same. If they aren't, then some commands were lost and need to be
recreated. Hmm, no I guess you'd never lose commands in that
scenario. They'd just end up drawn all weird and the server would never
know.

Hmm, maybe having a "saved" pad and a "current" pad? I'll stop now :wink:

I think that XDRIVER will have to do proper process management. The
existing code is really just proof-of-concept.

The first draft only did a single fork(), which left the child
processes as zombies. The double-fork was a quick hack to get around
this (now, by the time the grandchild dies, its parent is long gone,
so it will get reaped by init).

This is the "fire-and-forget" approach, but it clearly isn't going to
work. The main process needs to keep track of the processes which are
spawned for redraw, and not spawn a new process while a previous
process is still active.

Also, it would ideally only accept connections from the redraw
commands whilst a redraw operation was in progress. However, this
would require the platform to support getsockopt(SO_PEERCRED).
Otherwise, there would be problems if a user resized the window whilst
running a script containing GRASS display commands.

--
Glynn Clements <glynn.clements@virgin.net>

----------------------------------------
If you want to unsubscribe from GRASS Development Team mailing list write to:
minordomo@geog.uni-hannover.de with
subject 'unsubscribe grass5'

On Wed, May 16, 2001 at 04:59:35AM +0100, Glynn Clements wrote:

Eric G. Miller wrote:

[snip]

> If the window manager uses a rubber-band box for moving/resizing
> windows, then it only generates one Expose event. If the window manager
> uses opaque moving/resizing it is likely to queue up a whole bunch of
> Expose events. Ahh, I see that should be handled...

Do you mean ConfigureNotify?

Yep, used wrong term...

> Now, on the pad thing, what I see is at the end of handleResizeEvent()
> there are two forks() and one waitpid(). Inside the inner fork is a
> loop that shells out the items from PAD. So, if I'm understanding
> correctly, the second fork() returns in the parent which then does
> exit(0) whereby the waitpid() returns and the function finishes.

Actually, it's the short-lived child of the first fork() that is
reaped by waitpid; the parent process has to get back to event
processing otherwise you get deadlock.

We're both saying the same thing here... parent of second fork is child
of first...

I think that XDRIVER will have to do proper process management. The
existing code is really just proof-of-concept.

What do you mean? Do you have some idea how the XDRIVER could possibly
manage the behavior of the external programs that instigate the drawing
operations?

I was thinking some kind of "semaphore" like mechanism might work.
Maybe the first child "acquires" a lock (or waits) and the second child
"releases" it when it's done. No, that doesn't work either, because the
command list would've already been built but would be missing items.
Hmm, unless if it can't get the "lock" it sets a flag which do_events()
would check again later? Sorry, I'm just brainstorming a little here...

--
Eric G. Miller <egm2@jps.net>

----------------------------------------
If you want to unsubscribe from GRASS Development Team mailing list write to:
minordomo@geog.uni-hannover.de with
subject 'unsubscribe grass5'

Eric G. Miller wrote:

> I think that XDRIVER will have to do proper process management. The
> existing code is really just proof-of-concept.

What do you mean? Do you have some idea how the XDRIVER could possibly
manage the behavior of the external programs that instigate the drawing
operations?

It can keep track of whether they are still running.

At present, XDRIVER does a double fork() so that it can forget all
about the long-lived redraw process; it only has to wait for the
short-lived intermediate process (to reap it, so that it doesn't
become a zombie).

What I'm suggesting is to revert to a single fork, so that the redraw
process is a child of the main process. The parent would periodically
use waitpid() with the WNOHANG flag to check whether the child has
finished yet.

This would allow it to inhibit spawning another redraw process before
the previous one had completed.

The other part of my previous suggestion, namely restricting
connections to redraw commands while the redraw was in operation,
turns out to be a bit more complex than I had initially allowed for.

The actual clients will be children of the redraw process, and hence
grandchildren of the main process. There isn't any straightforward way
for the main process to recognise its grandchildren (recognising a
child is easy; it's pid matches the return value from fork()).

The simplest approach which I can see would be for the child process
to spawn the individual redraw commands with fork() and exec(), so
that it obtains their pids, and then pass these up to the parent
through a pipe.

This is starting to get messy, and it's of no use if the OS doesn't
support getsockopt(SO_PEERCREDS). And it's only necessary if we are
concerned about other clients trying to connect to XDRIVER whilst a
redraw is in progress.

--
Glynn Clements <glynn.clements@virgin.net>

----------------------------------------
If you want to unsubscribe from GRASS Development Team mailing list write to:
minordomo@geog.uni-hannover.de with
subject 'unsubscribe grass5'