Close fd in CMD_Exec
[fvwm.git] / fvwm / windowlist.c
blob7dee3d016ea947729cfe438713cd50765393e9fd
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * This module is all new
19 * by Rob Nation
20 * A little of it is borrowed from ctwm.
21 * Copyright 1993 Robert Nation. No restrictions are placed on this code,
22 * as long as the copyright notice is preserved
26 * fvwm window-list popup code
30 #include "config.h"
32 #include <stdio.h>
33 #include <limits.h>
35 #include "libs/fvwmlib.h"
36 #include "libs/FScreen.h"
37 #include "libs/FGettext.h"
38 #include "libs/Parse.h"
39 #include "libs/Strings.h"
40 #include "fvwm.h"
41 #include "externs.h"
42 #include "functions.h"
43 #include "misc.h"
44 #include "screen.h"
45 #include "menudim.h"
46 #include "menuitem.h"
47 #include "menuroot.h"
48 #include "menustyle.h"
49 #include "menus.h"
50 #include "menuparameters.h"
51 #include "conditional.h"
52 #include "stack.h"
53 #include "focus.h"
54 #include "virtual.h"
55 #include "geometry.h"
57 #define SHOW_GEOMETRY (1<<0)
58 #define SHOW_ALLDESKS (1<<1)
59 #define SHOW_NORMAL (1<<2)
60 #define SHOW_ICONIC (1<<3)
61 #define SHOW_STICKY_ACROSS_PAGES (1<<4)
62 #define SHOW_STICKY_ACROSS_DESKS (1<<5)
63 #define NO_DESK_SORT (1<<6)
64 #define SHOW_ICONNAME (1<<7)
65 #define SHOW_ALPHABETIC (1<<8)
66 #define SORT_BYCLASS (1<<9)
67 #define SORT_BYRESOURCE (1<<10)
68 #define SORT_REVERSE (1<<11)
69 #define SHOW_INFONOTGEO (1<<12)
70 #define NO_DESK_NUM (1<<13)
71 #define NO_CURRENT_DESK_TITLE (1<<14)
72 #define TITLE_FOR_ALL_DESKS (1<<15)
73 #define NO_NUM_IN_DESK_TITLE (1<<16)
74 #define SHOW_PAGE_X (1<<17)
75 #define SHOW_PAGE_Y (1<<18)
76 #define NO_LAYER (1<<19)
77 #define SHOW_SCREEN (1<<20)
78 #define SHOW_DEFAULT (SHOW_GEOMETRY | SHOW_ALLDESKS | SHOW_NORMAL | \
79 SHOW_ICONIC | SHOW_STICKY_ACROSS_PAGES | SHOW_STICKY_ACROSS_DESKS)
81 static char *get_desk_title(int desk, unsigned long flags, Bool is_top_title)
83 char *desk_name;
84 char *tlabel;
86 desk_name = GetDesktopName(desk);
87 if (desk_name != NULL)
89 tlabel = (char *)safemalloc(strlen(desk_name)+50);
91 else
93 tlabel = (char *)safemalloc(50);
96 if (desk_name != NULL)
98 if (flags & NO_NUM_IN_DESK_TITLE)
100 sprintf(tlabel, "%s%s", desk_name,
101 (is_top_title && (flags & SHOW_GEOMETRY)) ?
102 _("\tGeometry") : "");
104 else
106 sprintf(tlabel,"%d: %s%s", desk, desk_name,
107 (is_top_title && (flags & SHOW_GEOMETRY)) ?
108 _("\tGeometry") : "");
111 else
113 sprintf(tlabel,_("Desk: %d%s"),desk,
114 (is_top_title && (flags & SHOW_GEOMETRY)) ?
115 _("\tGeometry") : "");
118 return tlabel;
121 /* Function to compare window title names */
122 static int visibleCompare(const FvwmWindow **a, const FvwmWindow **b)
124 return strcasecmp((*a)->visible_name, (*b)->visible_name);
127 static int iconCompare(const FvwmWindow **a, const FvwmWindow **b)
129 return strcasecmp((*a)->visible_icon_name, (*b)->visible_icon_name);
132 /* Which of the compare functions to sort on. */
133 static int (*compare)(const FvwmWindow **a, const FvwmWindow **b);
135 static int classCompare(const FvwmWindow **a, const FvwmWindow **b)
137 int result = strcasecmp((*a)->class.res_class, (*b)->class.res_class);
138 if (result)
140 return result;
143 return strcasecmp((*a)->visible_name, (*b)->visible_name);
146 static int resourceCompare(const FvwmWindow **a, const FvwmWindow **b)
148 int result = strcasecmp((*a)->class.res_class, (*b)->class.res_class);
149 if (result)
151 return result;
154 result = strcasecmp((*a)->class.res_name, (*b)->class.res_name);
155 if (result)
157 return result;
160 return strcasecmp((*a)->visible_name, (*b)->visible_name);
163 static int classIconCompare(const FvwmWindow **a, const FvwmWindow **b)
165 int result = strcasecmp((*a)->class.res_class, (*b)->class.res_class);
166 if (result)
168 return result;
171 return strcasecmp((*a)->visible_icon_name, (*b)->visible_icon_name);
174 static int resourceIconCompare(const FvwmWindow **a, const FvwmWindow **b)
176 int result = strcasecmp((*a)->class.res_class, (*b)->class.res_class);
177 if (result)
179 return result;
182 result = strcasecmp((*a)->class.res_name, (*b)->class.res_name);
183 if (result)
185 return result;
188 return strcasecmp((*a)->visible_icon_name, (*b)->visible_icon_name);
191 static int compareReverse(const FvwmWindow **a, const FvwmWindow **b)
193 return -compare(a, b);
197 * Change by PRB (pete@tecc.co.uk), 31/10/93. Prepend a hot key
198 * specifier to each item in the list. This means allocating the
199 * memory for each item (& freeing it) rather than just using the window
200 * title directly. */
201 void CMD_WindowList(F_CMD_ARGS)
203 struct MenuRoot *mr;
204 struct MenuParameters mp;
205 char* ret_action = NULL;
206 FvwmWindow *t;
207 FvwmWindow **windowList;
208 FvwmWindow **iconifiedList = NULL;
209 int numWindows;
210 int ii;
211 char tname[128];
212 char loc[64];
213 char *name=NULL;
214 Bool free_name = False;
215 int dwidth;
216 int dheight;
217 char *tlabel;
218 int last_desk_done = INT_MIN;
219 int last_desk_displayed = INT_MIN;
220 int next_desk = 0;
221 char *t_hot=NULL; /* Menu label with hotkey added */
222 char scut = '0'; /* Current short cut key */
223 char *opts=NULL;
224 char *tok=NULL;
225 int desk = Scr.CurrentDesk;
226 unsigned long flags = SHOW_DEFAULT;
227 char *func = NULL;
228 char *ffunc = NULL;
229 char *tfunc = NULL;
230 char *default_action = NULL;
231 MenuReturn mret;
232 MenuOptions mops;
233 int low_layer = 0; /* show all layers by default */
234 int high_layer = INT_MAX;
235 int max_label_width = 0;
236 int skiplist_mode = 0; /* do not show skiplist by default */
237 Bool use_hotkey = True;
238 KeyCode old_sor_keycode;
239 char sor_default_keyname[8] = { 'M', 'e', 't', 'a', '_', 'L' };
240 char *sor_keyname = sor_default_keyname;
241 /* Condition vars. */
242 Bool use_condition = False;
243 Bool current_at_end = False;
244 Bool iconified_at_end = False;
245 int ic = 0;
246 int ij;
247 WindowConditionMask mask;
248 char *cond_flags;
249 Bool first_desk = True;
250 Bool empty_menu = True;
251 Bool was_get_menu_opts_called = False;
252 FvwmWindow * const fw = exc->w.fw;
253 const Window w = exc->w.w;
254 const exec_context_t *exc2;
256 memset(&mops, 0, sizeof(mops));
257 memset(&mret, 0, sizeof(MenuReturn));
258 /* parse postitioning args - must call this even if no action is given
259 * because it sets the xinerama screen origin */
260 if (action && *action)
262 /* Look for condition - CreateFlagString returns NULL if no '('
263 * or '[' */
264 cond_flags = CreateFlagString(action, &action);
265 if (cond_flags)
267 /* Create window mask */
268 use_condition = True;
269 DefaultConditionMask(&mask);
271 /* override for Current [] */
272 mask.my_flags.use_circulate_hit = 1;
273 mask.my_flags.use_circulate_hit_icon = 1;
275 CreateConditionMask(cond_flags, &mask);
276 free(cond_flags);
278 opts = get_menu_options(
279 action, w, fw, NULL, NULL, NULL, &mops);
280 was_get_menu_opts_called = True;
282 /* parse options */
283 while (opts && *opts)
285 opts = GetNextSimpleOption(opts, &tok);
286 if (!tok)
288 break;
291 if (StrEquals(tok,"NoHotkeys"))
293 use_hotkey = False;
295 else if (StrEquals(tok,"Function"))
297 opts = GetNextSimpleOption(opts, &func);
299 else if (StrEquals(tok,"Desk"))
301 free(tok);
302 opts = GetNextSimpleOption(opts, &tok);
303 if (tok)
305 desk = atoi(tok);
306 flags &= ~SHOW_ALLDESKS;
309 else if (StrEquals(tok,"CurrentDesk"))
311 desk = Scr.CurrentDesk;
312 flags &= ~SHOW_ALLDESKS;
314 else if (StrEquals(tok,"NotAlphabetic"))
316 flags &= ~SHOW_ALPHABETIC;
318 else if (StrEquals(tok,"Alphabetic"))
320 flags |= SHOW_ALPHABETIC;
322 else if (StrEquals(tok,"SortByClass"))
324 flags |= SORT_BYCLASS;
326 else if (StrEquals(tok,"SortByResource"))
328 flags |= SORT_BYRESOURCE;
330 else if (StrEquals(tok,"ReverseOrder"))
332 flags |= SORT_REVERSE;
334 else if (StrEquals(tok,"CurrentAtEnd"))
336 current_at_end = True;
338 else if (StrEquals(tok,"IconifiedAtEnd"))
340 iconified_at_end = True;
342 else if (StrEquals(tok,"NoDeskSort"))
344 flags |= NO_DESK_SORT;
346 else if (StrEquals(tok,"ShowPage"))
348 flags |= SHOW_PAGE_X | SHOW_PAGE_Y;
350 else if (StrEquals(tok,"ShowPageX"))
352 flags |= SHOW_PAGE_X;
354 else if (StrEquals(tok,"ShowPageY"))
356 flags |= SHOW_PAGE_Y;
358 else if (StrEquals(tok,"ShowScreen"))
360 flags |= SHOW_SCREEN;
362 else if (StrEquals(tok,"UseIconName"))
364 flags |= SHOW_ICONNAME;
366 else if (StrEquals(tok,"NoGeometry"))
368 flags &= ~SHOW_GEOMETRY;
369 flags &= ~SHOW_INFONOTGEO;
371 else if (StrEquals(tok,"NoGeometryWithInfo"))
373 flags &= ~SHOW_GEOMETRY;
374 flags |= SHOW_INFONOTGEO;
376 else if (StrEquals(tok,"Geometry"))
378 flags |= SHOW_GEOMETRY;
379 flags &= ~SHOW_INFONOTGEO;
381 else if (StrEquals(tok,"NoIcons"))
383 flags &= ~SHOW_ICONIC;
385 else if (StrEquals(tok,"Icons"))
387 flags |= SHOW_ICONIC;
389 else if (StrEquals(tok,"OnlyIcons"))
391 flags = SHOW_ICONIC;
393 else if (StrEquals(tok,"NoNormal"))
395 flags &= ~SHOW_NORMAL;
397 else if (StrEquals(tok,"Normal"))
399 flags |= SHOW_NORMAL;
401 else if (StrEquals(tok,"OnlyNormal"))
403 flags = SHOW_NORMAL;
405 else if (StrEquals(tok,"NoSticky"))
407 flags &= ~(SHOW_STICKY_ACROSS_PAGES);
408 flags &= ~(SHOW_STICKY_ACROSS_DESKS);
410 else if (StrEquals(tok,"NoStickyPage"))
412 flags &= ~(SHOW_STICKY_ACROSS_PAGES);
414 else if (StrEquals(tok,"NoStickyDesk"))
416 flags &= ~(SHOW_STICKY_ACROSS_DESKS);
418 else if (StrEquals(tok,"Sticky"))
420 flags |= SHOW_STICKY_ACROSS_PAGES;
421 flags |= SHOW_STICKY_ACROSS_DESKS;
423 else if (StrEquals(tok,"StickyPage"))
425 flags |= SHOW_STICKY_ACROSS_PAGES;
427 else if (StrEquals(tok,"StickyDesk"))
429 flags |= SHOW_STICKY_ACROSS_DESKS;
431 else if (StrEquals(tok,"OnlySticky"))
433 flags = SHOW_STICKY_ACROSS_PAGES;
434 flags = SHOW_STICKY_ACROSS_DESKS;
436 else if (StrEquals(tok,"OnlyStickyPage"))
438 flags = SHOW_STICKY_ACROSS_PAGES;
440 else if (StrEquals(tok,"OnlyStickyDesk"))
442 flags = SHOW_STICKY_ACROSS_DESKS;
444 else if (StrEquals(tok,"UseListSkip"))
446 /* deprecated as of 02-May-2007 (SS) */
447 fprintf(stderr, "UseListSkip is deprecated. Please use \"UseSkipList\".\n");
448 skiplist_mode = 1;
450 else if (StrEquals(tok,"UseSkipList"))
452 skiplist_mode = 1;
454 else if (StrEquals(tok,"OnlyListSkip"))
456 /* deprecated as of 02-May-2007 (SS) */
457 fprintf(stderr, "OnlyListSkip is deprecated. Please use \"OnlySkipList\".\n");
458 skiplist_mode = 2;
460 else if (StrEquals(tok,"OnlySkipList"))
462 skiplist_mode = 2;
464 else if (StrEquals(tok,"NoDeskNum"))
466 flags |= NO_DESK_NUM;
468 else if (StrEquals(tok,"NoLayer"))
470 flags |= NO_LAYER;
472 else if (StrEquals(tok,"NoCurrentDeskTitle"))
474 flags |= NO_CURRENT_DESK_TITLE;
476 else if (StrEquals(tok,"TitleForAllDesks"))
478 flags |= TITLE_FOR_ALL_DESKS;
480 else if (StrEquals(tok,"NoNumInDeskTitle"))
482 flags |= NO_NUM_IN_DESK_TITLE;
484 /* these are a bit dubious, but we should keep the
485 * OnTop options for compatibility */
486 else if (StrEquals(tok, "NoOnTop"))
488 if (high_layer >= Scr.TopLayer)
490 high_layer = Scr.TopLayer - 1;
493 else if (StrEquals(tok, "OnTop"))
495 if (high_layer < Scr.TopLayer)
497 high_layer = Scr.TopLayer;
500 else if (StrEquals(tok, "OnlyOnTop"))
502 high_layer = low_layer = Scr.TopLayer;
504 else if (StrEquals(tok, "NoOnBottom"))
506 if (low_layer <= Scr.BottomLayer)
508 low_layer = Scr.BottomLayer - 1;
511 else if (StrEquals(tok, "OnBottom"))
513 if (low_layer > Scr.BottomLayer)
515 low_layer = Scr.BottomLayer;
518 else if (StrEquals(tok, "OnlyOnBottom"))
520 high_layer = low_layer = Scr.BottomLayer;
522 else if (StrEquals(tok, "Layer"))
524 free(tok);
525 opts = GetNextSimpleOption(opts, &tok);
526 if (tok)
528 low_layer = high_layer = atoi(tok);
529 free(tok);
530 opts = GetNextSimpleOption(opts, &tok);
531 if (tok)
533 high_layer = atoi(tok);
537 else if (StrEquals(tok, "SelectOnRelease"))
539 if (sor_keyname != sor_default_keyname)
541 free(sor_keyname);
543 sor_keyname = NULL;
544 opts = GetNextSimpleOption(opts, &sor_keyname);
546 else if (StrEquals(tok, "MaxLabelWidth"))
548 char *wid;
550 opts = GetNextSimpleOption(opts, &wid);
551 if (wid)
553 max_label_width = atoi(wid);
554 if (max_label_width < 1)
556 max_label_width = 1;
558 free(wid);
561 else if (!opts || !*opts)
563 default_action = safestrdup(tok);
565 else
567 fvwm_msg(
568 ERR, "WindowList","Unknown option '%s'",
569 tok);
571 if (tok)
573 free(tok);
577 if (was_get_menu_opts_called == False)
579 opts = get_menu_options(
580 action, w, fw, NULL, NULL, NULL, &mops);
583 tlabel = get_desk_title(desk, flags, True);
584 mr = NewMenuRoot(tlabel);
585 if (!(flags & NO_CURRENT_DESK_TITLE))
587 AddToMenu(mr, tlabel, "TITLE", False, False, False);
588 empty_menu = False;
590 free(tlabel);
592 numWindows = 0;
593 for (t = Scr.FvwmRoot.next; t != NULL; t = t->next)
595 numWindows++;
597 windowList = malloc(numWindows*sizeof(t));
598 if (windowList == NULL)
600 return;
602 if (iconified_at_end)
604 iconifiedList = malloc(numWindows*sizeof(t));
605 if (iconifiedList == NULL)
607 free(windowList);
608 return;
611 /* get the windowlist starting from the current window (if any)*/
612 t = get_focus_window();
613 if (t == NULL)
615 t = Scr.FvwmRoot.next;
617 else if (current_at_end)
619 if (t->next)
621 t = t->next;
623 else
625 t = Scr.FvwmRoot.next;
628 for (ii = 0; ii < numWindows; ii++)
630 if (flags & SORT_REVERSE)
632 windowList[numWindows - ii - 1] = t;
634 else if (iconified_at_end && IS_ICONIFIED(t))
636 iconifiedList[ic++] = t;
638 else
640 windowList[ii - ic] = t;
642 if (t->next)
644 t = t->next;
646 else
648 t = Scr.FvwmRoot.next;
651 if (iconified_at_end && ic > 0)
653 if (current_at_end && ii > ic)
655 windowList[numWindows - 1] = windowList[--ii - ic];
657 for (ij = 0; ij < ic; ij++)
659 windowList[ij + (ii - ic)] = iconifiedList[ij];
663 /* Do alphabetic sort */
664 if (flags & (SHOW_ALPHABETIC | SORT_BYCLASS | SORT_BYRESOURCE))
666 /* This will be compare or compareReverse if a reverse order
667 * is selected. */
668 int (*sort)(const FvwmWindow **a, const FvwmWindow **b);
670 switch (flags & (SHOW_ALPHABETIC | SHOW_ICONNAME | \
671 SORT_BYCLASS | SORT_BYRESOURCE))
673 case SHOW_ALPHABETIC:
674 compare = visibleCompare;
675 break;
676 case SHOW_ALPHABETIC | SHOW_ICONNAME:
677 compare = iconCompare;
678 break;
679 /* Sorting based on class name produces an alphabetic
680 * order so the keyword alphabetic is redundant. */
681 case SORT_BYCLASS:
682 case SORT_BYCLASS | SHOW_ALPHABETIC:
683 compare = classCompare;
684 break;
685 case SORT_BYCLASS | SHOW_ICONNAME:
686 case SORT_BYCLASS | SHOW_ICONNAME | SHOW_ALPHABETIC:
687 compare = classIconCompare;
688 break;
689 case SORT_BYRESOURCE:
690 case SORT_BYRESOURCE | SORT_BYCLASS:
691 case SORT_BYRESOURCE | SORT_BYCLASS | SHOW_ALPHABETIC:
692 compare = resourceCompare;
693 break;
694 case SORT_BYRESOURCE | SHOW_ICONNAME:
695 case SORT_BYRESOURCE | SHOW_ICONNAME | SORT_BYCLASS:
696 case SORT_BYRESOURCE | SHOW_ICONNAME | SORT_BYCLASS | \
697 SHOW_ALPHABETIC:
698 compare = resourceIconCompare;
699 break;
701 /* All current cases are covered, but if something
702 * changes in the future we leave compare valid even if
703 * it isn't what is expected. */
704 default:
705 compare = visibleCompare;
706 break;
709 if ( flags & SORT_REVERSE )
711 sort = compareReverse;
713 else
715 sort = compare;
717 qsort(windowList, numWindows, sizeof(t),
718 (int(*)(const void*, const void*))sort);
721 while(next_desk != INT_MAX)
723 /* Sort window list by desktop number */
724 if ((flags & SHOW_ALLDESKS) && !(flags & NO_DESK_SORT))
726 /* run through the windowlist finding the first desk
727 * not already processed */
728 next_desk = INT_MAX;
729 for (ii = 0; ii < numWindows; ii++)
731 t = windowList[ii];
732 if (t->Desk >last_desk_done &&
733 t->Desk < next_desk)
735 next_desk = t->Desk;
739 if (!(flags & SHOW_ALLDESKS))
741 /* if only doing one desk and it hasn't been done */
742 if (last_desk_done == INT_MIN)
743 next_desk = desk; /* select the desk */
744 else
745 next_desk = INT_MAX; /* flag completion */
747 if (flags & NO_DESK_SORT)
748 next_desk = INT_MAX; /* only go through loop once */
750 last_desk_done = next_desk;
751 for (ii = 0; ii < numWindows; ii++)
753 t = windowList[ii];
754 if (t->Desk != next_desk && !(flags & NO_DESK_SORT))
756 continue;
758 if (skiplist_mode == 0 && DO_SKIP_WINDOW_LIST(t))
760 /* don't want skiplist windows - skip */
761 continue;
763 if (skiplist_mode == 2 && !DO_SKIP_WINDOW_LIST(t))
765 /* don't want no skiplist one - skip */
766 continue;
768 if (use_condition && !MatchesConditionMask(t, &mask))
770 /* doesn't match specified condition */
771 continue;
773 if (!(flags & SHOW_ICONIC) && (IS_ICONIFIED(t)))
775 /* don't want icons - skip */
776 continue;
778 if (!(flags & SHOW_STICKY_ACROSS_PAGES) &&
779 (IS_STICKY_ACROSS_PAGES(t)))
781 /* don't want sticky ones - skip */
782 continue;
784 if (!(flags & SHOW_STICKY_ACROSS_DESKS) &&
785 (IS_STICKY_ACROSS_DESKS(t)))
787 /* don't want sticky ones - skip */
788 continue;
790 if (!(flags & SHOW_NORMAL) &&
791 !(IS_ICONIFIED(t) ||
792 IS_STICKY_ACROSS_PAGES(t) ||
793 IS_STICKY_ACROSS_DESKS(t)))
795 /* don't want "normal" ones - skip */
796 continue;
798 if (get_layer(t) < low_layer ||
799 get_layer(t) > high_layer)
801 /* don't want this layer */
802 continue;
805 empty_menu = False;
806 /* add separator between desks when geometry
807 * shown but not at the top*/
808 if (t->Desk != last_desk_displayed)
810 if (last_desk_displayed != INT_MIN)
812 if (((flags & SHOW_GEOMETRY) ||
813 (flags & SHOW_INFONOTGEO)) &&
814 !(flags & TITLE_FOR_ALL_DESKS))
816 AddToMenu(
817 mr, NULL, NULL, False,
818 False, False);
820 if (flags & TITLE_FOR_ALL_DESKS)
822 tlabel = get_desk_title(
823 t->Desk, flags, False);
824 AddToMenu(
825 mr, tlabel, "TITLE",
826 False, False, False);
827 free(tlabel);
830 last_desk_displayed = t->Desk;
832 if (first_desk && flags & TITLE_FOR_ALL_DESKS)
834 tlabel = get_desk_title(t->Desk, flags, False);
835 AddToMenu(
836 mr, tlabel, "TITLE", False, False,
837 False);
838 free(tlabel);
840 first_desk = False;
842 if (flags & SHOW_ICONNAME)
844 name = t->visible_icon_name;
846 else
848 name = t->visible_name;
851 free_name = False;
852 if (!name)
854 name = "NULL_NAME";
856 else if (max_label_width > 0 &&
857 strlen(name) > max_label_width)
859 name = strdup(name);
860 name[max_label_width] = '\0';
861 free_name = True;
864 t_hot = safemalloc(strlen(name) + 80);
865 if (use_hotkey)
867 /* Generate label */
868 sprintf(t_hot, "&%c. ", scut);
870 else
872 *t_hot = 0;
874 if (!(flags & SHOW_INFONOTGEO))
876 strcat(t_hot, name);
878 if (*t_hot == 0)
880 strcpy(t_hot, " ");
883 /* Next shortcut key */
884 if (scut == '9')
886 scut = 'A';
888 else if (scut == 'Z')
890 scut = '0';
892 else
894 scut++;
897 if (flags & SHOW_INFONOTGEO)
899 tname[0]=0;
900 if (!IS_ICONIFIED(t) &&
901 !(flags & NO_DESK_NUM))
903 sprintf(loc,"%d:", t->Desk);
904 strcat(tname,loc);
906 if (IS_ICONIFIED(t))
908 strcat(tname, "(");
910 strcat(t_hot,"\t");
911 strcat(t_hot,tname);
912 strcat(t_hot, name);
913 if (IS_ICONIFIED(t))
915 strcat(t_hot, ")");
918 else if (flags & SHOW_GEOMETRY)
920 size_borders b;
922 tname[0]=0;
923 if (IS_ICONIFIED(t))
925 strcpy(tname, "(");
927 if (!(flags & NO_DESK_NUM))
929 sprintf(loc, "%d", t->Desk);
930 strcat(tname, loc);
932 if (flags & SHOW_SCREEN)
934 fscreen_scr_arg fscr;
935 int scr;
937 fscr.xypos.x =
938 Scr.Vx + t->g.frame.x +
939 t->g.frame.width / 2;
940 fscr.xypos.y =
941 Scr.Vy + t->g.frame.y +
942 t->g.frame.height / 2;
943 scr = FScreenGetScrId(
944 &fscr, FSCREEN_XYPOS);
945 sprintf(loc, "@%d", scr);
946 strcat(tname, loc);
948 if (flags & SHOW_PAGE_X)
950 sprintf(loc, "+%d",
951 (Scr.Vx + t->g.frame.x +
952 t->g.frame.width / 2) /
953 Scr.MyDisplayWidth);
954 strcat(tname, loc);
956 if (flags & SHOW_PAGE_Y)
958 sprintf(loc, "+%d",
959 (Scr.Vy + t->g.frame.y +
960 t->g.frame.height/2) /
961 Scr.MyDisplayHeight);
962 strcat(tname, loc);
964 if (!(flags & NO_LAYER))
966 sprintf(loc, "(%d)",
967 (get_layer(t)));
968 strcat(tname, loc);
970 strcat(tname, ":");
971 get_window_borders(t, &b);
972 dheight = t->g.frame.height -
973 b.total_size.height;
974 dwidth = t->g.frame.width -
975 b.total_size.width;
977 dwidth = (dwidth - t->hints.base_width)
978 /t->orig_hints.width_inc;
979 dheight = (dheight - t->hints.base_height)
980 /t->orig_hints.height_inc;
982 sprintf(loc,"%d",dwidth);
983 strcat(tname, loc);
984 sprintf(loc,"x%d",dheight);
985 strcat(tname, loc);
986 if (t->g.frame.x >=0)
988 sprintf(loc,"+%d",t->g.frame.x);
990 else
992 sprintf(loc,"%d",t->g.frame.x);
994 strcat(tname, loc);
995 if (t->g.frame.y >=0)
997 sprintf(loc,"+%d",t->g.frame.y);
999 else
1001 sprintf(loc,"%d",t->g.frame.y);
1003 strcat(tname, loc);
1005 if (IS_STICKY_ACROSS_PAGES(t) ||
1006 IS_STICKY_ACROSS_DESKS(t))
1008 strcat(tname, " S");
1010 if (IS_ICONIFIED(t))
1012 strcat(tname, ")");
1014 strcat(t_hot,"\t");
1015 strcat(t_hot,tname);
1017 ffunc = func ? func : "WindowListFunc";
1018 tfunc = safemalloc(strlen(ffunc) + 36);
1019 /* support two ways for now: window context
1020 * (new) and window id param (old) */
1021 sprintf(tfunc, "WindowId %lu %s %lu",
1022 FW_W(t), ffunc, FW_W(t));
1023 AddToMenu(
1024 mr, t_hot, tfunc, False, False, False);
1025 free(tfunc);
1026 /* Add the title pixmap */
1027 if (FMiniIconsSupported && t->mini_icon)
1029 MI_MINI_ICON(MR_LAST_ITEM(mr))[0] =
1030 t->mini_icon;
1031 /* increase the cache count. Otherwise the
1032 * pixmap will be eventually removed from the
1033 * cache by DestroyMenu */
1034 t->mini_icon->count++;
1036 if (t_hot)
1038 free(t_hot);
1040 if (free_name)
1042 free(name);
1047 if (empty_menu)
1049 /* force current desk title */
1050 tlabel = get_desk_title(desk, flags, True);
1051 AddToMenu(mr, tlabel, "TITLE", False, False, False);
1052 free(tlabel);
1055 if (func)
1057 free(func);
1059 free(windowList);
1060 if (iconified_at_end)
1062 free(iconifiedList);
1064 /* Use the WindowList menu style if there is one */
1065 change_mr_menu_style(mr, "WindowList");
1067 /* Activate select_on_release style */
1068 old_sor_keycode = MST_SELECT_ON_RELEASE_KEY(mr);
1069 if (sor_keyname &&
1070 (!MST_SELECT_ON_RELEASE_KEY(mr) ||
1071 sor_keyname != sor_default_keyname))
1073 MST_SELECT_ON_RELEASE_KEY(mr) =
1074 XKeysymToKeycode(
1075 dpy, FvwmStringToKeysym(dpy, sor_keyname));
1078 memset(&mp, 0, sizeof(mp));
1079 mp.menu = mr;
1080 exc2 = exc_clone_context(exc, NULL, 0);
1081 mp.pexc = &exc2;
1082 mp.flags.has_default_action = (default_action && *default_action != 0);
1083 mp.flags.is_sticky = 1;
1084 mp.flags.is_submenu = 0;
1085 mp.flags.is_already_mapped = 0;
1086 mp.flags.is_triggered_by_keypress =
1087 (!default_action && exc->x.etrigger->type == KeyPress);
1088 mp.pops = &mops;
1089 mp.ret_paction = &ret_action;
1090 do_menu(&mp, &mret);
1091 /* Restore old menu style */
1092 MST_SELECT_ON_RELEASE_KEY(mr) = old_sor_keycode;
1093 if (ret_action)
1095 free(ret_action);
1097 DestroyMenu(mr, False, False);
1098 if (mret.rc == MENU_DOUBLE_CLICKED &&
1099 default_action && *default_action)
1101 execute_function(cond_rc, exc2, default_action, 0);
1103 if (default_action != NULL)
1105 free(default_action);
1107 if (use_condition)
1109 FreeConditionMask(&mask);
1111 if (sor_keyname && sor_keyname != sor_default_keyname)
1113 free(sor_keyname);
1115 exc_destroy_context(exc2);
1117 return;