haskellx11

How to listen for window closing in X11 code?


I'm still struggling with Haskell's X11 binding. Now, I want to detect the event of user closing the window. My best attempt so far:

import Graphics.X11.Xlib
import Graphics.X11.Xlib.Extras
import Control.Concurrent (threadDelay)
import Data.Bits    

main :: IO ()
main = do
 dpy <- openDisplay ""
 let dflt = defaultScreen dpy
     border = blackPixel dpy dflt
     background = whitePixel dpy dflt
 rootw <- rootWindow dpy dflt
 win <- createSimpleWindow dpy rootw 0 0 300 200 1 border background
 setTextProperty dpy win "Hello World" wM_NAME
 mapWindow dpy win
 moveWindow dpy win 0 0
 selectInput dpy win (structureNotifyMask .|. exposureMask)
 updateWin dpy win

updateWin :: Display -> Window -> IO ()
updateWin dpy win = do
  sync dpy True
  allocaXEvent $ \e -> do
    nextEvent dpy e
    ev <- getEvent e
    putStrLn $ eventName ev
  threadDelay (1000000)
  updateWin dpy win

But instead of getting the event, I get the following output:

ConfigureNotify
XIO:  fatal IO error 11 (Resource temporarily unavailable) on X server ":0.0"
      after 26 requests (25 known processed) with 5 events remaining.

What is causing this? What would be the right way to deal with it?


Solution

  • You need to watch ClientMessage events. There's no mask and no need to select them, just detect them and destroy the window. You also need to set WM_DELETE_WINDOW protocol. See e.g. here. Look for ClientMessage and WM_DELETE_WINDOW.

    At some point you will want to intercept other client messages apart from WM_DELETE_WINDOW. You will need to examine ClientMessage contents, not just the type, but for now it's not needed.