From 08a165df40acd60b261e141495e0244521c7b86c Mon Sep 17 00:00:00 2001 From: slotThe Date: Wed, 20 Jan 2021 11:25:26 +0100 Subject: [PATCH] XMonad.Prompt: Allow Pointer Events If this is not done, trying to select another window with the mouse when the prompt is up, the X server executes a pointer/keyboard grab until `allowEvents' is called; which it never is and so both remain frozen indefinitely. C.f.: - xmonad/xmonad/issues/116 - xmonad/xmonad-contrib/issues/445 --- XMonad/Prompt.hs | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/XMonad/Prompt.hs b/XMonad/Prompt.hs index 3beee729..43249a11 100644 --- a/XMonad/Prompt.hs +++ b/XMonad/Prompt.hs @@ -619,7 +619,8 @@ eventLoop handle stopAction = do [] -> do d <- gets dpy io $ allocaXEvent $ \e -> do - maskEvent d (exposureMask .|. keyPressMask) e + -- Also capture @buttonPressMask@, see Note [Allow ButtonEvents] + maskEvent d (exposureMask .|. keyPressMask .|. buttonPressMask) e ev <- getEvent e (ks,s) <- if ev_event_type ev == keyPress then lookupString $ asKeyEvent e @@ -635,14 +636,39 @@ eventLoop handle stopAction = do evDefaultStop :: XP Bool evDefaultStop = (||) <$> (gets modeDone) <*> (gets done) --- | Common patterns shared by all event handlers. Expose events can be --- triggered by switching virtual consoles. +-- | Common patterns shared by all event handlers. handleOther :: KeyStroke -> Event -> XP () handleOther _ (ExposeEvent {ev_window = w}) = do + -- Expose events can be triggered by switching virtual consoles. st <- get when (win st == w) updateWindows +handleOther _ (ButtonEvent {ev_event_type = t}) = do + -- See Note [Allow ButtonEvents] + when (t == buttonPress) $ do + d <- gets dpy + io $ allowEvents d replayPointer currentTime handleOther _ _ = return () +{- Note [Allow ButtonEvents] + +Some settings (like @clickJustFocuses = False@) set up the passive +pointer grabs that xmonad makes to intercept clicks to unfocused windows +with @pointer_mode = grabModeSync@ and @keyboard_mode = grabModeSync@. +This means that any click in an unfocused window leads to a +pointer/keyboard grab that freezes both devices until 'allowEvents' is +called. But "XMonad.Prompt" has its own X event loop, so 'allowEvents' +is never called and everything remains frozen indefinitely. + +This does not happen when the grabs are made with @grabModeAsync@, as +pointer events processing is not frozen and the grab only lasts as long +as the mouse button is pressed. + +Hence, in this situation we call 'allowEvents' in the prompts event loop +whenever a button event is received, releasing the pointer grab. In this +case, 'replayPointer' takes care of the fact that these events are not +merely discarded, but passed to the respective application window. +-} + -- | Prompt event handler for the main loop. Dispatches to input, completion -- and mode switching handlers. handleMain :: KeyStroke -> Event -> XP ()