Shell – How to detect whether the terminal has focus in the GUI from a shell script

focusshellshell-scriptterminal-emulator

Problem/Goal description

Ideally, I would like a good way of detecting from a shell script whether or not the window has focus. By a "good" way, I mean some way which requires minimal steps and preferably does not require sifting through each open window blindly to find mine based on title.

The purpose is for controlling notifications in many different scripts — so I'm just looking for a general solution that can apply to any and all of them.

What I've come up with so far is roundabout and hacky — it is as follows:

  1. Set my title to something unique or mechanically relevant (in my model, it is my PTS path or, more robustly, a UUID). Hope desperately that this title is not overridden by something.

  2. Get a list of all open windows, by title.

  3. Iterate through list to identify my window by matching it to the title element. (Note the possibility of errors here if another window happens to have that same title element.)

  4. Detect whether said window has focus or not.

It should be noted that I do not want to implement this, and will only do it as a last resort. So what I'm asking for here is something that is not this.

Compromises

This solution is obviously terrible, so I'd like to know if there is anything remotely better, in any way. I would prefer something portable, elegant, and perfect, but I recognize the potential need to compromise. By better I mean any of the following:

  1. A solution that only works with a specific terminal emulator, e.g. by having the terminal emulator itself set an environment variable allowing the script to detect which window it is in.

  2. A solution that does not require setting the title, and instead uses some other invisible marker in window state that is accessible and detectable from a shell script attached to said window.

  3. Recusing up the parent process ladder to find the parent terminal emulator PID, and working from there (Note that a solution that works by recusing up the the process tree to detect the parent process that started the script will only work if the script is running locally, so this solution is incomplete but still good!)

Conditions

I was getting questions about exactly what conditions my preferred solution is supposed to function under, and the answer is as many as possible. But at minimum, I would like something that works:

  1. In a single-tab terminal session running natively (default scenario).

  2. In terminal multiplexers like tmux. (Portability between different terminal multiplexers is preferred but really not required.)

Extras that I'd really appreciate (in order of importance), include:

  1. Ability to function on remote connections over telnet and SSH.

  2. Ability to distinguish which tab is open in a multi-tab terminal session.


Summary

I want a good way of finding what terminal emulator window my shell script is attached to, so that I can detect whether it has focus or not.

Note that I'm already aware of the mechanics of how to to iterate through open windows, and how to detect whether they have focus or not and what titles they have. I am aware of the existance of xdotool and xprop and this question is not about the basic mechanics of those tools (unless there is some hidden black magic feature I don't know about that side-steps the intrinsic hackiness of my current solution.)

The reason I don't want to that is because it's terrible. Any other solution that accomplishes the same thing?

Best Answer

if [ "$(xdotool getwindowfocus)" -eq "$WINDOWID" ]; then
   echo I have the focus
fi

This will not work inside screen/tmux if they were started from somewhere else and just attached in the current window.

Related Question