Linux下使用Haskell获取前台窗口标题的等效方法(对比getForegroundWindow)
Great question! On Linux, window management is tied to your display server—most commonly X11 (the traditional standard) or Wayland (the modern replacement). The approach varies between the two, but there are solid non-FFI Haskell solutions for both using existing, well-maintained libraries.
X11 (Most Common Desktop Environments)
The x11 Haskell library provides pure-Haskell bindings to the X11 protocol, so you won’t need to write any manual FFI code. Here’s a working example:
First, add this dependency to your Cabal file:
build-depends: base >= 4.14 && < 5, x11 >= 1.9
Then the code to fetch the foreground window title:
import Graphics.X11.Xlib import Graphics.X11.Xlib.Extras getForegroundWindowTitle :: IO (Maybe String) getForegroundWindowTitle = do -- Connect to the default display dpy <- openDisplay "" rootWin <- defaultRootWindow dpy -- Get the currently focused (foreground) window (_, _, activeWin) <- getInputFocus dpy if activeWin == none then return Nothing -- No active window found else do -- Fetch the window's WM_NAME property (the title) rawTitle <- getWindowProperty8 dpy wM_NAME activeWin closeDisplay dpy -- Convert the raw byte data to a string return $ fmap (map toEnum) rawTitle
How it works:
- We open a connection to the X11 display server.
getInputFocusretrieves the window that currently has user input focus.getWindowProperty8fetches theWM_NAMEproperty (the standard X11 window title) as raw bytes, which we convert to a HaskellString.
Wayland (Modern Desktops like GNOME, KDE Plasma)
Wayland has a more decentralized ecosystem, but the gtk3 Haskell library offers a cross-display-server solution—it automatically adapts to X11 or Wayland without extra work. Again, this uses pure-Haskell bindings, no manual FFI.
Add this dependency to your Cabal file:
build-depends: base >= 4.14 && < 5, gtk3 >= 0.15
Here’s the code:
import Graphics.UI.Gtk getForegroundWindowTitleGTK :: IO (Maybe String) getForegroundWindowTitleGTK = do -- Initialize GTK (handles X11/Wayland setup automatically) initGUI -- Get the default screen (represents the display) maybeScreen <- screenGetDefault case maybeScreen of Nothing -> return Nothing Just screen -> do -- Get the active window on the screen maybeWindow <- screenGetActiveWindow screen case maybeWindow of Nothing -> return Nothing Just window -> do -- Fetch the window title title <- windowGetTitle window -- Clean up GTK resources mainQuit return title
Why this works:
GTK abstracts away the display server details. When running on Wayland, it uses the Wayland protocol under the hood; on X11, it falls back to X11 calls. You get a single codebase that works across both environments.
Notes
- If you’re targeting a specific Wayland compositor (like Sway), there might be compositor-specific libraries, but the GTK approach is the most portable.
- All the libraries mentioned (
x11,gtk3) are maintained and available on Hackage—no manual FFI required, as the bindings are already implemented in Haskell.
内容的提问来源于stack exchange,提问作者Răzvan Flavius Panda

