Subject: FVWM: Variable assignment and use

From: Rusty Phillips <[email-masked]>
Date: Tue, 29 Jun 2004 02:35:05 -0500

Creating constant valued scalar variables is obviously possible with
SetEnv, but is there an accepted way to do anything beyond this?
I have two questions about this:

I  Lets say, for example, that I wanted to create a command that keeps
track of the location of every window on the screen and restores them to
that condition if I press that command again, while ignoring windows
that are new or closed.  Is this possible in fvwm?

These are the big problems I can't solve:
1)  I can't find a non-scalar assignment mechanism.
2)  I can't find a looping mechanism that uses such an assignment
(foreach type looping)
3)  I can't find a way to return the properties of a window. 
4)  Some Window commands don't accept a Window name or id, and will only
use the "current" window. 

II  Is there a way to get the properties from a window newly created
with an "Exec" command (or from multiple windows created from an Exec
command)?

I've looked through all the modules, read the FAQ, and looked at quite a
few fvwm2rc files, but I can't find the answer to these questions. 
Anyone have a clue?  Any help would be greatly appreciated.

--
Visit the official FVWM web page at <URL: http://www.fvwm.org/>.
To unsubscribe from the list, send "unsubscribe fvwm" in the body of a
message to [email-masked].
To report problems, send mail to [email-masked].

---

From: Tavis Ormandy <[email-masked]>
Date: Tue, 29 Jun 2004 09:19:23 +0100

> 1)  I can't find a non-scalar assignment mechanism.

Well, you have access to shell functions with PipeRead, and there's
FvwmPerl, but apart form that I think SetEnv is the only option.

> 2)  I can't find a looping mechanism that uses such an assignment

All (conditions) xxx

will loop through all windows, you can add an assignment for each window
that matches.

> 3)  I can't find a way to return the properties of a window. 

There are variables such as $[w.id], $[w.width], etc that if accessed in
the context of a window are expanded to that property.

> use the "current" window. 

I'm not aware of any, some commands need to run in the context of a
window, but can be prefixed with Pick, Current, WindowId, etc. I think
most commands will use the Pick mechanism if they need to be run in the
context of a window but are'nt?

> with an "Exec" command (or from multiple windows created from an Exec

yes, see #3.18 in the faq.

> track of the location of every window on the screen and restores them
> to that condition if I press that command again, while ignoring windows

How about this:

AddToFunc SavePosition I All (CurrentPage) SetEnv Position-$[w.id] "\(True\) AnimatedMove $[w.x]p $[w.y]p"
AddToFunc RestorePosition I All (CurrentPage) PipeRead "echo Test \\$\\[Position-$[w.id]\\]"

Uses a PipeRead though :) You could use FvwmEvent to UnsetEnv variables
as windows are destroyed...

I'm not sure if this needs the new Test syntax in cvs or not.

-- 
-------------------------------------
[email-masked] | finger me for my gpg key.
-------------------------------------------------------
--
Visit the official FVWM web page at <URL: http://www.fvwm.org/>.
To unsubscribe from the list, send "unsubscribe fvwm" in the body of a
message to [email-masked].
To report problems, send mail to [email-masked].

---

From: Dominik Vogt <[email-masked]>
Date: Tue, 29 Jun 2004 13:43:54 +0200

> 1)  I can't find a non-scalar assignment mechanism.

Fvwm does not support array variables directly.  However, you can
put the array index in the variable name.  For example:

  setenv xpos_$[w.id] $[w.x]
  setenv ypos_$[w.id] $[w.y]

(replace $[w.id] with $w for older fvwm versions).  If you have
the window selected, you can access the stored property like this
by using the functions below:

  array_get xpos $[w.id]
  array_get ypos $[w.id]
  # return values are now stored in xpos_val and ypos_val

With the functions array_init, array_append and array_delete you
can even manage indexed arrays.  E.g.:

  # create new array
  array_init foo
  # append a couple of entries
  array_append foo entry1
  array_append foo entry2
  array_append foo entry3
  # print some entries
  array_get foo 1
  echo $[foo_0] $[foo_val]
  # delete entry2
  array_delete foo 1
  # clean out whole array
  array_init foo

Looping over all aray indices can be done with a shell script via
piperead.

------------------------- snip -------------------------------------
#
# Fvwm based array implementation
#

# Warning: These function can *not* handle quoting characters or
# shell meta characters in variable names or contents.

# $0 = array name
# $1 = array index
# result is stored in $0_val
AddToFunc array_get
+ i piperead 'echo setenv \\"$0_val\\" \\"\\$\[$0_$1\]\\"'

# $0 = array name
AddToFunc array_init
+ I setenv "$0_num" 0

# $0 = array name
# $1 = data to store
AddToFunc array_append
+ i piperead 'echo setenv \\"$0_"\\$\[$0_num\]"\\"  \\"\\$1\\"'
+ i piperead 'echo setenv \\"$0_num\\" \$\[$0_num + 1\]'

# $0 = array name
# $1 = array index to delete
# Note: If the array is already empty, this function may corrupt
# the array.  The last entry in the array is moved to the vacant
# slot.
AddToFunc array_delete
+ i piperead 'echo setenv \\"$0_num\\" \$\[$0_num - 1\]'
+ i piperead 'echo setenv \\"$0_$1\\" \\"\\$\[$0_\${$0_num}\]\\"'
--------------------------------------------------------------------

Ciao

Dominik ^_^  ^_^

 --
Dominik Vogt, [email-masked]
Reply-To: [email-masked]

---

From: Rusty Phillips <[email-masked]>
Date: Tue, 29 Jun 2004 10:11:59 -0500

Masterful answers Dominik Vogt and Tavis Ormandy.   It's not
straightforward, but I guess you can do anything you want with fvwm.

Tavis, with your approach to that problem you're going to be filling the
memory with useless variables, won't you?  I mean, when you're finished
with them, and have closed the window they describe, they're still there
since there's no way to unset a variable (there isn't is there?).

Anyway, you certainly gave me enough info to have an array datatype, so
I guess I'll just do that.

---

From: Thomas Adam <[email-masked]>
Date: Tue, 29 Jun 2004 16:04:25 +0100

On Tue, 29 Jun 2004 10:11:59 -0500
Rusty Phillips <[email-masked]> wrote:

> Tavis, with your approach to that problem you're going to be filling
> the memory with useless variables, won't you?  I mean, when you're
> finished with them, and have closed the window they describe, they're
> still there since there's no way to unset a variable (there isn't is
> there?).

You can with FvwmEvent do something like:

DestroyModuleConfig FvwmEvent-somealias: *
*FvwmEvent-somealias: destroy_window FvwmFuncUnsetName

DestroyFunc FvwmFuncUnsetName
AddToFunc FvwmFuncUnsetName
+ I UnSetEnv <var>
+ I UnSetEnv <var2>

...etc

-- Thomas Adam

--
"Annie Hall leaves New York in the end. Press rewind, and Woody gets her
back again." -- "Look Inside America", Blur.

---

From: Mikhael Goikhman <[email-masked]>
Date: Tue, 29 Jun 2004 15:10:52 +0000

> + i piperead 'echo setenv \\"$0_val\\" \\"\\$\[$0_$1\]\\"'

I am not sure poluting the environment space of all fvwm processes is the
best solution. An arguably faster, cleaner and easier solution is to use
FvwmPerl to handle any complex data structures, like arrays of hashes.

Here is a fun example. Open some windows and type in FvwmConsole:

  FvwmPerl  # run this only once
  AddToFunc eval I SendToModule FvwmPerl eval $*

  # store position of all non sticky windows on the current page
  All (!Sticky, !Iconic, CurrentPage) \
    eval push @a, { id => $[w.id], x => $[w.x], y => $[w.y] }

  # switch x and y coordinates of windows
  eval foreach (@a) { cmd("WindowId $_->{id} AnimatedMove $_->{y}p $_->{x}p") }

  # some time later, restore original position of windows
  eval foreach (@a) { cmd("WindowId $_->{id} AnimatedMove $_->{x}p $_->{y}p") }

  # warp to the first window if any
  eval cmd("WindowId $a[0]->{id} WarpToWindow") if @a

  # clean up the stored windows data
  eval @a = ()

See the man page and ask if you don't understand something. FvwmPerl is
good for small tasks, for longer ones it is probably easier to write you
own module. I will post a short module (script of several lines) later
today, I need to test a new WindowList tracker anyway.

Regards,
Mikhael.

---

From: Mikhael Goikhman <[email-masked]>
Date: Tue, 29 Jun 2004 22:56:15 +0000

Ok, here is the promissed module in Perl that demonstrates one more
solution for storing window positions/names/whatever. This module
requires the latest fvwm from cvs. Save this file as FvwmWindowDance and
call it using the full path with an optional Module keyword. The code
hopefully explains itself.

#!/usr/bin/perl -w

use lib `fvwm-perllib dir`;
use FVWM::Module;

my $module = new FVWM::Module;
my $tracker = $module->track("WindowList");

foreach my $window ($tracker->windows) {
	my $x = $window->{x};
	my $y = $window->{y};
	my $name = $window->{visible_name};
	next unless $window->match("CurrentPage, !Iconified");

	$module->send("Move ${y}p ${x}p", $window->{id});
	sleep(1);
	$module->send("Move ${x}p ${y}p", $window->{id});
	sleep(1);
}

$module->disconnect;

Note 1. "AnimatedMove" instead of "Move" does not work well here,
supposedly because of the general fvwm problem with grabbing+AnimatedMove.

Note 2. Unfortunately there are no many window conditions right now
besides the "CurrentDesk", "Iconified". For example "Sticky" and other
flags are definitely missing.

Note 3. This is a transient module, but a long-lived module with event
loop is possible and would be preferable in some cases. All window
information is automatically up to date in this case, it all should be
handled by the WindowList tracker behind the scenes. "fvwm-perllib man".

Regards,
Mikhael.

---

From: Rusty Phillips <[email-masked]>
Date: Wed, 30 Jun 2004 08:36:25 -0500

I've been trying out variations on ways to keep track of Windows, and am
not trying the perl module creation technique.
I've run into difficulty debugging:  none of my debugging output
actually shows up anywhere unless I run the module from the command
line.

Is it supposed to?  Of course, I can always just redirect the error to a
file within perl, but is there a standardized way of doing this that I'm
not seeing?

---

From: Scott Smedley <[email-masked]>
Date: Wed, 30 Jun 2004 23:47:05 +1000

> actually shows up anywhere unless I run the module from the command

stdout/stderr from each module goes to the same place as stdout/stderr
of FVWM. I suggest adding a line like this to your ~/.xsession file:

exec fvwm >& $HOME/.fvwm/.errorLog

Then all FVWM & module output is captured in ~/.fvwm/.errorLog. I often
run "tail -f" on this file.

SCoTT. :)

---

From: Thomas Adam <[email-masked]>
Date: Wed, 30 Jun 2004 15:08:09 +0100

On Wed, 30 Jun 2004 23:47:05 +1000
Scott Smedley <[email-masked]> wrote:

> Then all FVWM & module output is captured in ~/.fvwm/.errorLog. I
> often run "tail -f" on this file.

Logging defaults to ~/.xsession-errors otherwise. 

-- Thomas Adam

---

From: [email-masked]
Date: Wed, 30 Jun 2004 14:13:21 -0700

Reading through the archives, it seems a bunch of years back there had 
been an abortive discussion about making the Fvwm frames able to be 
sized independently. Specifically, the discussion mentioned being able 
to set the top, bottom, right and left borders to different sizes. I'm 
curious how difficult these would be to implement with the current codebase.

Even just a new option for Border/HandleHeight would be interesting. It 
could work the same as the Border/HandleWidth option, but obviously 
would only set the height of the top and bottom borders. Alternately it 
would be better, though probably harder, to make each border 
independantly sizable. Any chance any of this is on the todo list?

Also a question. For a verticle 6 pixel border (drawn in craptastic 
ascii) The colors draw like below.

   _shadow
 /  _hilight
| /  _ hilight
|| /  _ background
||| /  _shadow
|||| /  _shadow
||||| /
||||||

Which when made transparent, makes only the background line transparent. 
The hilight and Shadow colors are still opaque. If I set the border to 
"flat" the entire thing is drawn as the background color and is 
transparent, but lacks contrast between windows without the outer 1 
pixel shadow color. Is there a way to make all but the outer and 
innermost 1 pixel transparent?

Also, the hilight being drawn twice while the shadow is only drawn once 
makes the bevel look really odd/bad. Pretty obvious with a setup like:

Style * Handlewidth 20, Colorset 1
Colorset  1 bg yellow, hi red, sh blue

In any case, thanks for your time all. I've been using Fvwm for years 
and it just keeps getting better and better.

Regards,
Frederick Potetz