Mikhael Goikhman <[EMAIL PROTECTED]> wrote on Sat, 2 Nov 2002 03:08:09 +0000: > > Subject: Re: FVWM: Idea: Improved Window List Menu > > On 01 Nov 2002 18:04:38 -0500, Richard Lister wrote: > > > > As I mentioned in another thread, I've already implemented this. > > I ported it to the 2.5.4 perllib, which was very straightforward. > > > > Let me know if you want me to post it. I've included a screenshot > > of the menu generated. > > Actually, I will need to write a lot of small modules in addition to the > current 6 in cvs to test trackers, I may use your module as a test case.
Hi Mikhael I've added optional page and desk-level resolution and some documentation to the script. I've attached it here. > > Is there any info online about the automatic trackers you are > > implementing? > > Such info is not even in my head yet. I only know that this should be > somewhat powerful and easy to use and extend. :) As far as I understand it the trackers will make most of the stuff I've done in handlers redundant. Is that correct? > Take a look at TrackerFactory.pm in cvs or ftp.fvwm.org to get some ideas. Will do this later. > My plan is to get some module and see how trackers may help it. > For example, your module may use 3 trackers, WindowList (with "wininfo" > and probably "icons" options), ConfigInfo and PageInfo. Other trackers > may be: Colorsets, GlobalInfo and "stack" option to the WindowList. > Nothing is final at all, even the names "tracker" and "grabber". > > You are as the library user may help with ideas and design. > If you want to participate, install cvs. > Just please keep in mind that this is not my first priority for November. Ditto on November :-) But I'll take a look when I get a bit of time. A bug in my script ... sticky windows are only listed on the desk where they originated (were made sticky). This is not a problem when changing page, as there seems to be a M_CONFIGURE_WINDOW packet sent for each window in that case and I set the desk from that handler. But these packets are not send for a change desk event. Why is that? I could probably get round this by doing a Send_Windowlist when M_NEW_DESK is caught, but that seems clunky :-) Cheers Ric Richard J Lister Dept of Neuroscience Georgetown University Medical Center http://cns.georgetown.edu/~ric/
#!/usr/bin/perl -w =head1 VERSION $Id: FvwmLister.pl,v 2.2 2002/11/05 23:57:10 ric Exp $ =head1 AUTHOR Ric Lister <http://cns.georgetown.edu/~ric/> =head1 DESCRIPTION Substitute for fvwm builtin WindowList, but written in Perl and easy to customize. Unlike FvwmIconMan or FvwmWinlist the module does not draw its own window, but instead creates a fvwm menu and asks fvwm to pop it up. By defining a set of regular expressions in @show, windows may be sorted into sections based on the regexp matching their title. Similarly, matches in @dontshow will be excluded from the list. Any windows not matching an element of @show or @dontshow will be placed in the last section of the menu. =head1 USAGE Place this in e.g. your .fvwm2rc StartFunction Module FvwmLister Invoke the menu from .fvwmrc like this, for example: Key Menu A N SendToModule FvwmLister Root c c The arguments are any valid Menu arguments. Set module options, e.g.: *FvwmLister: Show ^Galeon|^Netscape *FvwmLister: Show ^emacs will define two sections containing respectively browsers, and emacs. Number of sections is unlimited. The strings are perl regular expressions that will be evaluated in m// context. See perlre(1). Similarly: *FvwmLister: DontShow ^Fvwm *FvwmLister: DontShow ^gkrellm will cause the menu to ignore windows with title beginning Fvwm or gkrellm. Other options: *FvwmLister: OnlyIconic {on|off} ## show only iconified windows *FvwmLister: MiniIcon {0|1|2} ## show mini icon: 0=never, ## 1=always, 2=icon windows only *FvwmLister: AllDesks {on|off} ## show windows from all desks *FvwmLister: AllPages {on|off} ## show windows from all pages *FvwmLister: ShowPosition {on|off} ## show window position in () *FvwmLister: Maxlen 32 ## max length in chars of entry *FvwmLister: Menu foobar ## name of menu to popup *FvwmLister: MenuStyle foobarstyle ## name of MenuStyle to apply *FvwmLister: Debug {-1,0,1,...} ## level of debug info output =cut ## default user options my $opt = { onlyiconic => 0, ## only list iconified windows mini_icon => 2, ## 0=never, 1=always, 2=iconic windows only alldesks => 0, ## list windows on all desks allpages => 0, ## list windows on all pages showposition => 1, ## show window position maxlen => 32, ## max chars for window name in menu menu => "Lister", ## name of fvwm menu to create menustyle => "Lister", ## name of fvwm menu style to use }; ## get size of your screen my $screen; ## I would like a better way of getting screen dimensions! open(XWININFO, "xwininfo -root|") || die "can't run xwininfo"; while ( <XWININFO> ) { $screen->{w} = $1 if /Width:\s*(\d+)/; $screen->{h} = $1 if /Height:\s*(\d+)/; } close(XWININFO); ## or hard-code it # $screen->{w} = 1600; # $screen->{h} = 1200; ## ## USER SHOULD NOT NEED TO CHANGE ANYTHING BELOW HERE ## use strict; use lib `fvwm-perllib dir`; use FVWM::Module; use FVWM::EventNames; ## some global vars my (%window, $page, $desk); ## show = window matches to display in order, each entry defines a section ## dontshow = window matches to ignore, none of these will show up in the menu my (@show, @dontshow); ## init the module ## set Debug = -1 for no messages at all ## set Debug = 0 to see my messages about window decisions ## set Debug = 1 to see also perllib messages about communication my $module = new FVWM::Module( Name => "FvwmLister", Mask => M_WINDOW_NAME | M_STRING | M_NEW_PAGE | M_NEW_DESK | M_ADD_WINDOW | M_CONFIGURE_WINDOW | M_DESTROY_WINDOW | M_END_WINDOWLIST | M_ICONIFY | M_DEICONIFY | M_MINI_ICON | M_CONFIG_INFO | M_SENDCONFIG, Debug => -1, ); $module->debug("starting " . $module->name); ## process module options $module->addHandler(M_CONFIG_INFO, sub { my ($module, $event) = @_; my $modname = $module->name; return unless $event->_text =~ /^\*$modname(.*)$/; $_ = $1; ## get show array if ( /^show\s+(.*)$/i ) { push(@show, $1); } ## get dontshow array elsif ( /^dontshow\s+(.*)$/i ) { push(@dontshow, $1); } ## get mini_icon option elsif ( /^miniicon\s*(.*)/i ) { $opt->{mini_icon} = $1 if $1; } ## get all other options, arg of 'off' sets opt to 0 elsif ( $1 =~ /^(\w+)\s*(\w+)/i ) { (my $arg1 = $1) =~ tr/A-Z/a-z/; $opt->{$arg1} = ($2 =~ /^off$/i) ? 0 : $2; } ## should probably do more error checking }); ## handler to get page and desk info $module->addHandler(M_NEW_PAGE, sub { my ($module, $event) = @_; $desk = $event->_desk; $page = { x => $event->_vp_x, y => $event->_vp_y, h => $event->_vp_height, w => $event->_vp_width, } }); $module->addHandler(M_NEW_DESK, sub { my ($module, $event) = @_; $desk = $event->_desk; }); $module->addHandler(M_STRING, sub{ my ($module, $event) = @_; &PopupMenu($event->_text); }); $module->addHandler(M_ADD_WINDOW|M_CONFIGURE_WINDOW, sub { my ($module, $event) = @_; $window{$event->_win_id}->{desk} = $event->_desk; $window{$event->_win_id}->{x} = $event->_frame_x; $window{$event->_win_id}->{y} = $event->_frame_y; }); $module->addHandler(M_DESTROY_WINDOW, sub { my ($module, $event) = @_; delete $window{$event->_win_id}; }); $module->addHandler(M_WINDOW_NAME, sub { my ($module, $event) = @_; $window{$event->_win_id}->{name} = $event->_name; }); $module->addHandler(M_ICONIFY, sub { my ($module, $event) = @_; $window{$event->_win_id}->{iconic} = 1; }); $module->addHandler(M_DEICONIFY, sub { my ($module, $event) = @_; $window{$event->_win_id}->{iconic} = 0; }); $module->addHandler(M_MINI_ICON, sub { my ($module, $event) = @_; $window{$event->_win_id}->{mini_icon} = $event->_name; }); ## does all the work and pops up the menu sub PopupMenu { my($menu_args) = @_; my @section; ## loop on list of windows foreach my $id ( keys %window ) { $module->debug("\t$id - " . $window{$id}->{name}); ## skip windows in the dontshow array my $dont_show_me; foreach ( @dontshow ) { $dont_show_me = 1, last if $window{$id}->{name} =~ /$_/; } $module->debug("\t\tin dontshow list"), next if $dont_show_me; ## skip windows not on this desk if alldesks not set $module->debug("\t\tnot on this desk"), next unless $opt->{alldesks} || ($window{$id}->{desk} == $desk); ## show only iconic windows if onlyiconic set $module->debug("\t\tskipping because not iconified"), next if $opt->{onlyiconic} && (not $window{$id}->{iconic}); ## skip window if its top left is not on this page if ( ( not $opt->{allpages} ) && ($window{$id}->{x} < 0 || $window{$id}->{x} >= $screen->{w} || $window{$id}->{y} < 0 || $window{$id}->{y} >= $screen->{h}) ) { $module->debug("\t\tnot on this page"); next; } ## loop on sections and choose which one to file in my $sectctr = 0; foreach ( @show ) { last if $window{$id}->{name} =~ /$_/ ; ++$sectctr; } ## if we got here add the window to the last section ## which is 'none of the above' $module->debug("\t\tadding to section $sectctr"); &AddToSection(\$section[$sectctr], $id); } ## tell fvwm to start the menu $module->send("DestroyMenu " . $opt->{menu}); $module->send("AddToMenu " . $opt->{menu} . " \"Desk $desk, Page +" . $page->{x} . "+" . $page->{y} . "\" Title"); ## now loop on sections sending menu entries to fvwm while ( @section ) { my $s = shift @section; if ( $s ) { $module->send($s); ## add separator after section unless this is last section $module->send("+ \"\" Nop") if ( @section ); } } ## set a menustyle if one given $module->send("ChangeMenuStyle " . $opt->{menustyle} . " " . $opt->{menu}) if $opt->{menustyle}; ## popup the menu with args we were sent $module->send("Menu " . $opt->{menu} . " " . $menu_args); } ## build a line containing the fvwm menu entry for a window ## then add it to the appropriate member of the global array @section ## args: pointer to section, window id sub AddToSection { my($s, $id) = @_; ## shorten menu entry my $entry = substr($window{$id}->{name}, 0, $opt->{maxlen}); ## add ellipses if we shortened entry $entry .= "..." if length($window{$id}->{name}) > $opt->{maxlen}; ## add window position $entry .= "\t\t(" . $window{$id}->{x} . "x" . $window{$id}->{y} . ")" if $opt->{showposition}; ## add desk number if we are in multi-desk mode $entry .= "\t(" . $window{$id}->{desk} . ")" if $opt->{alldesks}; ## add mini_icon always (opt=1) or only to iconified programs (opt=2) my $mi = ""; if ( ($opt->{mini_icon} == 1) or ($opt->{mini_icon} == 2 and $window{$id}->{iconic}) ) { $mi = "%" . $window{$id}->{mini_icon} . "%"; } ## add the entry to the section $$s .= "+ \"$entry$mi\" WindowListFunc $id\n"; } ## main loop $module->send("Send_ConfigInfo"); $module->send("Send_WindowList"); $module->eventLoop;