I have been using a video player recently that uses full-screen windows,
the kind that get promoted all the way to the top as long as they have
focus.

I have also seen lots of the asserts from $SUBJECT recently, while I was
interacting with such a window.

I think I finally found out what's wrong, while running ctwm from a
debugger.

First, the stack trace (transcribed by hand since I didn't run the
debugger in an xterm, of course). Most recent call at the bottom.

HandleEnterNotify()     event_handlers.c line 3301
SetFocus()              win_ops.c line 168
OtpRestackWindow()      otp.c line 1578
OtpCheckConsistency()   otp.c line 200
OtpCheckConsistencyVS() otp.c line 248
assert()

The code in SetFocus() around the call site looks like

   (do stuff with SetFocusVisualAttributes() and AutoSqueeze())

163         Scr->Focus = tmp_win;
164 
165 #ifdef EWMH
166         /* Priority may change when focus does */
167         if(old_focus && OtpIsFocusDependent(old_focus)) {
168                 OtpRestackWindow(old_focus);
169         }
170         if(tmp_win && OtpIsFocusDependent(tmp_win)) {
171                 OtpRestackWindow(tmp_win);
172         }
173 #endif
174 }

and otp.c:

1571 void
1572 OtpRestackWindow(TwmWindow *twm_win)
1573 {
1574         OtpWinList *owl = twm_win->otp;
1575 
1576         RemoveOwl(owl);
1577         InsertOwl(owl, Above);
1578         OtpCheckConsistency();
1579 }
1

The first call to OtpRestackWindow() would eventually call the failing
assert(PRI(owl) >= priority) in OtpCheckConsistency() but after it has
already fixed its target.

Now PRI here looks innocent, but in reality it is defined as 

    #define PRI(owl) OwlEffectivePriority(owl)

In other words, it calls a function that dynamically determines window
priority, possibly depending on which window has focus.

But which window that is, is just changing. Suddenly there may be one or
two windows in the stacking order which are in the wrong place. When we
check consistency after adjusting the first candidate (old_focus), the
second candidate (tmp_win) may still be wrongly stacked, causing the
assertion failure.

Now I'm trying to convince myself that the following code change is
necessary and sufficient:

163 
164 #ifdef EWMH
165     /*
166      * Priority may change when focus does: do PRI calculation
167      * on old_focus and tmp_win while it doesn't have focus.
168      */
169     Scr->Focus = NULL;
170 
171     if(old_focus && OtpIsFocusDependent(old_focus)) {
172         OtpRestackWindow(old_focus);
173     }
174 
175     Scr->Focus = tmp_win;
176 
177     if(tmp_win && OtpIsFocusDependent(tmp_win)) {
178         OtpRestackWindow(tmp_win);
179     }
180 #else
181     Scr->Focus = tmp_win;
182 #endif

Does anybody has ideas about that?

I'm running with this now, and I'll see if I have more of these
problems.

-Olaf.
-- 
___ Olaf 'Rhialto' Seibert  -- "What good is a Ring of Power
\X/ rhialto/at/falu.nl      -- if you're unable...to Speak." - Agent Elrond

Attachment: signature.asc
Description: PGP signature

Reply via email to