Subject: FVWM: Using output of external programs.

From: "Daniel M." <[email-masked]>
Date: Tue, 12 Oct 2004 18:11:01 +0200

Hello,

I have a small script which receives one argument, builds menus
and echos fvwm commands to create them. I added the following line
to .fvwm file in order to be able to use menus created by that script:

PipeRead 'menu-builder ~/.fvwm/menu'

but when I try to pop up one of the created menus (executing "popup XYZ"
from FvwmConsole), I get an error:

"Menu XYZ does not exists".

If I ran the script manually and copy/paste it's output into
FvwmConsole and then try to pop up menus, it works.

What can I do so that the script will work automatically
(I want to use that script rather than the standard ones for
menu creation)?

I use fvwm 2.5.12.

Daniel.
--
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, 12 Oct 2004 23:11:24 +0200

> (I want to use that script rather than the standard ones for

It's hard to say what goes wrong without knowing the script.  Can
you please post it to the list?

Ciao

Dominik ^_^  ^_^

 --
Dominik Vogt, [email-masked]

---

From: "Daniel M." <[email-masked]>
Date: Wed, 13 Oct 2004 00:04:22 +0200

> you please post it to the list?

The script is included below. It is only a first draft version,
and using anything complex will probably break it.

Usage:

The script receives one argument, which should be a path to
a directory where menu configuration files reside.

The script (recursively) does the following:

Every directory becomes a menu, with the same label as a
directory. for example, ~/.fvwm/menu will become a manu with
'menu' as a label (the menu itself will be named ~/.fvwm/menu).
Subirectories in a given directory will become submenus, and
files in a directory will contain configuration for menu items.
For example, '+ "Firefox browser" Exec exec mozilla-firefox'
expression, which can be part of a AddToMenu command, will appear
in some file in a directory without the leading '+'. Such an
expressions may be put into one or more files in a directory (in
case of multiple files, their contents will be simply concatanated
- files would be read in alphabetical order of their names).

Single letter on a line tells how to sort items/submenus in a
menu. Default is an alphabetical descending order of labels,
submenus first (which is the only working option right now). Actually,
sort order may be set for every section of a menu. Secion is all
the items from the beginning of a menu/separator till separator/end
of a menu. By default, all submenus are put into the first section.
If user wants to put it in other section, he has to insert double-quoted
name (label, actually) of that submenu into the desired section.

One of the rules, is that every line should contain a command,
in addition to menu item's label. For example, it won't work to put
'""' all alone on a line to create a separator - it should be '"" Nop',
otherwise the line would be disregarded.

And here is a script:

---------------------------------------------------
#!/usr/bin/perl

use strict;

my $dir = $ARGV[0];
my $menus_config;

process_dir($dir);
print $menus_config;

sub process_dir {
	my ($dir, @dir_contents, @menu_contents, %submenus_list) = shift;

	opendir(DIR, $dir) or warn "Counldn't read directory $dir: $!. Skipping...\n"
			      and return;
         @dir_contents = sort(readdir(DIR));

	foreach (@dir_contents) {
		next if (/^(\.|\.\.)$/);
		$submenus_list{$_} = 1 and next if (-d "$dir/$_");
		if (-f "$dir/$_") {
			open(FILE, "$dir/$_") or next;
			push @menu_contents, <FILE>;
			close(FILE);
		}
	}

	make_menu($dir, \%submenus_list, \@menu_contents);

	foreach (keys %submenus_list) {
		process_dir("$dir/$_");
	}
}

sub make_menu {
	my ($dir, $submenus_list_ref, $menu_contents_ref) = @_;

	my ($section, @sections) = [];
	foreach (@$menu_contents_ref) {
		s/^\s*//;
		s/\s*$//;
		next if ($_ eq "");
		
		push(@$section, ("CONTROL", lc($_))) and next if (length == 1);

		/^([^"].*?)\s{1,}(.*)/ or /^"(.*?)"\s*(.*)/;
		# separator or tear up menu
		if ($1 eq "") {
			push(@$section, ("", $2));
			push(@sections, $section);
			$section = [];
			next;
		}
		
		# means that it submenu is supposed to be inserted here	
		if ($2 eq "" and exists $$submenus_list_ref{$1}) {
			delete $$submenus_list_ref{$1};
		} elsif ($2 eq "") {
			next;
		}
		
		push(@$section, ($1, $2));
	}
	push(@sections, $section);

	# if some of the submenu names were not in one of the sections,
	# insert them all into the first section, and sort according to
	# that section's rules.
	foreach (keys %$submenus_list_ref) {
		push(@{$sections[0]}, ($_, ""));
	}
		
	$menus_config .= "AddToMenu \"$dir\"\n";
	foreach (@sections) {
		sort_section($dir, $_);
		foreach (@$_) {
			$menus_config .= $_;
		}
	}

}	
			
sub sort_section {
	my $dir = shift;
	my $section_ref = shift;
	my %entries = @$section_ref;

	my $sort_type = $entries{CONTROL};
	delete $entries{CONTROL};
	
	my (@submenus, @items, @processed_section);
	# Alphabetic sort, submenus at the beginning
	if ($sort_type eq "") {
		foreach (sort keys %entries) {
			push(@submenus, "+ \"$_\" PopUp \"$dir/$_\"\n") and next
				if ($entries{$_} eq "");
				
			push(@items, "+ \"$_\" $entries{$_}\n");
		}
		
		@processed_section = (@submenus, @items);
		
	} elsif ($sort_type eq "n") { # no sorting
	
		for (my $n = 0; $n < $#$section_ref; $n += 2) {
			push(@processed_section, "+ \"$section_ref->[$n]\" PopUp ",
			     "\"$dir/$section_ref->[$n]\"\n") and next
			     if ( $section_ref->[$n+1] eq "");
				
			push(@processed_section, "+ \"$section_ref->[$n]\" ",
			     "$section_ref->[$n+1]\n");
		}
	}
	
	@$section_ref = @processed_section;
}
---------------------------------------------------

I have a great doubt, though, that somebody is going to
get to that last line :).

Daniel.

---

From: Dominik Vogt <[email-masked]>
Date: Wed, 13 Oct 2004 02:44:58 +0200

On Wed, Oct 13, 2004 at 12:04:22AM +0200, Daniel M. wrote:
> directory.

Hm, are you aware that such a script is included in the fvwm
tarball?  Look for fvwm-menu-directory.  It even has a man page.
If you instist on writing your own script, take utmost care that
file and directory names with embedded spaces, tabs and newlines
are handled correctly.  Otherwise you might end up running
commands embedded in a file name, e.g. if the name is

 "foo<newline>rm -rf *"

Your script seems to work fine for me.  Are you sure it it
executed at all?  Is it in the PATH?  Hm, nor that I run it again,
it sometimes hangs or dumps the contents of the files in the
given directory.

[snip]

Ciao

Dominik ^_^  ^_^

---

From: "Daniel M." <[email-masked]>
Date: Wed, 13 Oct 2004 22:17:56 +0200

> tarball?  Look for fvwm-menu-directory. 

If I understood the man page correctly, it doesn't do what I want
- it creates a kind of a directory browser, but I want to create
a regular menu. The other solution can be to create Gnome/Kde
menu and then run a script included with fwvm to convert that menu
to fvwm's format.

> it sometimes hangs or dumps the contents of the files in the

Yes, it is in the path. Don't know about whether it is actually
executed when fvwm starts, but manually it always executes correctly.

Daniel.

---

From: Mikhael Goikhman <[email-masked]>
Date: Wed, 13 Oct 2004 22:00:57 +0000

> menu and then run a script included with fwvm to convert that menu

I think it would be better to warn people not to run the included script
on random directories, since it just slightly preprocesses the content of
all files and dirs and dumps it (binary or not).

If I understand you correctly, you want to create an alternative syntax
for menus and use a specially prepared dir structure and file contents
for this purpose.

I think there is an error in the script somewhere that gives you the
problem. I suggest to add "DestroyMenu" commands before "AddToMenu", so
you could PipeRead the script more than once.

> when I try to pop up one of the created menus (executing "popup XYZ"

I guess the actual error message is "No such menu XYZ". Maybe you run the
script manually with different parameters and then get menu XYZ defined?
I suggest to examine again the config line you use to run the script and
its output.

If you still think there is a problem in fvwm, then:

  * pack the whole dir used to define the menus to tar.gz and send it
  * prepare a minimal .fvwm2rc config file with 2-3 lines that shows the
    "No such menu XYZ" problem and send it
  * send the new script version that does "DestroyMenu" first
  * send the output of the same script command you have in the minimal
    config file (with menu XYZ defined, just to compare the results)

It is possible you will find the problem before completing these steps.

Regards,
Mikhael.