How I select (terminal) windows from the keyboard in FVWM

February 11, 2012

As part of reorganizing my work desktop to deal with big screens, I decided that I wanted a way to select terminal windows by name from the keyboard, with some form of autocompletion for speed. The goal was to give me a faster way to get a particular terminal window than sweeping my mouse all the way to my taskbar for terminals and finding the specific window I wanted. FVWM doesn't have any native features for this, so I had to bolt something together for this out of pieces.

(To make life simple I decided to not do anything clever about several windows having the same name. If that happened and I picked the name, the system could pick whichever specific window it wanted.)

The most difficult bit is selecting among alternatives from the keyboard with some form of autocompletion. Fortunately I already had a general program that could do this: dmenu, which I was already using as the core of a general 'do things' launcher. Dmenu will read a list of things from standard input, put up a menu/text entry area, let you type to it, and then print out the selection to standard output. All I needed was a way of generating the list of terminal window names and then of making FVWM activate the chosen window.

With the help of the FVWM mailing list I managed to put together both parts of this. Here is what I have. First, the driver script (slightly simplified; the real version also matches gnome-terminal):

#!/bin/sh
# Generate a list of unique names of
# terminal windows.
genwins() {
  xwininfo -root -tree |
  egrep '': \([^)]* "(XTerm|9term)"\)  [0-9]' |
  awk '{print $2}' |
  sed -e 's/^"//' -e 's/":$//' |
  sort -u
}
# run dmenu to get the answer.
win=$(genwins | dmenu -b -p win -P -t) || exit 1
# pass the selected window to FVWM
echo "Function ToWindow \"$win\"" |
  FvwmCommand -c

(The -P and -t arguments to dmenu are from a personal patch that I did. -t is especially useful because it makes dmenu do shell-like partial autocompletion. The real script also specifies the dmenu colours and font to use. There may be a more elegant command than xwininfo to use for getting the window names, but xwininfo has the virtue of being ready to hand.)

In FVWM, I've defined the ToWindow function as follows (the real one also selects gnome-terminal windows):

 AddToFunc ToWindow
 + I   Current ("XTerm|9term", "$0") Break
 + I   Next ("XTerm|9term", "$0") ToWindow2

 AddToFunc ToWindow2
 + I   Iconify False
 + I   Focus
 + I   Raise
 + I   WarpToWindow 80 20

Update: there is a better way to write ToWindow using FVWM States; I've written it up in FvwmStatesUnderstood.

This does nothing if either there is no such terminal window or the current window is a terminal window with the right name. Otherwise, the named terminal window is deiconified, given the focus (which also switches me to its virtual screen if it's not on the current virtual screen), raised to be on top of everything else, and then the mouse pointer is moved into it. I don't normally like having the mouse pointer moved around on me, but it's necessary here in order to make sure that this window keeps the focus; popping up a window and then immediately having it lose focus was more irritating than having my mouse pointer teleported.

(The odd structure of this as two functions is necessary for internal FVWM reasons. Basically it's the easiest way to insure that nothing happens if there's no such window.)

(I also had to add FvwmCommandS (the FvwmCommands server module) to the set of FVWM modules that my configuration runs, since I hadn't been using it before this.)

PS: This code omits '|Gnome-terminal' in three places purely to shorten the length of the unbreakable lines in this blog entry.


Comments on this page:

From 188.222.193.222 at 2012-02-11 05:45:11:

Disappointing not to see you use State here, as we discussed previously.

-- Thomas Adam

By cks at 2012-02-11 16:10:45:

I started to do a version with State and then thought that using State for this would immediately clash with using State for icon placement if I got that working in a future version of FVWM. Writing this now I've just realized that that isn't the case because I iconify terminal windows to FvwmIconMan so that them not being handled properly for a State-based icon placement doesn't matter; they never have desktop icons to be placed.

The real problem with State as I was about to use it is that what I want is effectively a bitmap of options, not a single label for windows. The 'is or is not a terminal window' option is not related to the 'has had its icon placed' option (or any future option I want), but I have to somehow fold them both into a single label with State. Even now I'm not sure I want to lock myself into a single use for states for terminal windows when I don't have to.

Possibly I'm missing something about how to use States cleverly to get overlapping options.

From 188.222.193.222 at 2012-02-11 16:54:53:

Well, I think you're misunderstanding a lot of things here -- you can have up to 32 states for anything you deem appropriate, and in your case you can have one for your terminal windows and others for icon positioning and still test for one or the other or both in conditional commands, depending on your needs.

Certainly, my original outline to your for the use-case you specified will work, but it seems to me as though there's a lot more detail you failed to mention, and it's slightly detrimental to your recommendations in your post, because my general hints to you to use State were correct; and to not mention them in your post just leads to a load of unnecessary complexity. Which, when you're trying to lend advise on things you've discovered to other people, should be correct as much as possible. As it reads now though, it's almost there, but not quite. And if I've learnt anything from all the years of support for different software, it's that there's nothing worse than correcting posts of well-intended enthusiasts. ;P

-- Thomas Adam

By cks at 2012-02-11 19:05:35:

Let me try to show what I meant with a real(ish) example.

Suppose that I want to use a State to mark things as browser windows (as I'm doing here with terminal windows); I assign such windows State 1 as part of applying my general 'browser' style to them. I also want to use a State to mark things that have not had been iconified and had their icon placed yet; I assign such windows State 2. So what is the State of a browser window that has not yet had its icon placed, and how do I match and manipulate this state?

(I think that you can sort of do this in FVWM today but it's awkward, because you are basically writing out all of the cases for an emulation of bitfields. You'd have to match both State 2 and State 3, and then if you label some other sort of windows with their own state you expand the matching and so on.)

Thinking about this led me to the conclusion that I should probably save States for things that really can't be handled any other way, things where I need to mark essentially arbitrary state transformations that can't be matched in other ways. Using States simply as shorthand markers may be slightly more convenient in the short term but runs into long-term problems if you later need States for, well, state markers.

Even if I was successfully using States for 'has not been iconified and had its icon placed yet' in my FVWM configuration, I could get away with it today because terminal windows are never iconified to icons. But I can't use the same approach for other 'tag a class of windows' uses, and I could face problems in the future if I want to use States for something that terminal windows overlap with.

From 188.222.193.222 at 2012-02-11 19:21:32:

Suppose that I want to use a State to mark things as browser windows (as I'm doing here with terminal windows); I assign such windows State 1 as part of applying my general 'browser' style to them. I also want to use a State to mark things that have not had been iconified and had their icon placed yet; I assign such windows State 2. So what is the State of a browser window that has not yet had its icon placed, and how do I match and manipulate this state?

In much the same way you would in your first example, but with a means of tracking iconified state of windows, which is what FvwmEvent is for. But note that you're committing the naughtiest of sins here and deciding your situation in the specific case rules out any use of the general case. Here:

DestroyModuleConfig FE:* *FE: iconify "WindowStyle (!State 2) State 2" *FE: deiconify "ThisWindow (State 2) !State 2"

For anything more specific, such as applying this state only when you've manually placed icons somewhere, you'd need to bind a function to a +M operation which did the above afterwards. Either way, I don't mind. Whether you need to clear out State 2 at all is up to you -- the point is, it's an example to allow you to do whatever you need.

But the state of a browser window which has not had its icon placed yet, is always one which does not have State 2 defined, but can have any other states attached to it, depending on the condition(s) you want to perform on the windows.

  1. Match a window with both States 11 and 12 on it:

Next (State 11, State 12) Focus

  1. Match one specific window:

Next (State 12) Focus

(I think that you can sort of do this in FVWM today but it's awkward, because you are basically writing out all of the cases for an emulation of bitfields. You'd have to match both State 2 and State 3, and then if you label some other sort of windows with their own state you expand the matching and so on.)

Not really.

Thinking about this led me to the conclusion that I should probably save States for things that really can't be handled any other way, things where I need to mark essentially arbitrary state transformations that can't be matched in other ways. Using States simply as shorthand markers may be slightly more convenient in the short term but runs into long-term problems if you later need States for, well, state markers.

In which case you're mis-thinking the whole point of what a "state marker" is, and just because internally FVWM uses a bit-field to mark these windows, does not mean you, as a user, have to use them in that way.

-- Thomas Adam

By cks at 2012-02-11 19:34:16:

Oh! I suddenly see my misunderstanding; I did not realize that windows could be in several states at once. I thought it was exclusive, so that a window in State 1 could not also be in State 2. Non-exclusive States answer my concerns completely and make States the right answer for what I'm doing here.

This is an especially stupid misunderstanding on my part because the documentation more or less explicitly describes them as separate (in the description of State in the FVWM manpage). I just never read the documentation carefully enough. So this one is my fault.

Written on 11 February 2012.
« What supporting a production OS means for me
Understanding FVWM States, with better FVWM code for selecting terminal windows »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Sat Feb 11 01:13:11 2012
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.