32

From a bash script, is there some way to get the ID of the X window under the mouse pointer?

(edit) I need the process to be non-interactive.

Peter.O
  • 32,426
  • 28
  • 115
  • 163

9 Answers9

37

xdotool exposes the pointer location (xdotool getmouselocation), and recent versions (since 2.20110530.1) indicate which window is at that location as well. None of xwininfo, wmctrl or older versions of xdotool appear to have a way to match a window by a screen position where it's visible.

The underlying X library call is XQueryPointer (corresponding to a QueryPointer message). Here's a simple Python wrapper script around this call (using ctypes). Error checking largely omitted. Assumes you're using screen 0 (if you didn't know that displays could have more than one screen, ignore this).

#! /usr/bin/env python
import sys
from ctypes import *
Xlib = CDLL("libX11.so.6")
display = Xlib.XOpenDisplay(None)
if display == 0: sys.exit(2)
w = Xlib.XRootWindow(display, c_int(0))
(root_id, child_id) = (c_uint32(), c_uint32())
(root_x, root_y, win_x, win_y) = (c_int(), c_int(), c_int(), c_int())
mask = c_uint()
ret = Xlib.XQueryPointer(display, c_uint32(w), byref(root_id), byref(child_id),
                         byref(root_x), byref(root_y),
                         byref(win_x), byref(win_y), byref(mask))
if ret == 0: sys.exit(1)
print child_id.value

Usage example:

xwininfo -tree -id $(XQueryPointer)
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
  • 1
    Thanks Gilles: This is (almost) exactly what I need... It is ideal but for the fact that it returns a value of '0' for the desktop itself.. A non-zero window ID is returned (for the desktop) by the asynchronous `xdotool click 1` method mentioned in the comment to *Bruce Ediger's* answer.. The non-zero desktop ID is valid insomuch as it returns the appropriate image via `import -window $nonzeroID screen.png`.... Is there some simple tweak for the python script to return *that* value for the desktop? – Peter.O Jul 06 '11 at 13:48
  • @Gilles... Testing `$(XQueryPointer)` for `0`, and calling `xwininfo -root` for this condition resolves this quirk.. Thanks.. – Peter.O Jul 06 '11 at 14:34
  • @fred Untested because I'm not in front of a unix machine: try printing `root_id.value` if `child_id.value == 0`. – Gilles 'SO- stop being evil' Jul 06 '11 at 14:39
  • Yes, your mod works fine..   `if child_id.value == 0: print root_id.value`     `else: print child_id.value`  :) – Peter.O Jul 06 '11 at 15:23
  • `sed /x[0-9]\\++/q\;d <(xwininfo -tree -id $(XQueryPointer))` – F. Hauri - Give Up GitHub Feb 14 '15 at 22:19
  • ***WOW! xdotool actually does***. Please run @user82110 example `xdotool click 1|xwininfo|grep 'Window id:'` then copy the hex value. Later, execute `xdotool getactivewindow` and you will get THE SAME, but integer. Conversion is (0x2201c57)16 = (35658839)10 so you can't say it's not doing it. It's also cross-monitor compatible. You can get the window id of a vncserver inclusive and do not requires you to click anywhere. – m3nda May 25 '15 at 04:28
  • Seems the answers are pretty old. For the sake of a update :D – m3nda May 25 '15 at 04:34
  • @erm3nda I'm not sure what you're trying to say in your comment. `xdotool click 1` followed by `xdotool getactivewindow` does indirectly report the mouse cursor location if you have click-to-focus, but it changes the focus and sends a mouse event to the window (e.g. it might click a button). So this is not a solution to the problem here. – Gilles 'SO- stop being evil' May 25 '15 at 11:26
  • That was the @user82110 example. Not mine. I've posted an answer. Check it and welcome back if is not what you need. I'll try to solve. And please, check every command before get back to blame me :) – m3nda May 25 '15 at 23:29
25

The xwininfo command gives this kind of output, but you do have to click on the window you want info on:

% xwininfo
xwininfo: Please select the window about which you
          would like information by clicking the
          mouse in that window.

xwininfo: Window id: 0xa0000d "flask"

...

So doing: xwininfo | grep 'Window id:' might give you something you can parse the ID out of.

  • 1
    I need it to be non-interactive... – Peter.O Jul 06 '11 at 04:32
  • 1
    It can be made to be non-interactive by running it in the background `xwinfo |grep window id:' &`, and following it by `xdotool click 1`... but that runs the risk of the foreground `click` executing before the `xdotool` grabs the mouse. I'd rathen not use a nominal `sleep n, so although this answer is on-track, I'll wait a wihile to see if something more *inline* turns up... – Peter.O Jul 06 '11 at 05:39
11

try this, it uses only xdotool, but its version is at least "2.20110530.1"

xdotool getmouselocation --shell | grep WINDOW

to get the window id directly you can use this:

sedGetValue='s/.*=\(.*\)/\1/' # or more readable: sedGetValue='s".*=\(.*\)"\1"' # as / \ confuses me
windowId=`xdotool getmouselocation --shell 2>/dev/null |grep WINDOW |sed "$sedGetValue"`
echo $windowId
Aquarius Power
  • 4,099
  • 5
  • 38
  • 56
5

If you have access to python-xlib, here's a shorter and more pythonic equivalent to Gilles' answer:

from Xlib.display import Display

display = Display()
window = display.screen().root
result = window.query_pointer()

print(result.child.id)
1

xdotool is good enough to do so.

Run xdotool getactivewindow and you'll see the result (int) The window can be over ANY monitor. Just read where is located the x11 pointer waiting for a click :), and no matter if it's a remote window, a vncserver or the 3rd desktop of the cube desktop environment. Just works.

You can play it using sleep for better testing sleep 3; xdotool click 1+2; xdotool getactivewindow.

I've see that getwindowsfocus returns the same value than getactivewindow.

If you do the clicks manually you'll see the contextual menu, but click 1+2 fires both clicks at time clicking on the current mouse location and getting the desired id.

Try it :)

m3nda
  • 168
  • 1
  • 7
  • 1
    This gives the ID of the active window (wherever that **window** may be), regardless of whether or not that active window is under the mouse pointer. As per the wording of the question: "... find the X window ID under the mouse pointer ..." (wherever that **mouse** may be). – Peter.O May 25 '15 at 04:51
  • 1
    Thank you for correction, youre right. ***Updated***. I was mixing the concept of getmouselocation with activewindow, but anyway, xdotool is cool enough. – m3nda May 25 '15 at 05:25
1

I use: xdotool getmouselocation | sed "s/.*://"

For example, to minimize the window under mouse cursor:

xdotool windowminimize $(xdotool getmouselocation|sed "s/.*://")

rustyx
  • 287
  • 1
  • 9
0
xprop -root 2>/dev/null | sed -n '/^_NET_ACTIVE_WINDOW/ s/.* // p'
blueyed
  • 735
  • 1
  • 9
  • 14
  • 1
    This gives the ID of the active window instead of the window under the mouse pointer. – Peter.O Nov 24 '14 at 12:34
  • Oh, I was assuming sloppy focus (focus follows mouse) here. – blueyed Nov 24 '14 at 21:25
  • @blueyed Focus is on the active windows, and this windows does respond to KEYBOARD. Mouse is followed/tracked by X11 as it's server from it, and when you click a windows, x11 sets window-manager focus to clicked windows. Focus don't follow mouse really. You can check running `xdotool getwindowsfocus` from a console and moving mouse around. Value would be the same until you click mouse or interact keyboard (alt+tab, etc) – m3nda May 25 '15 at 05:39
0

I toyed around with the answer from Peter.O and came up with:

xdotool click 1|xwininfo|grep 'Window id:'
Ikem Krueger
  • 479
  • 5
  • 4
  • 1
    That sends a mouse click, so it would e.g. click a button where the mouse cursor is. It would incidentally report the window where the cursor is in if you use click to focus, but sending a click event is disruptive. – Gilles 'SO- stop being evil' May 25 '15 at 11:28
0

ArchWiki has a good answer to this:

activeWinLine=$(xprop -root | grep "_NET_ACTIVE_WINDOW(WINDOW)")
activeWinId=${activeWinLine:40}

Using sed you can do this in a single line, which is probably the most readable way to do it:

activeWin="$(xprop -root | sed -n 's/^_NET_ACTIVE_WINDOW(WINDOW): window id # //p')"

Note that xdotool was missing in my Debian minimal X11 while xprop was included (likewise sed of course).

If you don't want to fork sed nor grep you can do the text transformation it entirely in bash, which perhaps is a little bit more safe in case the output of xprop changes a bit:

activeWin="$(xprop -root)"
activeWin="${activeWin#*_NET_ACTIVE_WINDOW(WINDOW):}'
activeWin="${activeWin%%?_NET_*}'
activeWin="${activeWin##* }'

Anyway, it's still a strange way to archive such a simple task.

Tino
  • 1,112
  • 8
  • 11
  • 3
    This gives the ID of the active window instead of the window under the mouse pointer. – Peter.O Nov 24 '14 at 12:35
  • @Peter.O You are right this does return the active window. Sorry for the wrong answer, however with my tests it worked - probably because I had focus-follows-mouse on. – Tino May 29 '15 at 12:08