'GTK: How do I grab keyboard input for a dialog/splash window, so that keyinput works out of window region?

I noticed that when my mouse is out of the dialog area, the keyboard input stops working.

This is detrimental since I want this small app to grab keyboard, so that I could handle it through keyboard without having to move my mouse.

I tried: windowSetKeepAbove, windowSetSkipPagerHint, windowSetSkipTaskbarHint, and windowPresentWithTime. I still could not focus in the window. None of these seem to work.

Also tried Seat.grab function, it gave me GDK_GRAB_NOT_VIEWABLE. But I am running this after calling showAll on the main window. Why is it not viewable?

I am so confused now. Any help would be appreciated.

EDIT: It is written in gi-gtk binding of haskell, but I don't think the language would be relevant - it is pretty much 1-1 binding to the gtk library itself. (E.g. windowSetTypeHint corresponds toGtk.Window.set_type_hint)

Here is the close-to-minimal reproducible example. (I guess things like windowSetPosition could have culled out, but it should not affect much. onWidgetKeyPressEvent is to hook into key press event)

{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE LambdaCase #-}

module Main where

import Control.Monad
import Data.Foldable
import Data.Text qualified as T
import GI.Gdk qualified as Gdk
import GI.Gio.Objects qualified as Gio
import GI.Gtk qualified as Gtk
import System.Exit

main :: IO ()
main = do
  -- Does not care crashing here
  Just app <- Gtk.applicationNew (Just $ T.pack "test.program") []
  Gio.onApplicationActivate app (activating app)
  status <- Gio.applicationRun app Nothing
  when (status /= 0) $ exitWith (ExitFailure $ fromIntegral status)
  where
    activating :: Gtk.Application -> IO ()
    activating app = do
      window <- Gtk.applicationWindowNew app >>= Gtk.toWindow
      Gtk.windowSetTitle window (T.pack "Test Program")
      Gtk.windowSetDefaultSize window 560 140
      Gtk.windowSetTypeHint window Gdk.WindowTypeHintDialog
      Gtk.windowSetPosition window Gtk.WindowPositionCenterAlways
      Gtk.windowSetKeepAbove window True
      Gtk.windowSetSkipPagerHint window True
      Gtk.windowSetSkipTaskbarHint window True
      Gtk.onWidgetKeyPressEvent window $
        Gdk.getEventKeyKeyval >=> \case
          Gdk.KEY_Escape -> True <$ Gtk.windowClose window
          _ -> pure False

      Gtk.widgetShowAll window

      screen <- Gtk.windowGetScreen window
      gdkWins <- Gdk.screenGetToplevelWindows screen
      seat <- Gdk.screenGetDisplay screen >>= Gdk.displayGetDefaultSeat
      event <- Gtk.getCurrentEvent
      putStrLn "Finding window"
      filterM (fmap (Gdk.WindowStateAbove `elem`) . Gdk.windowGetState) gdkWins
        >>= traverse_
          ( \win -> do
              putStrLn "Window found"
              Gdk.windowShow win
              stat <- Gdk.seatGrab seat win [Gdk.SeatCapabilitiesAll] True (Nothing @Gdk.Cursor) event Nothing
              print stat
          )

      pure ()

I know, horrible hack, but I don't know other ways to get Gdk.Window. Searched through the gtk library, could not find the way to take Gdk.Window out of Gtk.Window.

Still, it turns out that this hack have found the gdk window.

Running with e.g. cabal run prints:

Finding window
Window found
GrabStatusNotViewable

So I got: GDK_GRAB_NOT_VIEWABLE somehow. It turns out that later on when e.g. focus event is fired, grab works normally. But I want to grab the mouse/keyboard earlier.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source