[xmonad] darcs patch: broadcastMessage now uses Operations.windows to update...

Andrea Rossato andrea.rossato at unibz.it
Thu Feb 21 11:36:51 EST 2008

On Thu, Feb 21, 2008 at 09:43:30AM -0500, David Roundy wrote:
> I think broadcastMessage needs reworking, and should be reworked somewhat
> along the lines of your sendMessageToWorkspace idea that you previously
> implemented (but in a buggy way).
> The trouble here is that if any of these doLayouts modify the windowset,
> I'm afraid we'll run into trouble as we continue sending the Message to the
> other workspaces, but passing those funcitons a W.Workspace that's obsolete
> (e.g. maybe its layout changed because of an action by a previous
> handleMessage).  This *may* not cause trouble, but I think it's safer to
> write
> sendMessageToWorkspaceWithoutNecessarilyRefreshing :: Message a => a -> WorkspaceId -> X ()
> (but ideally with a shorter name)
> and then
> broadcastMessage :: Message a => a -> X ()
> broadcastMessage a = withWindowSet $ \ws -> do
>     sendMessage a
>     mapM_ (sendMessageToWorkspaceWithoutNecessarilyRefreshing a)
>           (map W.tag $ (map W.workspace $ W.visible ws) ++ W.hidden ws)
> It seems like with this function, each workspace that exists will get the
> message, unless its WorkspaceId changes first.  It's possible that a
> workspace will get the message never, or more than once, if its WorkspaceId
> changes, but that's almost unavoidable.  But the key feature of this
> approach is:  if the state is changed by a handleMessage (including changes
> to layouts), then that change will not be lost... unless a layout both
> changes the windowset *and* returns a modified layout.
> But the key is that any loss of that sort must happen within a single
> sendMessageToWorkspaceWithoutNecessarilyRefreshing call (or in the
> sendMessage call).  So those two functions (each of which call a single
> handleMessage) are the only two that place a limit on what is "safe" for a
> handleMessage to do.  And with just a bit of care they can actually be
> pretty forgiving.  As you point out, a handleMessage that returns Nothing
> should be able to make *any* X calls, with the worst danger being the
> introduction of an infinite loop (a real danger, but also unavoidable).

I think I was not able to make myself entirely clear, so I'll
elaborate a bit more, also to give you the possibility to spot a
mistake in my reasoning. In the meanwhile I'll also try to answer to
some of the issues you rose.

The problem is not whether we can call 'sendMessage' or
'broadcastMessage' from within doLayout. We know that doLayout is
called within 'windows', and we cannot call anything calling 'windows'
inside 'windows'.

The real issue, I think, can be thus summarized:

1. why we are able to make *any* X call from within 'handleMessage' if
   we return Nothing?

2. what shall we do if 'handleMessage' returns Just a new layout?
   Shall we do the same for the current, the visible and the hidden

Let's start with 'broadcastMessage': it gets the windowset and
collects each workspace record (that is to say, the tag, the layout
and the stack of each workspace, the current, the visible and the
hidden ones).

'broadcastMessage' then uses the layout filed of the workspace record
to call 'handleMessage' with it. If 'handleMessage' returns Just a new
layout, this new layout is used to update the previously retrieved
workspace record, and this workspace record is used to update the
windowset component of the X state.

What happens if, in 'handleMessage', we call 'focus'? 

'focus' will call 'windows' to modify the stack of the workspace
record whose layout field is being used to run 'handleMessage'. After
that 'windows' will use that very layout field of that workspace
record to run doLayout and refresh the screen. 'doLayout' may return a
new layout and that field of the workspace record will be updated by

Now, all those changes, made within 'handleMessage' can be saved (and
are safe) if, *after* returning Nothing the windowset is *not*
modified anymore - it had been in 'windows' as we have seen.

And what is doing 'broadcastMessage' instead? If we return Nothing in
'handleMessage' the layout field of the *previously* retrieved
workspace record will be pushed back, even if it had been changed in
'handleMessage'. And the very *same* happens with the stack!
Everything we did in 'handleMessage' is overwritten with the *old*
workspace record.

And if we return Just? 'broadcastMessage' will just update the layout
field ('sendMessage', instead, would call 'windows' to run 'doLayout'
with the stack and the *new* layout - the right thing to do, I think).

This is why we cannot call 'focus' and return Just in 'handleMessage'.
If we did, the layout returned by 'doLayout' (called by 'windows'
called by 'focus' - see above) would be lost because overwritten by
the one returned by 'handleMessage'.

And now a question: if we return Just should we refresh the screen?
Definitely yes for the current and visible layouts. I think it should
be safe to call 'doLayout' also for hidden layouts.

Finally: keep in mind that the case we are really interested in, the
one in which we call 'focus' in 'handleMessage', is a case in which
'windows' is *not* called afterward. Which means that we are not going
to increase the number of screen refreshes. Not in this case at least.

I hope this clarifies a bit my understanding of the issue.


More information about the xmonad mailing list