...making Linux just a little more fun!
By Jim Dennis, Jason Creighton, Chris G, Karl-Heinz, and... (meet the Gang) ... the Editors of Linux Gazette... and You!
From Kapil Hari Paranjape
Answered By: Thomas Adam
This reply is a followup to http://linuxgazette.net/issue114/tag/4.html but is more specific to X11 itself. -- Thomas Adam
But I'm often confused as to what "the other half does". For example, I am now using "fvwm" (thanks to Thomas' suggestions on how to ratpoison-ify it). I know that "fvwm" traps some keys and uses them for its own nefarious purposes.
[Thomas] Key-bindings as set by the user for the window manager are always greedy with respect to the window manager. So for instance, in FVWM, one might have a key-binding such as:
Key X A 3 Function FvwmTitleRxvt
Now, of course, it might be the case that windowskey+X is an actual binding to an application I have running, but it's tough -- the WM has precedence in that binding as I have it defined there.
What happens when it is used with GNOME? Who is gets the first option to look at the keys or other input events? GNOME or fvwm?
[Thomas] Always the window manager. Remember that GNOME is just a framework and a collection of utilities. If you wanted a hierarchy, a depiction such as the following is an accurate representation:
GNOME <--> window manager --> Application
Of course, the integration aspect of GNOME <--> Window Manager how depends on EWMH. I've talked about these in the past, but I might as well summarise them here for clarity. EWMHs are extensions from window states which were first outlined by the ICCCM manual [1]. Unfortunately, the ICCCM is rather old, but it does provide a fantastic framework on which to build a WM, and it is still very relevant today. When KDE and GNOME were developing into the bloatware we see today, one thing they both did were to extend the ICCCM to define their own window states. Of course, compatability became a nightmare in such instances, and so these were cleaned up and standardised by the freedesktop people [2]. They're only windowing hints at the end of the day for things such as 'Working areas', 'Number of Desktops', and such like.
You may ask why the WM has precedence over an application, when it is the job of the WM to manage applications. The answer is simple. Key-bindings are the job of the Xserver. So actually the propogation looks like this:
Xserver -> Window Manager -> Application.
When you get your window manager to bind your keys for you, what's actually happening is that the window manager will map the requests itself, so it keeps a record of WM-specific keybindings. When the WM grabs the Xserver when it maps an application or a key-binding it then checks to see (via the Xserver) whether that keybinding is WM-defined or not. If it is then it will act appropriately, else it will pass it down to the underlying application, or do nothing.
A similar question could be raised regarding how window positioning and decorations are decided/executed. Perhaps the overall GNOME/GTK theme decides and passes on the info to the window manager which actually executes these?
[Thomas] Not quite. GTK itself is window manager agnostic. When you apply a GTK-theme, all that happens is that any currently running GTK apps are redrawn by the Xserver. There is no interaction with the window manager in anyway while this is happening.
Of course, GTK themes don't really allow for the stylation of title bars -- that's the job of the WM, and rightly so. You have to remember thatit's the job of the xserver to map the window which the WM then grabs and decorates as it sees fit. So the decoration could come in any form.
Window positioning is a separate entity in itself. When windows are mapped to the Xserver, the server will naturally map it to 0+0 which is top-left. The window manager already has one window that is top-level, and that is the root-window. This is the ultimate window from which everything else stems from, when windows are created. Consider the following Xlib snippet:
win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), xsh.x, xsh.y, xsh.width, xsh.height, bw, bd, bg);
I could easily spend hours talking about this line of Xlib alone, but I'll save you the gory details. Essentially, the point you should realise is that all windows created in this way [3] are always a child of the root-window. Why? Well, it's all about management. Once the Wm knows the top-level window, it knows how to stack windows as well as place hints on them. Of course, the WM is not allowed to change application-set windowing hints when the window is being mapped. Indeed, this is really where 'xprop(1)' comes in useful. This allows one to examine all of the window states as well as set them. There's also 'xwininfo(1)' for a more high-level view, although to be honest, I prefer FvwmIdent for such things.
Of course, with window hierarchies comes the notion of Transient windows. These are (by definition) short-lived windows, such as dialog boxes. They'll often have the the following hint set:
[n6tadam@station ~]$ xprop | grep -i trans WM_TRANSIENT_FOR(WINDOW): window id # 0x2a0002e
The window manager might well treat these differently -- indeed, FVWM does. Due to their short-lived nature, it's often not desireable to have all buttons on the titlebar, so FVWM might well not decorate transient windows in such a manner. Of course, one can change that with:
Style * DecorateTransient
Anyway, window positioning is managed by the window manager. The geometry of a window defines its position on screen, and hence its size. In the form:
widthx height+/- xorigin+/- yorigin
Note that the window geometry will often be with respect the actual window itself, and not the frame that surrounds it. In slight relation to that is a window gravity. There's 'Window Gravity' and 'Bit Gravity', and they specify for the window as a whole (including the borders) and the window contents how to react on window resizing.
Of course, as you have no doubt guessed, it is not quite as simple as -geometry. There is certain other hints that provide additional positioning. Take for instance Mozilla. That doesn't have a '-geometry' option because of they way it was designed. Instead that remembers its position (and hence window size) each time it is closed. The WM can be instructed to ignore or react to such things. As is the case with FVWM there's a hint called 'NoPPosition'. This instructs FVWM to place the window based on what/where it tells the WM to put it. Hence:
Style gecko NoPPosition
would be such an example [4]. There are instances though where a window will use PPosition hints as well as accept geometries. Notably, [X]emacs is such a beast and will set its PPosition to (0,0) each time, so overriding that is paramount for some. Again, geometry specifications take precedence over PPosition hints where they're supported.
A pointer to relevant sources of information would be greatly appreciated.
[Thomas] I hope this helps. I could rabbit on for ages about all of this, but I'd rather answer such things as they come up, as opposed to overloading you with tedious information. Unfortunately, information such as this is sparse, and represents my understanding through working with FVWM, and Xlib in general.
- http://tronche.com/gui/x/icccm
- http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html
- Of course, it doesn't have to be at the low-level such as Xlib. Often, languages have wrapper functions around XCreateSimpleWindow() which will automatically map a window to be a child of the root window.
- http://fvwm.lair.be/viewtopic.php?t=273
Dear Thomas,
Thanks for the detailed write-up. Any chance that this will one day become an article somewhere? (Hint! Hint!).
Great stuff.
This question was raised about a specific window flag. I've split it out from the above commentry to keep readability intact. -- Thomas Adam
[Thomas] Of course, as you have no doubt guessed, it is not quite as simple as -geometry. There is certain other hints that provide additional positioning. Take for instance Mozilla. That doesn't have a '-geometry' option because of they way it was designed. Instead that remembers its position (and hence window size) each time it is closed.
[Ben] Oh, how I wish it did. Not a big thing, but this has been a long-standing problem with Mozilla for me (both the Big Moz and now Firefox): Due to couple of info bars that I use (MailDooHicky and the Moaning Goat Meter),I like for my windows to span from the left edge of the screen to ~100px short of the right edge, and from ~30px down from the top to ~30px short of the bottom. Xterms are, of course, no problem - I've got "XTerm*VT100*geometry: 134x40+0+21" in my ~/.Xresources, and that takes care of it. Mozilla, well... I've got a little Java bookmarklet on the toolbar that makes it jump to the correct position whenever I find it too annoying. But it never remembers the position.
[Thomas] It does work, but it's dependant on how the window manager deals with such things. I have to say that some WMs are better than others in this regard. It has been many years since I used icewm for any serious use, but as far as I can recall, it doesn't allow for arbitrary commands to be run on a window.
[Ben]
Eh, well... for certain values of 'arbitrary'... kinda sorta. :) You can't (so far as I know, at least) run commands on a window once it's up. You can, however, assign initial properties to windows (actually, your discussion of all this stuff is what I needed to remind me of that - thanks!) by defining them in ~/.icewm/winoptions; in this case, what I needed was:
Gecko.Firefox-bin.geometry: 1212x722+0+23
This sets the initial position of the window to what I need, which is perfect.
[Thomas] I hate to err, draw comparisons.
[Ben] No you don't. C'mon, you love to tout the superiority of FVWM! (And why not? If it can do something better than everybody else, go for it. After all, it's not boasting if you can do it.)
[Thomas] In FVWM, doing what you're describing above can be achieved in two ways, the first is to use a function, as in:
DestroyFunc FuncStartMoveBrowser AddToFunc FuncStartMoveBrowser + I Exec exec $0 + I Wait $0 + I Next ($0) ResizeMove w+0 -100px 0 -30p
(I've most likely got the co-ordinates wrong, but that can be left as an exercise to the reader).
So the above will exec the first formal argument to the function ($0), wait for it to appear, and then will move and resize it to the said co-ordinates. You might invoke it thus:
FuncStartMoveBrowser mozilla
One would replace 'mozila' with whatever program was wanted. But there are limitations with that method. The first one is that it will only work when invoked from within a menu, or FvwmConsole, and won't work if one were to type in 'mozilla' from an Xterm. In such cases where this is more desirable, FvwmEvent can be used, as in:
DestroyModuleConfig FvwmEvent-Browser: * *FvwmEvent-Browser: Cmd Function *FvwmEvent-Browser: add_window FuncStartMoveBrowser
Which would set up an event for each window that was created, calling the function specified. The function as we have it defined needs modifying for use with FvwmEvent, as the window would have already been created, hence:
DestroyFunc FuncStartMoveBrowser AddToFunc FuncStartMoveBrowser + I All (CurrentDesk, AcceptsFocus, !Transient) ThisWindow ("gecko") ResizeMove w+0 -100px 0 -30p
I've used 'gecko' as that is the window class common to both Mozilla and Firefox.
You're probably wondering how this helps you, Ben. It doesn't, but there is an application which can move and resize windows which you could make use of, coupled with xwininfo(1). It's called 'xwit' and is just a wrapper program around some of the Xlib functions, so for example:
xwit -move x y -resize x y -names 'mozilla'
If you wanted to get specific, you could use xwininfo to fine tune things, matching by window ID, etc. Maybe a little crude, but it might help you.
[Ben] [laugh] Well... it's got this little problem built in...
ben@Fenrir:~$ xwininfo|grep 'Window id' xwininfo: Window id: 0xc00031 "Google Advanced Search - Mozilla Firefox"
Since Firefox changes its window name to whatever the site happens to be, I have to click the Firefox window in order to find out its window ID (which could then be used to do 'xwit' twiddling.) This is, shall we say, suboptimal for the task. I'd imagine there are other ways to hunt it down - 'xwininfo -all -root|grep Mozilla' comes to mind - but that gets a bit shaky. Anyway, you've avalanched some synapses for me, the appropriate brain cells fired, and All Is Now Well. Thanks!
[Thomas] No worries. You can probably get a fairly accurate result in making use of '-root' to xwininfo, so something like:
[n6tadam@station ~]$ xwininfo -root -all -tree | grep -m1 'Mozilla-bin' 0x282c250 "Gecko": ("Gecko" "Mozilla-bin") 200x200+0+0 +0+0
At least with it displayed in a tree form (and stopping at the first match), you can be fairly well assurred that you'll be matching the parent window.