[xmonad] X () with side effects

Brandon Allbery allbery.b at gmail.com
Mon Aug 15 00:05:52 CEST 2011

On Sun, Aug 14, 2011 at 17:03, Jochen Keil <jochen.keil at gmail.com> wrote:

> > It's because your function is doing stuff instead of listening for X
> > events.  If you want to go off and do something else, forkIO a thread
> I've already tried forkIO, xfork, seq, par, etc. all with more or less

seq and par won't do anything useful here (seq has nothing to do with
parallelism and par isn't designed for this kind of usage).  Also, xmonad
doesn't use OS threads, and it's just occurred to me that there's no way to
hook the X event loop into GHC's thread scheduler, so forkIO won't actually
be useful anyway.  :(

xfork spawns a subprocess, which would then need to send X events to the
main event loop which you would handle in the handleEventHook.  This is also
how an independent thread would need to communicate.

> the same result: the program's window will be mapped only after the
> function returns.

...this happens with forkIO as well?  I'm tempted to say you didn't use it
properly; "after the function returns" isn't one of the behaviors I'd expect
unless you're trying to synchronize with the thread as well.

> > for the something else.  If your something else requires communication
> > with X11, you'll need to think about rewriting around the event
> > handler instead.
> I can't see how to do this at the moment. Is this even possible? As far
> as I understand/stood the xmonad code it's all about grabbing events.

That's *why* event passing is how it should be solved.

As to the how:  sendEvent and the handleEventHook.

>        timeout <- io $ waitForEvent d 1000000

*sigh* This is a good way to make xmonad stop processing events.  You must
*not* do this if you expect xmonad to be usable while waiting.  (This is why
X.A.Submap doesn't try to handle timeouts.)

Instead, you need to have the event loop manage it.  Use ExtensibleState to
store the keymap state and start time; the handleEventHook recognizes a key,
checks the ExtensibleState to see if it's useful, and if so acts on it and
returns All False to prevent xmonad's default handler from also acting on
the key.  Acting on it may involve updating the state to point to a new
submap, or performing some xmonad action.  You should also forkIO a timeout
thread which invokes (delay) (see Control.Concurrent) and then sendEvent to
send a timeout event which is also processed by the handleEventHook.
 (Remember to clear the ExtensibleState as well as invoking releaseKeys.)

> -- this is oversimplistic:  you need to make sure the MyTimeoutEvent
> -- to the current vmap and not an earlier one, by storing some kind of id
in both.
> -- You can't simply pass the vmap because it's going to take a trip
through the X11
> -- server and there's no guarantee the same pointer comes back.
> handleEventHook (SendEvent {ev_type = e})
>     | e == MyTimeoutEvent = releaseKeys >> ES.put () >> return (All False)
> handleEventHook (KeyPress {ev_key = k}) = do
>   vmap <- ES.get -- state of vi keymap
>   -- keyDecision goes here, more or less
>   -- if you update the keymap, delete the
> -- the initial key binding then places the vi keymap in ES and spawns a
> -- thread, allowing the handleEventHook to do the rest.

brandon s allbery                                      allbery.b at gmail.com
wandering unix systems administrator (available)     (412) 475-9364 vm/sms
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/xmonad/attachments/20110814/917ccc8a/attachment.htm>

More information about the xmonad mailing list