FVWM Recent Applications menu

I have created a perl script which creates and matains a Recent Aps menu. I use this with my DebianMenu to collect together the items I select most often from this menu and make them more redially avialable. This Reecnt Aps menu can be adapted to any menu system (or other system in which you want to launch programs from). The system works as follows:

I have created two types of aps that are run, either a X11 app or a Term app ran in your faviorte terminal, $[fvwm_term]. In your menu (or key binding, etc) you run the apps by calling either of the functions FvwmRunX11 or FvwmRunTerm as shown below:

# Usage FvwmRunX11 "App Title" "Icon" "Binary"
DestroyFunc FvwmRunX11
AddToFunc FvwmRunX11
+ I Exec exec $2
+ I PipeRead '$[fvwm_scrpt]/fvwm-aps-menu --title "$0" \
  --icon "$1" --bin "$2" --type "X11" --data-file "$[fvwm_cfg]/recent_aps"'

# Usage FvwmRunTerm "App Title" "Icon" "Binary"
DestroyFunc FvwmRunTerm
AddToFunc FvwmRunTerm
+ I Exec exec $[fvwm_term] -T "$0" -e "$2"
+ I PipeRead '$[fvwm_scrpt]/fvwm-aps-menu --title "$0" \
  --icon "$1" --bin "$2" --type "Term" --data-file "$fvwm_cfg]/recent_aps"'

These functions first run the desired application then add the application to the recent aps menu by the use of the perl script fvwm-aps-menu. This script works as follows:

fvwm-aps-menu --title "$title" --icon "$icon" --bin "$bin" --type "$type" --data-file "$file" --menu-name "$menuName" --menu-title "$menuTitle"

where the variables are related to the app that was just ran via the FvwmRunX11 or FvwmRunTerm functions. This function will first open $file if it exists and build an aps list of all the aps that have been stored. It then checks to see if the app $title is already in the list, if so all it does is increase the times that app has been selected by one. If the app was not found in the list, it will add the new app to the list. It will then sort the list by number of times the app has been used and output syntax to create a menu named $menuName to stdout, so it can be understood via PipeRead. Once this is done the recent application menu can be seen by using the Menu or Popup command for the menu $menuName.

The last thing to note about the script is it will only add a new item to the recent aps list if $title, $icon, $bin and $type are defiend. If you just want to create the recent aps menu at startup, just call the script without any of the above mentioned options:

PipeRead 'fvwm-aps-menu --data-file "$file" --menu-name "$menuName" --menu-title "$menuTitle"'

One last note is that $type can only be either “X11” or “Term” as the script won’t understand any other type and just output “Error: $type” to
the menu.

I hope someone else finds this useful or intersting, and last but not least you can find the perl script below:

jaimos

#!/usr/bin/perl
#
# Perl script to keep track of what aps are being
# run in Fvwm via the two functions FvwmRunX11
# and FvwmRunTerm, invoked though my DebianMenu


use strict;
use Getopt::Long;

# Defaults of global variables
my $apsFile = "/home/jaimos/.fvwm/cfg/recent_programs";
my $menuName = "FvwmMenuRecentAps";
my $menuTitle = "Recent Aps";
my @lines;
my @aps = ();
my $cnt = 0;
my $new = 1;
my $newTitle = "";
my $newBin = "";
my $newIcon = "";
my $newType = "";

my $title = "";
my $icon = "";
my $bin = "";
my $type = "";
my $count = "";

GetOptions(
  "title=s"		=> \$newTitle,
  "bin=s"		=> \$newBin,
  "icon=s"		=> \$newIcon,
  "type=s"		=> \$newType,
  "data-file=s"		=> \$apsFile,
  "menu-name=s"		=> \$menuName,
  "menu-title=s"	=> \$menuTitle,
);

# Read $apsFile push the data onto @lines
if (open ( APS_FD, "< $apsFile" ))
{
  while ( <APS_FD> )
  {
    chomp;              # remove trailing newline characters
    push @lines, $_;    # push the data line onto the array
  }
  close APS_FD;
}

# Parse @lines and create the @aps aray
# With each line is writen like
# $count\0$type\0$title\0$icon\0$bin
my $app_no = 0;
foreach (@lines)
{
  if ( $_ =~ /(.+)\0(.+)\0(.+)\0(.+)\0(.+)/ )
  {
    $count = "$1";
    $type = "$2";
    $title = "$3";
    $icon = "$4";
    $bin = "$5";
    $title =~ s/_/ /g;
    push @aps, [ "$title", "$icon", "$bin", "$type", $count ];
    $app_no++;
  }
}

# Check to see if the $newTitle is already known in @aps.
# If it is $count++ other wise add it to @aps.
if ( $newTitle && $newIcon && $newBin && $newType)
{
  for ( $cnt = 0 ; $cnt < $app_no ; $cnt++ )
  {
    if ( "$newTitle" eq "$aps[$cnt][0]" )
    { $aps[$cnt][4]++; $new = 0; }
  }
  if ( $new )
  {
    push @aps, [ "$newTitle", "$newIcon", "$newBin", "$newType", 1 ];
    $app_no++;
  }
}

# Sort the @aps by $count
@aps = sort { $b->[4] <=> $a->[4] } @aps;

# Print the FvwmMenu syntax to stdout
print qq(DestroyMenu $menuName\n);
print qq(AddToMenu $menuName "$menuTitle" Title\n);

for ( $cnt = 0 ; $cnt < $app_no ; $cnt++ )
{
  $title = $aps[$cnt][0];
  $icon = $aps[$cnt][1];
  $bin = $aps[$cnt][2];
  $type = $aps[$cnt][3];
  $count = $aps[$cnt][4];
  if ( $type eq "X11" )
  {
    print qq(+ "$title\%$icon\%" FvwmRunX11 "$title" "$icon" "$bin"\n);
  } elsif ( $type eq "Term" )
  {
    print qq(+ "$title\%$icon\%" FvwmRunTerm "$title" "$icon" "$bin"\n);
  } else # This should not happen
  {
    print qq(+ "Error: Invalid type $type" Nop\n);
  }
}

# Write @aps to $apsFile
open ( APS_FD, "> $apsFile" ) or die "Failed to open file: $apsFile";
for ( $cnt = 0 ; $cnt < $app_no ; $cnt++ )
{
  $title = $aps[$cnt][0];
  $icon = $aps[$cnt][1];
  $bin = $aps[$cnt][2];
  $type = $aps[$cnt][3];
  $count = $aps[$cnt][4];
  $title =~ s/ /_/g;
  print APS_FD qq($count\0$type\0$title\0$icon\0$bin\n);
}
close APS_FD;