Who's got the focus?
May 12, 2010 10:53 PM   Subscribe

On MacOS, I can say osascript -e 'set myapp to name of (info for (path to frontmost application))' to print the name of the program that currently has focus, in a way that's useful for shell scripting. How can I get the same information in a graphical session on Linux?
posted by fantabulous timewaster to Computers & Internet (21 answers total) 5 users marked this as a favorite
Response by poster: Advice for any distro, any window manager would be helpful, but I find myself most frequently in GNOME on either RHEL or Ubuntu.
posted by fantabulous timewaster at 10:56 PM on May 12, 2010

Best answer: With a reasonably functional window manager, you should be able to use the following incantation:
xprop -id $(xprop -root | grep '_NET_ACTIVE_WINDOW(WINDOW)' | cut -d' '  -f5)
That gets you a bunch of useful information from which you can parse whatever you need, such as the window's title, class, or process ID. (WM_ICON_NAME, WM_CLASS and _NET_WM_PID, respectively.)
posted by teraflop at 11:16 PM on May 12, 2010

Best answer: Based on this, I made this one-liner:
xprop -id `xprop -root | grep "_NET_ACTIVE_WINDOW(WINDOW)" | awk '{print $5}'` | grep "WM_CLASS(STRING)"

That returns something like: WM_CLASS(STRING) = "gnome-terminal", "Gnome-terminal"

To further refine and get just the executable name, use the following:

xprop -id `xprop -root | grep "_NET_ACTIVE_WINDOW(WINDOW)" | awk '{print $5}'` | grep "WM_CLASS(STRING)" | sed -e 's/.*= "\([^"]*\)".*/\1/'

Now, getting that into a variable in a script is a bit tricky. Honestly, to avoid the quoting nightmare, I would recommend making a helper script with just that function, say, topprog.sh:

xprop -id `xprop -root | grep "_NET_ACTIVE_WINDOW(WINDOW)" | awk '{print $5}'` | grep "WM_CLASS(STRING)" | sed -e 's/.*= "\([^"]*\)".*/\1/'

Then in the script where you need the program, just do:

topprog=`. topprog.sh`

I doubt this whole thing is the cleanest way to do things, but it's the best I can come up with right now.
posted by kmz at 11:21 PM on May 12, 2010

Oh yeah, if you're doing this in something other than shell script, obviously you can use the regex parsing power of whatever language you're using to do things a bit more cleanly based on the first command I had up there.
posted by kmz at 11:23 PM on May 12, 2010

xdotool can tell you the active window and xwininfo can tell you about it.

The debian packages are xdotool and x11-utils respectively. This is the geekiest AskMeFi answer ever.
posted by fydfyd at 11:32 PM on May 12, 2010

I take my "geekiest" claim, kmz ;)
posted by fydfyd at 11:34 PM on May 12, 2010

Best answer: $ topprog=$(xprop -id $(xprop -root | awk '/_NET_ACTIVE_WINDOW\(WINDOW\)/{print $5}') | awk '/WM_CLASS\(STRING\)/{gsub(/^"|",$/,"",$3); print $3}');

$ echo $topprog

Only if the CLASS is simply the command name, sometimes it isn't.

$ cmdline=$(ps h -oargs -p $(xprop -id $(xprop -root | awk '/_NET_ACTIVE_WINDOW\(WINDOW\)/{print $5}') | awk '/WM_PID\(CARDINAL\)/{gsub(/^"|",$/,"",$3); print $3}'));

$ echo $cmdline
xterm -e /bin/bash

Gets you the command line used to start the program in the window. So it depends on what you want. (change the '-oargs' to '-ofname' to get just the base command name).

Oddly enough, I was using xdotool and wmctrl earlier tonight to control Hulu Desktop Player on my desktop from my laptop so I can watch it on the big TV screen without futzing around with VNC.
posted by zengargoyle at 1:12 AM on May 13, 2010

Best answer: I find xwit the easiest command line program for this sort of thing (xwit can report most info a WM can get from your windows, and perform most actions a WM could perform as well).

xwit -current -print | cut -d ' ' -f7-
(not the - after the 7 - this is necessary for windows with spaces in the names)

Will print the info you want. I don't think any standard program will get you the info in a simpler way than that.

other examples of nifty stuff you can do with xwit:

xwit -current -move 0 0
(moves the current window to the upper left of your screen)
xwit -warp 100 100
(zaps the mouse pointer to the specified point)
xwit -select -name "the one I clicked on"
(renames the next window you click on)
posted by idiopath at 1:20 AM on May 13, 2010

oh, oops you wanted the command name:

xwit -current -print -property WM_COMMAND | cut -d"'" -f2

posted by idiopath at 1:57 AM on May 13, 2010

And now I see that not every window sets WM_COMMAND

xwit -print|cut -d: -f1|xargs -I '}' xprop -id '}'|grep PID|cut -d' ' -f3|xargs -I '}' ps -p '}' -o comm=

not nearly as elegant, but still the simplest one so far that gives the required info
posted by idiopath at 2:22 AM on May 13, 2010

cleaned up to use subshells instead of xargs:

ps -p $(xprop -id $(xwit -print | cut -d: -f1)| grep PID| cut -d' ' -f 3) -o comm=
posted by idiopath at 2:38 AM on May 13, 2010

Don't like xwit, -property seems to only work on certain properties and not others. :( But you can save some more typing if we're playing golf.

$ xwit -print|cut -d: -f1|xargs xprop -id|grep PID|cut -d' ' -f3|xargs ps -ocomm= -p
posted by zengargoyle at 3:13 AM on May 13, 2010

to avoid the quoting nightmare

This is why you should never use `backtick command substitution` and always use $(parenthetical command substitution).
posted by grouse at 7:50 AM on May 13, 2010

OK, if we are playing golf, here is my 77:

ps -p $(xprop -id $(xwit -print|cut -d: -f1)|grep PID|cut -d' ' -f 3) -o comm=

grouse, your last is 81
posted by idiopath at 10:40 AM on May 13, 2010

Any suggestions on how to get the name of the program running in an xterm? Assuming it wasn't started with -e? I don't think xprop or xwininfo will do it. Is there a way to find child processes if you have the pid of the xterm?
posted by valadil at 12:07 PM on May 13, 2010

Best answer: valadil:
ps --ppid $PID_OF_TERM -o comm=
will show executable names for all processes running in that xterm
posted by idiopath at 12:18 PM on May 13, 2010 [1 favorite]

also I have my golf score down to 73:

ps -p $(xprop -id `xwit -print|cut -d: -f1`|grep PI|cut -d' ' -f3) o args=

also if you are not playing golf and want a bit of corner case protection / future proofing you probably want to grep for _NET_WM_PID instead of "PI"

No other current X property contains "PI", though, so I think it is valid for golfing.
posted by idiopath at 12:30 PM on May 13, 2010


Guess no PI for me. Shaved off 5 strokes.

ps -p $(xprop -id `xwit -pr|cut -d: -f1`|grep PID|cut -d\ -f3) o cmd=
posted by zengargoyle at 1:49 PM on May 13, 2010 [1 favorite]

zengargoyle: awesome (though you needed a pre tag (or an   after 'cut -d\ ') - the lack of which made your working 68 char play look like a non working 67 char)
posted by idiopath at 1:57 PM on May 13, 2010

(make that 69 vs. 70, - backslash escape tripped me up)
posted by idiopath at 2:02 PM on May 13, 2010

Response by poster: Awesome, thanks guys. I think my favorite is
xprop -root | awk '/^_NET_ACTIVE_WINDOW\(WINDOW\)/ {print $5}' | xargs xprop -id | awk '/^WM_CLASS\(STRING\)/ {gsub(/^"|",$/,"",$3); print $3}'
I needed to start the patterns with ^ since otherwise the pattern sometimes showed up in the cut buffer. xwit looks nice but it looks like it's not universally available.

vladil/idiopath, I like the idea of finding all the process running in a particular terminal, too. Unfortunately ps --ppid happens not to work on the Mac side of things. An alternative is lsof $(tty).
posted by fantabulous timewaster at 4:06 PM on May 13, 2010

« Older You got a real purty neck, boy.   |   Are my employers paying us correctly? Newer »
This thread is closed to new comments.