3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 # Filter this script to pod2man to get a man page:
18 # pod2man -c "Fvwm Module" FvwmWindowMenu | nroff -man | less -e
24 use vars qw($prefix $datarootdir $datadir);
26 $datarootdir = "@datarootdir@";
27 $datadir = "@datadir@";
30 use lib "@FVWM_PERLLIBDIR@";
32 use General::Parse qw(get_token);
35 my $module_class = "FVWM::Module";
36 if ($ARGV[5] && $ARGV[5] eq "-g") {
38 eval "use FVWM::Module::Gtk;";
41 print STDERR "FvwmWindowMenu: Ignoring the -g switch\n";
45 $module_class = "FVWM::Module::Gtk";
50 # set Debug = 0 for no messages at all
51 # set Debug = 1 to see messages about window decisions
52 # set Debug = 2 to see also perllib messages about communication
53 my $module = new $module_class(
54 Name => "FvwmWindowMenu",
59 $module->debug("starting " . $module->name);
61 my $config_tracker = $module->track('ModuleConfig',
63 OnlyIconified => 'off',
70 Function => 'WindowListFunc',
71 ItemFormat => '%m%n%t%t(+%x+%y) - Desk %d',
77 DontShowResource => '',
81 my $config = $config_tracker->data;
82 my $win_tracker = $module->track("WindowList", "!stack icons names winfo");
84 $module->add_handler(M_STRING, sub {
85 my ($module, $event) = @_;
86 my ($action, $args) = get_token($event->_text);
87 return unless $action;
88 if ($action =~ /^Post|Menu|Popup$/i) {
89 PopupMenu($action, $args);
90 } elsif ($action =~ /^ShowBar$/i) {
91 if ($module_type ne "gtk") {
92 $module->debug("Not started with Gtk support", 0);
97 $module->debug("Unknown action $action", 0);
101 # does all the work and pops up the menu
103 my ($action, $args) = @_;
104 my $command = ($action =~ /^Popup$/i ? "Popup" : "Menu");
108 # loop on list of all windows
109 my $windows = $win_tracker->data;
110 while (my ($id, $w) = each %$windows) {
111 $module->debug("\twindow: " . $w->{name});
113 if ($config->{AllDesks} =~ /off/i &&
114 $w->{desk} != $win_tracker->page_info('desk_n'))
116 $module->debug("\t\tnot on this desk");
120 if ($config->{AllPages} =~ /off/i &&
121 ($w->{page_nx} != $win_tracker->page_info('page_nx') ||
122 $w->{page_ny} != $win_tracker->page_info('page_ny')))
124 $module->debug("\t\tnot on this page");
128 if ($config->{OnlyIconified} =~ /on/i && !$w->{iconified})
130 $module->debug("\t\tnot iconified");
135 if ($config->{ShowName} ne '' &&
136 $w->{name} =~ /$config->{ShowName}/i) {
138 } elsif ($config->{ShowClass} ne '' &&
139 $w->{res_class_name} =~ /$config->{ShowClass}/i) {
141 } elsif ($config->{ShowResource} ne '' &&
142 $w->{res_name} =~ /$config->{ShowResource}/i) {
148 if (($config->{DontShowName} ne '' &&
149 $w->{name} =~ /$config->{DontShowName}/i) ||
150 ($config->{DontShowClass} ne '' &&
151 $w->{res_class_name} =~ /$config->{DontShowClass}/i) ||
152 ($config->{DontShowResource} ne '' &&
153 $w->{res_name} =~ /$config->{DontShowResource}/i))
155 $module->debug("\t\tin dontshow list");
159 $module->debug("\t\tadding to section $section");
160 AddToSection(\$sections[$section], $id);
163 # tell fvwm to start the menu
164 $module->send("DestroyMenu recreate $config->{MenuName}");
165 $module->send("AddToMenu " . $config->{MenuName} . " 'Desk " .
166 $win_tracker->page_info('desk_n') . ", Page " .
167 $win_tracker->page_info('page_nx') . ' ' .
168 $win_tracker->page_info('page_ny') . "' Title");
170 # now loop on sections sending menu entries to fvwm
172 my $s = shift @sections;
176 # add separator after section unless it is the last
177 $module->send("+ \"\" Nop") if @sections;
181 # set a menustyle if one given
182 $module->send("ChangeMenuStyle $config->{MenuStyle} $config->{MenuName}")
183 if ($config->{MenuStyle} ne '');
185 # popup the menu with args we were sent
186 $module->send("$command $config->{MenuName} $args");
190 # build a line containing the fvwm menu entry for a window
191 # then add it to the appropriate member of the global array @sections
192 # args: pointer to section, window id
193 sub AddToSection ($$) {
196 my $format = $config->{ItemFormat};
197 my $w = $win_tracker->data($id);
199 # hack: insert __%__ instead of % to avoid bogus substitution later
200 $format =~ s/%%/__%____%__/g;
202 # make format string substitutions
203 $format =~ s/%t/\t/g;
204 $format =~ s/%n/&Shorten($w->{name})/ge;
205 $format =~ s/%i/&Shorten($w->{icon_name})/ge;
206 $format =~ s/%c/&Shorten($w->{res_class_name})/ge;
207 $format =~ s/%r/&Shorten($w->{res_name})/ge;
208 $format =~ s/%X/$w->{X}/g;
209 $format =~ s/%Y/$w->{Y}/g;
210 $format =~ s/%x/$w->{x}/g;
211 $format =~ s/%y/$w->{y}/g;
212 $format =~ s/%d/$w->{desk}/g;
214 # TODO: doesn't handle EWMH icons yet.
215 $format =~ s/%m// if ($w->{mini_icon_name} eq 'ewmh_mini_icon');
216 $format =~ s/%m/__%__$w->{mini_icon_name}__%__/g;
218 # %M is strange - does anyone really want this behaviour? -- SS.
219 if ($w->{iconified}) {
220 $format =~ s/%M/__%__$w->{mini_icon_name}__%__/g;
226 $format =~ s/__%__/%/g;
229 $format =~ s/"/\\"/g;
231 # add the entry to the section
232 # support two ways for now: window context (new), window id param (old)
233 $$s .= qq(+ "$format" WindowId $id $config->{Function} $id\n);
237 # shorten a string to given length and append ellipses
240 my $length = $config->{MaxLen};
242 my $r = substr($string, 0, $length);
243 $r .= "..." if length($string) > $length;
245 # For some special characters, fvwm expects a double sequence to get
246 # a literal character.
247 $r =~ s/([*&%^])/$1$1/g;
252 sub PopupTaskBar () {
253 my ($w, $h) = (180, 60);
255 my $window = new Gtk::Window('toplevel');
256 $window->set_title("FvwmWindowMenuBar");
257 $window->set_border_width(5);
258 $window->set_usize($w, $h);
260 my $screenW = $win_tracker->page_info('vp_width');
261 my $screenH = $win_tracker->page_info('vp_height');
262 $window->set_uposition(($screenW - $w) / 2, ($screenH - $h) / 2);
264 my $frame = new Gtk::Frame();
265 $window->add($frame);
266 $frame->set_shadow_type('etched_out');
268 my $vbox = new Gtk::VBox();
271 my $label = new Gtk::Label("Nothing interesting yet");
274 my $button = new Gtk::Button("Close");
276 $button->signal_connect("clicked", sub { $window->destroy; });
280 # my $win_id = $window->window->XWINDOW();
281 # $module->send("Schedule 2000 WindowId $win_id Close");
285 "Style FvwmWindowMenuBar UsePPosition, !Title, !Borders, " .
286 "StaysOnTop, WindowListSkip, CascadePlacement, SloppyFocus"
287 ) if $module_type eq "gtk";
295 # ----------------------------------------------------------------------------
299 FvwmWindowMenu - open configurable fvwm menu listing current windows
303 FvwmWindowMenu should be spawned by fvwm(1) for normal functionality.
305 Run this module from your StartFunction:
307 AddToFunc StartFunction
308 + I Module FvwmWindowMenu
312 A substitute for I<fvwm> builtin B<WindowList>, but written in Perl
313 and easy to customize. Unlike B<FvwmIconMan> or B<FvwmWinList> the
314 module does not draw its own window, but instead creates an
315 I<fvwm> menu and asks I<fvwm> to pop it up.
317 By defining a set of regular expressions, windows may
318 be sorted into sections based on a regexp matching the window
319 name, class or resource and included in the menu.
321 Similarly, another set of regular expressions can be used to exclude
324 Any windows not matching an instance of the include or exclude list will
325 be placed in the last section of the menu.
329 Run the module, supposedly from StartFunction in I<.fvwm2rc>:
331 Module FvwmWindowMenu
333 To actually invoke the menu add something like:
335 Key Menu A N SendToModule FvwmWindowMenu \
336 Post Root c c SelectOnRelease Menu
340 Mouse 2 A N SendToModule FvwmWindowMenu Popup
342 The additional parameters are any valid B<Menu> command parameters without a
343 menu name, see L<fvwm>.
345 Recognized actions are B<Post> (or its alias B<Menu>) and B<Popup>, they
346 create I<fvwm> menus and invoke them using the corresponding commands
347 B<Menu> and B<Popup>. If the module was started with "-g" switch, it
348 additionally supports B<PostBar> (not implemented yet).
350 Set module options for windows to include (Show) or exclude (DontShow).
353 *FvwmWindowMenu: ShowName pattern
354 *FvwmWindowMenu: ShowClass pattern
355 *FvwmWindowMenu: ShowResource pattern
356 *FvwmWindowMenu: DontShowName pattern
357 *FvwmWindowMenu: DontShowClass pattern
358 *FvwmWindowMenu: DontShowResource pattern
360 Pattern is a perl regular expression that will be evaluated in m// context.
365 *FvwmWindowMenu: ShowResource ^gvim
366 *FvwmWindowMenu: ShowName Galeon|Navigator|mozilla-bin|Firefox
368 will define two sections containing respectively browsers, and GVim. A third
369 section will contain all other windows.
371 To only include matching windows, add:
373 *FvwmWindowMenu: DontShowName .*
377 *FvwmWindowMenu: DontShowName ^Fvwm
378 *FvwmWindowMenu: DontShowClass Gkrellm
380 will cause the menu to ignore windows with name beginning with Fvwm
387 =item *FvwmWindowMenu: I<OnlyIconified> {on|off}
389 show only iconified windows
391 =item *FvwmWindowMenu: I<AllDesks> {on|off}
393 show windows from all desks
395 =item *FvwmWindowMenu: I<AllPages> {on|off}
397 show windows from all pages
399 =item *FvwmWindowMenu: I<MaxLen> 32
401 max length in chars of entry
403 =item *FvwmWindowMenu: I<MenuName> MyMenu
405 name of menu to popup
407 =item *FvwmWindowMenu: I<MenuStyle> MyMenuStyle
409 name of MenuStyle to apply
411 =item *FvwmWindowMenu: I<Debug> {0,1,2,3}
413 level of debug info output, 0 means no debug
415 =item *FvwmWindowMenu: I<Function> MyWindowListFunc
417 function to invoke on menu entries; defaults to WindowListFunc
419 =item *FvwmWindowMenu: I<ItemFormat> formatstring
421 how to format menu entries; substitutions are made as follows:
427 the window name, icon name, class or resource
431 the window x or y coordinates w.r.t. the page the window is on.
435 the window x or y coordinates w.r.t. the desk the window is on.
439 the window desk number
443 the window's mini-icon
447 the window's mini-icon only for iconified windows, otherwise empty
459 The format string must be quoted. The default string is
460 "%m%n%t%t(+%x+%y) - Desk %d".
466 Fancy binding of the window menu to the right windows key on some keyboards.
467 Hold this button while navigating using cursor keys, then release it.
469 CopyMenuStyle * WindowMenu
470 MenuStyle WindowMenu SelectOnRelease Super_R
471 *FvwmWindowMenu: MenuStyle WindowMenu
473 AddToFunc StartFunction I Module FvwmWindowMenu
475 Key Super_R A A SendToModule FvwmWindowMenu Post Root c c WarpTitle
479 Richard Lister <ric+lister@cns.georgetown.edu>.
481 Scott Smedley <ss@aao.gov.au>.
483 Mikhael Goikhman <migo@homemail.com>.