Reparenting cleanup
- From: Timo Korvola iki fi
- To: sawfish-list gnome org
- Subject: Reparenting cleanup
- Date: Thu, 15 Feb 2007 23:04:04 +0200
Hello everybody.
I've been using Sawfish with KDE for some time now. Most things work
but the system tray has a lot of problems. One of these was that the
tray and Sawfish sometimes appeared to fight over a tray icon,
simultaneously trying to reparent it. So I set out to find when
Sawfish reparents windows. I found the details rather confusing. The
following patch is an attempt to clarify the behaviour: Windows are
framed at map_request, never at map_notify. They are reparented back
to the root at unmap_notify unless Sawfish detects that the unmapping
was caused by someone else - such as the system tray - reparenting the
window (this check I took from Fluxbox).
After these changes I do not see reparenting fights anymore. Although
improved, the system tray unfortunately remains quite unreliable:
sometimes icons just don't appear at all, occasionally (rarely) they
appear in the root window. Also, windows that are initially withdrawn,
then mapped by clicking a tray icon suffer from this bug:
<URL:http://bugzilla.gnome.org/show_bug.cgi?id=104928>. In addition
they appear alone in some kind of a bogus virtual desktop. Windows that
are initially mapped, then unmapped and mapped again by clicking the
tray icon twice work fine.
--
Timo Korvola <URL:http://www.iki.fi/tkorvola>
--- sawfish-1.3+cvs20061004/src/events.c.orig 2006-11-16 00:23:22.000000000 +0200
+++ sawfish-1.3+cvs20061004/src/events.c 2006-11-16 00:48:48.000000000 +0200
@@ -687,31 +687,40 @@
DEFSTRING (iconify_mod, "sawfish.wm.state.iconify");
Window id = ev->xmaprequest.window;
Lisp_Window *w = find_window_by_id (id);
+ int fresh = 0;
+
if (w == 0)
{
+ fresh = 1;
w = add_window (id);
- if (w == 0)
+ if (w == 0) {
+ fprintf (stderr, "warning: failed to allocate a window\n");
return;
-
- if (w->wmhints && w->wmhints->flags & StateHint
- && w->wmhints->initial_state == IconicState)
- {
- rep_call_lisp1 (module_symbol_value (rep_VAL (&iconify_mod),
- Qiconify_window), rep_VAL(w));
}
}
+
+ /* Reparent now and don't worry about it later. -- thk */
+ if (!w->reparented)
+ {
+ Fgrab_server ();
+ create_window_frame (w);
+ install_window_frame (w);
+ Fungrab_server ();
+ }
+
+ if (fresh && w->wmhints && w->wmhints->flags & StateHint
+ && w->wmhints->initial_state == IconicState)
+ {
+ rep_call_lisp1 (module_symbol_value (rep_VAL (&iconify_mod),
+ Qiconify_window), rep_VAL(w));
+ }
else
{
- if (!w->reparented)
- {
- Fgrab_server ();
- create_window_frame (w);
- install_window_frame (w);
- Fungrab_server ();
- }
w->mapped = TRUE;
- rep_call_lisp1 (module_symbol_value (rep_VAL (&iconify_mod),
- Quniconify_window), rep_VAL(w));
+ if (!fresh)
+ rep_call_lisp1 (module_symbol_value (rep_VAL (&iconify_mod),
+ Quniconify_window),
+ rep_VAL(w));
}
if (!w->client_unmapped)
@@ -736,13 +745,18 @@
if (ev->xreparent.parent != root_window
&& ev->xreparent.parent != w->frame)
{
- /* Not us doing the reparenting.. */
+ /* The window is no longer on our turf and we must not
+ reparent it to the root. -- thk */
+ w->reparented = FALSE;
+ XRemoveFromSaveSet (dpy, w->id);
+
+ /* Not us doing the reparenting. */
remove_window (w, FALSE, FALSE);
- XReparentWindow (dpy, ev->xreparent.window, ev->xreparent.parent,
- ev->xreparent.x, ev->xreparent.y);
}
Fcall_window_hook (Qreparent_notify_hook, rep_VAL(w), Qnil, Qnil);
}
+ /* What if someone else reparents windows to the root?
+ Shouldn't we adopt them? Does it ever happen? -- thk */
}
static void
@@ -757,6 +771,10 @@
{
/* arrgh, the window changed its override redirect status.. */
remove_window (w, FALSE, FALSE);
+#if 0
+ fprintf(stderr, "warning: I've had it with window %#lx\n",
+ (long)(w->id));
+#endif
}
else
{
@@ -765,11 +783,11 @@
w->attr.height = wa.height;
w->mapped = TRUE;
+ /* This should not happen. The window should have been
+ framed at the map request. -- thk */
if (w->frame == 0)
- create_window_frame (w);
- install_window_frame (w);
- if (w->visible)
- XMapWindow (dpy, w->frame);
+ fprintf(stderr, "warning: window %#1x has no frame\n",
+ (long)(w->id));
Fcall_window_hook (Qmap_notify_hook, rep_VAL(w), Qnil, Qnil);
}
}
@@ -782,6 +800,9 @@
if (w != 0 && ev->xunmap.window == w->id
&& (ev->xunmap.event == w->id || ev->xunmap.send_event))
{
+ int being_reparented = FALSE;
+ XEvent reparent_ev;
+
w->mapped = FALSE;
if (w->reparented)
{
@@ -790,11 +811,30 @@
XUnmapWindow (dpy, w->frame);
reset_frame_parts (w);
}
- /* Removing the frame reparents the client window back to
- the root. This means that we receive the next MapRequest
- for the window. */
- remove_window_frame (w);
- destroy_window_frame (w, FALSE);
+ /* Careful now. It is possible that the unmapping was
+ caused by someone else reparenting the window.
+ Removing the frame involves reparenting the window to
+ the root. Bad things may happen if we do that while
+ a different reparenting is in progress. -- thk */
+ being_reparented = XCheckTypedWindowEvent(dpy, w->id,
+ ReparentNotify,
+ &reparent_ev);
+ if (!being_reparented)
+ {
+ /* Removing the frame reparents the client window back to
+ the root. This means that we receive the next MapRequest
+ for the window.
+
+ It also means that if we die, the window stays
+ unmapped. This is correct for withdrawn windows
+ while iconic windows should be mapped, which
+ happens if they are in their frames and in the save
+ set. Iconic windows should therefore be kept
+ mapped: iconification should only unmap the
+ frame. -- thk */
+ remove_window_frame (w);
+ destroy_window_frame (w, FALSE);
+ }
}
Fcall_window_hook (Qunmap_notify_hook, rep_VAL(w), Qnil, Qnil);
@@ -802,7 +842,10 @@
/* Changed the window-handling model, don't let windows exist
while they're withdrawn */
- remove_window (w, FALSE, FALSE);
+ if (being_reparented)
+ reparent_notify(&reparent_ev);
+ else
+ remove_window (w, FALSE, FALSE);
}
}
--- sawfish-1.3+cvs20061004/src/windows.c.orig 2006-11-16 00:23:13.000000000 +0200
+++ sawfish-1.3+cvs20061004/src/windows.c 2006-11-16 00:45:23.000000000 +0200
@@ -351,8 +351,9 @@
if (queued_focus_id == w->frame)
queued_focus_id = w->id;
- if (!w->mapped)
- XRemoveFromSaveSet (dpy, w->id);
+ /* Now that the window is a child of the root it does not need
+ to be in the save set anymore. -- thk */
+ XRemoveFromSaveSet (dpy, w->id);
}
}
@@ -514,8 +515,9 @@
return w;
}
-/* Remove W from the managed windows. If DESTROYED is nil, then the
- window will be reparented back to the root window */
+/* Remove W from the managed windows. If DESTROYED is nil and
+ the window is currently reparented by us, it will be reparented back to
+ the root window */
void
remove_window (Lisp_Window *w, bool destroyed, bool from_error)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]