Re: assertion error "PRI(owl) >= priority" otp.c line 248

"Matthew D. Fuller" <[email protected]>
Newsgroups gmane.comp.window-managers.ctwm
Message-ID <[email protected]>
On Wed, Jul 10, 2019 at 10:28:15PM +0200 I heard the voice of
Rhialto, and lo! it spake thus:
> 
> [...] None of the patches attempting to fix these bugs.

Hm.  I read this as "none of the patches fixed these bugs", but now I
think it means "I didn't try it patched".  Is that right?

> #4  OtpRestackWindow (twm_win=twm_win@entry=0x74ba18b40c00)
>     at /mnt/vol1/rhialto/cvs/other/ctwm/bzr/trunk/otp.c:1626
> #5  0x000000000042f705 in SetFocus (tmp_win=0x74ba18b40800, tim=<optimized out>)
>     at /mnt/vol1/rhialto/cvs/other/ctwm/bzr/trunk/win_ops.c:168

is definitely a non-patched backtrace, since SetFocus() doesn't call
Restack with the patch.  I can reproduce that crash with xine and
roughly your steps (just mousing, not warp'ing, since that doesn't
quite work right in xnest/xephyr) with trunk, but with a patched tree
I can't.

Looking into it did turn up a few more cases; we need to make similar
changes in the FocusIn/FocusOut handlers.  As far as I can tell from
reading and thinking, anyway.  It's extremely hard to actually trigger
them, since with ClickToFocus we just call SetFocus(), and without we
get EnterNotify -> SetFocus.  So, I don't have a good before/after
test on it, but it should be right.

So, updated patch attached; as far as I can tell, this (and the
previous variant) should fix that crash, and if that's also your
historic one, should cleanse the world.


> Now I use the window ring to bring focus to W which comes up
> partially on top of P. Now I move the mouse directly into P. (To my
> surprise, W did not disappear behind a rising F).

Correct; in this case, F doesn't rise, only P does.  That's what I've
tentatively classified as a cosmetic-but-not-correctness bug.  Should
fix that in trunk, but if we can't use it to crash things I'd like to
skip for backporting, for minimalism's sake.


> Sometimes I notice another weirdness: despite using f.warpring to go
> to W, it does not always come to the top as it should (since F isn't
> focused any more, it has no reason to stay on top of W).

When F loses focus, it will drop back down to its base OTP layer,
which would be the same layer as W.  But it'll wind up as the _top_
thing on that layer, so it'll still be above W.



-- 
Matthew Fuller     (MF4839)   |  [email protected]
Systems/Network Administrator |  http://www.over-yonder.net/~fullermd/
           On the Internet, nobody can hear you scream.
otp_transients.patch (text/x-diff, 6.6 KB)
=== modified file 'event_handlers.c'
--- event_handlers.c	2018-11-19 06:15:52 +0000
+++ event_handlers.c	2019-07-11 02:13:12 +0000
@@ -367,35 +367,36 @@
 static void
 HandleFocusIn(void)
 {
-#ifdef EWMH
-	TwmWindow *old_focus = Scr->Focus;
-#endif
-
 	if(! Tmp_win->wmhints->input) {
 		return;
 	}
 	if(Scr->Focus == Tmp_win) {
 		return;
 	}
+
+#ifdef EWMH
+	// Handle focus-dependent re-stacking of what we're moving out of.
+	if(Scr->Focus && OtpIsFocusDependent(Scr->Focus)) {
+		OtpUnfocusWindow(Scr->Focus);
+		// NULL's Scr->Focus
+	}
+#endif
+
 	if(Tmp_win->AutoSqueeze && Tmp_win->squeezed) {
 		AutoSqueeze(Tmp_win);
 	}
 	SetFocusVisualAttributes(Tmp_win, true);
 
+#ifdef EWMH
+	// Handle focus-dependent re-stacking of what we're moving in to.
+	if(Tmp_win && OtpIsFocusDependent(Tmp_win)) {
+		OtpFocusWindow(Tmp_win);
+		// Sets Scr->Focus
+	}
+#endif
+
+	// Redundant in EWMH case
 	Scr->Focus = Tmp_win;
-
-#ifdef EWMH
-	/*
-	 * Some EWMH flags may affect stacking, so after we change
-	 * Scr->Focus...
-	 */
-	if(old_focus && OtpIsFocusDependent(old_focus)) {
-		OtpRestackWindow(old_focus);
-	}
-	if(Tmp_win && OtpIsFocusDependent(Tmp_win)) {
-		OtpRestackWindow(Tmp_win);
-	}
-#endif
 }
 
 
@@ -413,18 +414,20 @@
 	}
 	SetFocusVisualAttributes(Tmp_win, false);
 
-	Scr->Focus = NULL;
-
 #ifdef EWMH
 	/*
 	 * X-ref HandleFocusIn() comment.  FocusOut is only leaving a window,
 	 * not entering a new one, so there's only one we may need to
 	 * restack.
 	 */
-	if(Tmp_win && OtpIsFocusDependent(Tmp_win)) {
-		OtpRestackWindow(Tmp_win);
+	if(Scr->Focus && OtpIsFocusDependent(Scr->Focus)) {
+		OtpUnfocusWindow(Scr->Focus);
+		// NULL's Scr->Focus
 	}
 #endif
+
+	// Redundant in EWMH case
+	Scr->Focus = NULL;
 }
 
 

=== modified file 'otp.c'
--- otp.c	2018-08-19 22:50:13 +0000
+++ otp.c	2019-07-07 04:44:45 +0000
@@ -1579,6 +1579,99 @@
 }
 
 
+
+/**
+ * Focus/unfocus backend.  This is used on windows whose stacking is
+ * focus-dependent (e.g., EWMH fullscreen), to move them and their
+ * transients around.  For these windows, getting/losing focus is
+ * practically the same as a f.setpriority, except it's on the calculated
+ * rather than the base parts.  And it's hard to re-use our existing
+ * functions to do it because we have to move Scr->Focus before the main
+ * window changes, but then it's too late to see where all the transients
+ * were.
+ *
+ * There are a number of unpleasant assumptions in here relating to where
+ * the transients are, and IWBNI we could be smarter and quicker about
+ * dealing with them.  But this gets us past the simple to cause
+ * assertion failures, anyway...
+ */
+static void
+OtpFocusWindowBE(TwmWindow *twm_win, int oldprio)
+{
+	OtpWinList *owl = twm_win->otp;
+
+	// This one comes off the list, and goes back in its new place.
+	RemoveOwl(owl);
+	InsertOwl(owl, Above);
+
+	// Now root around for any transients of it, and
+	// nudge them into the new location.  The whole Above/Below thing is
+	// kinda a heavy-handed guess, but...
+	//
+	// This is nearly a reimplementation of TryToMoveTransientsOfTo(),
+	// but the assumption that we can find the transients by starting
+	// from where the old priority was in the list turns out to be deeply
+	// broken.  So just walk the whole thing.  Which isn't ideal, but...
+	//
+	// XXX It should not be this freakin' hard to find a window's
+	// transients.  We should fix that more globally.
+	OtpWinList *trans = Scr->bottomOwl;
+	while((trans != NULL)) {
+		// Gotta pre-stash, since we're sometimes about to move trans.
+		OtpWinList *next = trans->above;
+
+		if((trans->type == WinWin)
+				&& isTransientOf(trans->twm_win, twm_win)) {
+			// Bounce this one
+			RemoveOwl(trans);
+			InsertOwl(trans, Above);
+		}
+
+		trans = next;
+	}
+
+	OtpCheckConsistency();
+}
+
+/**
+ * Unfocus a window.  This needs to know internals of OTP because of
+ * focus-dependent stacking of it and its transients.
+ */
+void
+OtpUnfocusWindow(TwmWindow *twm_win)
+{
+	// Stash where it currently appears to be.  We assume all its
+	// transients currently have the same effective priority.  See also
+	// TryToMoveTransientsOfTo() which makes the same assumption.  I'm
+	// not sure that's entirely warranted...
+	int oldprio = PRI(twm_win->otp);
+
+	// Now tell ourselves it's unfocused
+	assert(Scr->Focus == twm_win);
+	Scr->Focus = NULL;
+
+	// And do the work
+	OtpFocusWindowBE(twm_win, oldprio);
+}
+
+/**
+ * Focus a window.  This needs to know internals of OTP because of
+ * focus-dependent stacking of it and its transients.
+ */
+void
+OtpFocusWindow(TwmWindow *twm_win)
+{
+	// X-ref OtoUnfocusWindow() comments.
+	int oldprio = PRI(twm_win->otp);
+
+	assert(Scr->Focus != twm_win);
+	Scr->Focus = twm_win;
+
+	OtpFocusWindowBE(twm_win, oldprio);
+}
+
+
+
 /*
  * Calculating effective priority.  Take the base priority (what gets
  * set/altered by various OTP config and functions), and then tack on

=== modified file 'otp.h'
--- otp.h	2017-06-01 15:51:31 +0000
+++ otp.h	2019-07-07 04:42:48 +0000
@@ -61,6 +61,9 @@
 void OtpStashAflagsFirstTime(TwmWindow *twm_win);
 void OtpRestackWindow(TwmWindow *twm_win);
 
+void OtpUnfocusWindow(TwmWindow *twm_win);
+void OtpFocusWindow(TwmWindow *twm_win);
+
 /* functions to manage the preferences. The second arg specifies icon prefs */
 void OtpScrInitData(ScreenInfo *);
 name_list **OtpScrSwitchingL(ScreenInfo *, WinType);

=== modified file 'win_ops.c'
--- win_ops.c	2018-11-18 21:09:02 +0000
+++ win_ops.c	2019-07-07 04:42:48 +0000
@@ -129,9 +129,6 @@
 {
 	Window w = (tmp_win ? tmp_win->w : PointerRoot);
 	bool f_iconmgr = false;
-#ifdef EWMH
-	TwmWindow *old_focus = Scr->Focus;
-#endif
 
 	if(Scr->Focus && (Scr->Focus->isiconmgr)) {
 		f_iconmgr = true;
@@ -153,24 +150,34 @@
 			AutoSqueeze(Scr->Focus);
 		}
 		SetFocusVisualAttributes(Scr->Focus, false);
+#ifdef EWMH
+		// Priority may change when focus does
+		if(OtpIsFocusDependent(Scr->Focus)) {
+			OtpUnfocusWindow(Scr->Focus);
+			// That Scr->Focus = NULL's internally for us, but we don't
+			// care, since we're about to reset it if we need to.
+		}
+#endif
 	}
-	if(tmp_win)    {
+
+	if(tmp_win) {
 		if(tmp_win->AutoSqueeze && tmp_win->squeezed) {
 			AutoSqueeze(tmp_win);
 		}
 		SetFocusVisualAttributes(tmp_win, true);
+#ifdef EWMH
+		// Priority may change when focus does
+		if(OtpIsFocusDependent(tmp_win)) {
+			OtpFocusWindow(tmp_win);
+			// Pre-sets Scr->Focus
+		}
+#endif
 	}
+
+	// in the EWMH cases, this was already done.
 	Scr->Focus = tmp_win;
 
-#ifdef EWMH
-	/* Priority may change when focus does */
-	if(old_focus && OtpIsFocusDependent(old_focus)) {
-		OtpRestackWindow(old_focus);
-	}
-	if(tmp_win && OtpIsFocusDependent(tmp_win)) {
-		OtpRestackWindow(tmp_win);
-	}
-#endif
+	return;
 }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.