On Tue, Feb 07, 2012 at 03:41:22PM -0500, Chris Siebenmann wrote:
>  I feel like I'm missing some important bits about how fvwm handles
> functions.
> 
>  I'm trying to write a function that's fed a window name and has
> following goals. First, it only operates on terminal windows.
> Then:
> - if no (terminal) window by that name exists, it should do nothing.
> - if the currently selected/focused window has that name (and is a terminal
>   window), it should do nothing.
> - otherwise, it should deiconify, focus, and raise the window, then
>   move the pointer to be inside the window.
> 
> My current version is:
> 
>       AddToFunc ToWindow
>       + I     Current ("XTerm|9term|Gnome-terminal", "$0") Break
>       + I     Next ("XTerm|9term|Gnome-terminal", "$0") Iconify False
>       + I     Next ("XTerm|9term|Gnome-terminal", "$0") Focus
>       + I     Next ("XTerm|9term|Gnome-terminal", "$0") Raise
>       + I     Next ("XTerm|9term|Gnome-terminal", "$0") WarpToWindow 80 5

This is why it's better to do this:

Style XTerm State 1
Style 9term State 1
Style Gnome-terminal State 1

DestroyFunc ToWindow
AddToFunc   ToWindow
+ I Current (State 1, $0) Break
+ I Next (State 1, $0) SomeFunction

DestroyFunc SomeFunction
AddToFunc   SomeFunction
+ I Iconify False
+ I Focus
+ I Raise
+ I WarpToWindow 80 5

So you can see here, by using State, that we've shifted the repetitiveness
to the style of the window, and not a pre-condition to all commands we might
need to reference a bunch of terminals.

> This works but seems unnecessarily repetitive (actually I'm suddenly
> not convinced that it does nothing if the current window is a terminal
> window called $0). So I thought I could rewrite it like this (with
> comments about the logic):
> 
> AddToFunc ToWindow
>       # do nothing if current window is called $0
> + I   Current ("XTerm|9term|Gnome-terminal", "$0") Break
> + I   Next ("XTerm|9term|Gnome-terminal", "$0") Focus
>       # if no window is called $0, this stops; otherwise Focus has
>       # made that window the current window.
> + I   TestRc (NoMatch) Break
>       # do the rest of the work
> + I   Iconify False
> + I   Raise
> + I   WarpToWindow 80 5
> 
>  However, this doesn't work if no such window actually exists; before
> anything from the function seems to execute (even an 'Echo' statement

Context is about how functions run, and the way you have it there, FVWM will
need a window context to run in -- that is, a window to operate on.  Your
use of "$0" implies this to some extent, in that you have a name or
something being passed in, but you don't say how.

If FVWM doesn't have an operand window, then it will ask for one.  This will
depend on how you're trying to call this function.  This is perhaps the most
important piece of information you've failed to provide.

>  Do I need to make all commands conditional in this function in order
> to have things work right, by putting plain 'Current ' in front of the
> last three lines? (A version with this change seems to do nothing if
> there's no terminal window by that name, but I feel I'm just sort of
> writing code by superstition instead of actual understanding at this
> point.)

No you don't.  Consider this:

AddToFunc ToWindow
+ I     Current ("XTerm|9term|Gnome-terminal", "$0") Break
+ I     Next ("XTerm|9term|Gnome-terminal", "$0") Focus
+ I     TestRc (NoMatch) Break
+ I     Iconify False
+ I     Raise
+ I     WarpToWindow 80 5


If I bind this to a key like this:

Key f A M ToWindow

Then press Alt-f, FVWM evaluates the context of the binding.  It may well be
that the window we're operating on is implied, in which case FVWM won't ask
for a window -- and indeed, your implementation of ToWindow doesn't.  FVWM
processes the commands in order, top-to-bottom.  It comes across "Current"
and evaluates that in the context of the binding.  Of course, there is
nothing special about Current, Next, or TestRc, they can run inside a
function just fine, and at this point assume no specific window -- but
because you have this:

+ I Iconify False

... if FVWM processes this from your ToWindow function and there is no
implied operand window for ToWindow to be running in, it will prompt for a
window to run against, because it needs a window.

Let me elaborate more on what I mean by operand window, and implied context.
Mouse bindings are good for this:

Mouse 0   1       A     FuncWindowOpsOrClose

DestroyFunc FuncWindowOpsOrClose
AddToFunc FuncWindowOpsOrClose
+ H Nop 
+ C Echo Clicked $[w.id]
+ D Close

Pressing any mouse button on button 1 on a window will call
FuncWindowOpsOrClose -- and note that here:

+ D Close

I do not need:

+ D ThisWindow Close

Nor do I need:

+ D Current Close

It's because the binding happens on a window already.

Once you have a window you're hooked on it though.  So really, establishing
a binding to one window can happen outside the function before invoking it,
and that's precisely what I did with my original suggestion to you above:

DestroyFunc ToWindow
AddToFunc   ToWindow
+ I Current (State 1, $0) Break
+ I Next (State 1, $0) SomeFunction

DestroyFunc SomeFunction
AddToFunc   SomeFunction
+ I Iconify False
+ I Focus
+ I Raise
+ I WarpToWindow 80 5

So can you not see now, why in SomeFunction I do not need to prefix the
commands with Current, because they're all called in the matched window from
ToWindow, coming from the Next command?

There are other ways of achieving this though.  'Pick' is another useful
command which would have helped you as well, but I shied away from
mentioning it above to help illustrate what was going on.   But:

Pick ToWindow

Would work just as well with how you've written things.

-- Thomas Adam

-- 
"Deep in my heart I wish I was wrong.  But deep in my heart I know I am
not." -- Morrissey ("Girl Least Likely To" -- off of Viva Hate.)

Reply via email to