Bash – What Linux command will tell me where a window is in terms of the Z-axis compared to other windows

bashgnomelinuxshell-scriptx11

I'm looking to give some Linux command a window id as obtained by xprop or wmctrl or similar and have something tell me where in the "z-wards" stacking order that window currently is.

For example, if window C is visually behind window B (as in B is clipping C, if they overlap each other), and window A is in front of both them, some command would tell me something like 0 for window A, 1 for B, and 2 for C. Perhaps the "front" number is bigger than the "back" number; that's unimportant to me.

Best Answer

What you're looking for is not a window property but a side-effect of the way X displays windows. Looking for details on XRaiseWindow leads to XRestackWindows and seeing that it reorders a list of the windows (which given that it changes the order in which the X server displays them, controls the apparent stacking order).

The xwininfo command can return a list of child-windows for any window, and a tree of windows. That's presented in the same order (it uses XQueryTree, whose description says that it lists the children in current stacking order), you could (with some effort) make a script that analyzed that and relate it to the windows that you care about (not all windows are interesting).

Window-ids aren't that useful, but you can use those as a parameter to xprop and find the window-titles that correspond. Not all windows have titles, and there are some quirks to account for along the way.

(The solution is neither bash- or linux-specific, and predates both of those).

Someone alluded to EWMH's _NET_CLIENT_LIST:

_NET_CLIENT_LIST, WINDOW[]/32
_NET_CLIENT_LIST_STACKING, WINDOW[]/32

These arrays contain all X Windows managed by the Window Manager. _NET_CLIENT_LIST has initial mapping order, starting with the oldest window. _NET_CLIENT_LIST_STACKING has bottom-to-top stacking order. These properties SHOULD be set and updated by the Window Manager.

In a quick check, that illustrates the quirks to explore.

$ xprop -root
_NET_ACTIVE_WINDOW(WINDOW): window id # 0x400023
_NET_CLIENT_LIST(WINDOW): window id # 0x400023, 0xc00018, 0xa0000a
_NET_CLIENT_LIST_STACKING(WINDOW): window id # 0xa0000a, 0xc00018, 0x400023, 0xc00018
_NET_SUPPORTED(ATOM) = _NET_ACTIVE_WINDOW, _NET_CLIENT_LIST, _NET_CLIENT_LIST_STACKING, _NET_CLOSE_WINDOW, _NET_SUPPORTED, _NET_SUPPORTING_WM_CHECK, _NET_WM_ACTION_CLOSE, _NET_WM_ACTION_FULLSCREEN, _NET_WM_ACTION_MAXIMIZE_HORZ, _NET_WM_ACTION_MAXIMIZE_VERT, _NET_WM_ACTION_MINIMIZE, _NET_WM_ACTION_MOVE, _NET_WM_ACTION_RESIZE, _NET_WM_ACTION_SHADE, _NET_WM_ALLOWED_ACTIONS, _NET_WM_NAME, _NET_WM_STATE, _NET_WM_STATE_FULLSCREEN, _NET_WM_STATE_HIDDEN, _NET_WM_STATE_MAXIMIZED_HORZ, _NET_WM_STATE_MAXIMIZED_VERT, _NET_WM_STATE_MODAL, _NET_WM_STATE_SHADED, _NET_WM_STATE_SKIP_PAGER, _NET_WM_STATE_SKIP_TASKBAR, _NET_WM_STATE_STICKY, _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_COMBO, _NET_WM_WINDOW_TYPE_DESKTOP, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_WINDOW_TYPE_DND, _NET_WM_WINDOW_TYPE_DOCK, _NET_WM_WINDOW_TYPE_DROPDOWN_MENU, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_NORMAL, _NET_WM_WINDOW_TYPE_NOTIFICATION, _NET_WM_WINDOW_TYPE_POPUP_MENU, _NET_WM_WINDOW_TYPE_SPLASH, _NET_WM_WINDOW_TYPE_TOOLBAR, _NET_WM_WINDOW_TYPE_TOOLTIP, _NET_WM_WINDOW_TYPE_UTILITY
_NET_SUPPORTING_WM_CHECK(WINDOW): window id # 0x800001
_XKB_RULES_NAMES(STRING) = "base", "empty", "empty", "", ""
_NATIVE_SCREEN_ORIGIN(INTEGER) = 0, 22

I have 3 windows, and the stacking lists one twice. Also, which window is the parent of the visible clients can differ according to the window manager in use.

And of course, there are still window managers which don't follow EWMH. Even within EWMH, you have to appreciate that "SHOULD". It doesn't guarantee success.

For comparison, of course:

$ xwininfo -root -children

xwininfo: Window id: 0x111 (the root window) (has no name)

  Root window id: 0x111 (the root window) (has no name)
  Parent window id: 0x0 (none)
     7 children:
     0x80000a (has no name): ()  806x853+0+1  +0+1
     0x40007d (has no name): ()  225x401+183+45  +183+45
     0x40007c (has no name): ()  295x464+101+45  +101+45
     0x800010 (has no name): ()  164x186+1113+5  +1113+5
     0x80000d (has no name): ()  246x159+950+0  +950+0
     0x800001 (has no name): ()  1x1+0+0  +0+0
     0x600001 (has no name): ()  1x1+0+0  +0+0
Related Question