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
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
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"
42 #include "functions.h"
48 #include "menustyle.h"
50 #include "menuparameters.h"
51 #include "conditional.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
)
86 desk_name
= GetDesktopName(desk
);
87 if (desk_name
!= NULL
)
89 tlabel
= (char *)safemalloc(strlen(desk_name
)+50);
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") : "");
106 sprintf(tlabel
,"%d: %s%s", desk
, desk_name
,
107 (is_top_title
&& (flags
& SHOW_GEOMETRY
)) ?
108 _("\tGeometry") : "");
113 sprintf(tlabel
,_("Desk: %d%s"),desk
,
114 (is_top_title
&& (flags
& SHOW_GEOMETRY
)) ?
115 _("\tGeometry") : "");
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
);
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
);
154 result
= strcasecmp((*a
)->class.res_name
, (*b
)->class.res_name
);
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
);
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
);
182 result
= strcasecmp((*a
)->class.res_name
, (*b
)->class.res_name
);
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
201 void CMD_WindowList(F_CMD_ARGS
)
204 struct MenuParameters mp
;
205 char* ret_action
= NULL
;
207 FvwmWindow
**windowList
;
208 FvwmWindow
**iconifiedList
= NULL
;
214 Bool free_name
= False
;
218 int last_desk_done
= INT_MIN
;
219 int last_desk_displayed
= INT_MIN
;
221 char *t_hot
=NULL
; /* Menu label with hotkey added */
222 char scut
= '0'; /* Current short cut key */
225 int desk
= Scr
.CurrentDesk
;
226 unsigned long flags
= SHOW_DEFAULT
;
230 char *default_action
= NULL
;
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
;
247 WindowConditionMask mask
;
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 '('
264 cond_flags
= CreateFlagString(action
, &action
);
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
);
278 opts
= get_menu_options(
279 action
, w
, fw
, NULL
, NULL
, NULL
, &mops
);
280 was_get_menu_opts_called
= True
;
283 while (opts
&& *opts
)
285 opts
= GetNextSimpleOption(opts
, &tok
);
291 if (StrEquals(tok
,"NoHotkeys"))
295 else if (StrEquals(tok
,"Function"))
297 opts
= GetNextSimpleOption(opts
, &func
);
299 else if (StrEquals(tok
,"Desk"))
302 opts
= GetNextSimpleOption(opts
, &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"))
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"))
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");
450 else if (StrEquals(tok
,"UseSkipList"))
454 else if (StrEquals(tok
,"OnlyListSkip"))
456 /* deprecated as of 02-May-2007 (SS) */
457 fprintf(stderr
, "OnlyListSkip is deprecated. Please use \"OnlySkipList\".\n");
460 else if (StrEquals(tok
,"OnlySkipList"))
464 else if (StrEquals(tok
,"NoDeskNum"))
466 flags
|= NO_DESK_NUM
;
468 else if (StrEquals(tok
,"NoLayer"))
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"))
525 opts
= GetNextSimpleOption(opts
, &tok
);
528 low_layer
= high_layer
= atoi(tok
);
530 opts
= GetNextSimpleOption(opts
, &tok
);
533 high_layer
= atoi(tok
);
537 else if (StrEquals(tok
, "SelectOnRelease"))
539 if (sor_keyname
!= sor_default_keyname
)
544 opts
= GetNextSimpleOption(opts
, &sor_keyname
);
546 else if (StrEquals(tok
, "MaxLabelWidth"))
550 opts
= GetNextSimpleOption(opts
, &wid
);
553 max_label_width
= atoi(wid
);
554 if (max_label_width
< 1)
561 else if (!opts
|| !*opts
)
563 default_action
= safestrdup(tok
);
568 ERR
, "WindowList","Unknown option '%s'",
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
);
593 for (t
= Scr
.FvwmRoot
.next
; t
!= NULL
; t
= t
->next
)
597 windowList
= malloc(numWindows
*sizeof(t
));
598 if (windowList
== NULL
)
602 if (iconified_at_end
)
604 iconifiedList
= malloc(numWindows
*sizeof(t
));
605 if (iconifiedList
== NULL
)
610 /* get the windowlist starting from the current window (if any)*/
611 t
= get_focus_window();
614 t
= Scr
.FvwmRoot
.next
;
616 else if (current_at_end
)
624 t
= Scr
.FvwmRoot
.next
;
627 for (ii
= 0; ii
< numWindows
; ii
++)
629 if (flags
& SORT_REVERSE
)
631 windowList
[numWindows
- ii
- 1] = t
;
633 else if (iconified_at_end
&& IS_ICONIFIED(t
))
635 iconifiedList
[ic
++] = t
;
639 windowList
[ii
- ic
] = t
;
647 t
= Scr
.FvwmRoot
.next
;
650 if (iconified_at_end
&& ic
> 0)
652 if (current_at_end
&& ii
> ic
)
654 windowList
[numWindows
- 1] = windowList
[--ii
- ic
];
656 for (ij
= 0; ij
< ic
; ij
++)
658 windowList
[ij
+ (ii
- ic
)] = iconifiedList
[ij
];
662 /* Do alphabetic sort */
663 if (flags
& (SHOW_ALPHABETIC
| SORT_BYCLASS
| SORT_BYRESOURCE
))
665 /* This will be compare or compareReverse if a reverse order
667 int (*sort
)(const FvwmWindow
**a
, const FvwmWindow
**b
);
669 switch (flags
& (SHOW_ALPHABETIC
| SHOW_ICONNAME
| \
670 SORT_BYCLASS
| SORT_BYRESOURCE
))
672 case SHOW_ALPHABETIC
:
673 compare
= visibleCompare
;
675 case SHOW_ALPHABETIC
| SHOW_ICONNAME
:
676 compare
= iconCompare
;
678 /* Sorting based on class name produces an alphabetic
679 * order so the keyword alphabetic is redundant. */
681 case SORT_BYCLASS
| SHOW_ALPHABETIC
:
682 compare
= classCompare
;
684 case SORT_BYCLASS
| SHOW_ICONNAME
:
685 case SORT_BYCLASS
| SHOW_ICONNAME
| SHOW_ALPHABETIC
:
686 compare
= classIconCompare
;
688 case SORT_BYRESOURCE
:
689 case SORT_BYRESOURCE
| SORT_BYCLASS
:
690 case SORT_BYRESOURCE
| SORT_BYCLASS
| SHOW_ALPHABETIC
:
691 compare
= resourceCompare
;
693 case SORT_BYRESOURCE
| SHOW_ICONNAME
:
694 case SORT_BYRESOURCE
| SHOW_ICONNAME
| SORT_BYCLASS
:
695 case SORT_BYRESOURCE
| SHOW_ICONNAME
| SORT_BYCLASS
| \
697 compare
= resourceIconCompare
;
700 /* All current cases are covered, but if something
701 * changes in the future we leave compare valid even if
702 * it isn't what is expected. */
704 compare
= visibleCompare
;
708 if ( flags
& SORT_REVERSE
)
710 sort
= compareReverse
;
716 qsort(windowList
, numWindows
, sizeof(t
),
717 (int(*)(const void*, const void*))sort
);
720 while(next_desk
!= INT_MAX
)
722 /* Sort window list by desktop number */
723 if ((flags
& SHOW_ALLDESKS
) && !(flags
& NO_DESK_SORT
))
725 /* run through the windowlist finding the first desk
726 * not already processed */
728 for (ii
= 0; ii
< numWindows
; ii
++)
731 if (t
->Desk
>last_desk_done
&&
738 if (!(flags
& SHOW_ALLDESKS
))
740 /* if only doing one desk and it hasn't been done */
741 if (last_desk_done
== INT_MIN
)
742 next_desk
= desk
; /* select the desk */
744 next_desk
= INT_MAX
; /* flag completion */
746 if (flags
& NO_DESK_SORT
)
747 next_desk
= INT_MAX
; /* only go through loop once */
749 last_desk_done
= next_desk
;
750 for (ii
= 0; ii
< numWindows
; ii
++)
753 if (t
->Desk
!= next_desk
&& !(flags
& NO_DESK_SORT
))
757 if (skiplist_mode
== 0 && DO_SKIP_WINDOW_LIST(t
))
759 /* don't want skiplist windows - skip */
762 if (skiplist_mode
== 2 && !DO_SKIP_WINDOW_LIST(t
))
764 /* don't want no skiplist one - skip */
767 if (use_condition
&& !MatchesConditionMask(t
, &mask
))
769 /* doesn't match specified condition */
772 if (!(flags
& SHOW_ICONIC
) && (IS_ICONIFIED(t
)))
774 /* don't want icons - skip */
777 if (!(flags
& SHOW_STICKY_ACROSS_PAGES
) &&
778 (IS_STICKY_ACROSS_PAGES(t
)))
780 /* don't want sticky ones - skip */
783 if (!(flags
& SHOW_STICKY_ACROSS_DESKS
) &&
784 (IS_STICKY_ACROSS_DESKS(t
)))
786 /* don't want sticky ones - skip */
789 if (!(flags
& SHOW_NORMAL
) &&
791 IS_STICKY_ACROSS_PAGES(t
) ||
792 IS_STICKY_ACROSS_DESKS(t
)))
794 /* don't want "normal" ones - skip */
797 if (get_layer(t
) < low_layer
||
798 get_layer(t
) > high_layer
)
800 /* don't want this layer */
805 /* add separator between desks when geometry
806 * shown but not at the top*/
807 if (t
->Desk
!= last_desk_displayed
)
809 if (last_desk_displayed
!= INT_MIN
)
811 if (((flags
& SHOW_GEOMETRY
) ||
812 (flags
& SHOW_INFONOTGEO
)) &&
813 !(flags
& TITLE_FOR_ALL_DESKS
))
816 mr
, NULL
, NULL
, False
,
819 if (flags
& TITLE_FOR_ALL_DESKS
)
821 tlabel
= get_desk_title(
822 t
->Desk
, flags
, False
);
825 False
, False
, False
);
829 last_desk_displayed
= t
->Desk
;
831 if (first_desk
&& flags
& TITLE_FOR_ALL_DESKS
)
833 tlabel
= get_desk_title(t
->Desk
, flags
, False
);
835 mr
, tlabel
, "TITLE", False
, False
,
841 if (flags
& SHOW_ICONNAME
)
843 name
= t
->visible_icon_name
;
847 name
= t
->visible_name
;
855 else if (max_label_width
> 0 &&
856 strlen(name
) > max_label_width
)
859 name
[max_label_width
] = '\0';
863 t_hot
= safemalloc(strlen(name
) + 80);
867 sprintf(t_hot
, "&%c. ", scut
);
873 if (!(flags
& SHOW_INFONOTGEO
))
882 /* Next shortcut key */
887 else if (scut
== 'Z')
896 if (flags
& SHOW_INFONOTGEO
)
899 if (!IS_ICONIFIED(t
) &&
900 !(flags
& NO_DESK_NUM
))
902 sprintf(loc
,"%d:", t
->Desk
);
917 else if (flags
& SHOW_GEOMETRY
)
926 if (!(flags
& NO_DESK_NUM
))
928 sprintf(loc
, "%d", t
->Desk
);
931 if (flags
& SHOW_SCREEN
)
933 fscreen_scr_arg fscr
;
937 Scr
.Vx
+ t
->g
.frame
.x
+
938 t
->g
.frame
.width
/ 2;
940 Scr
.Vy
+ t
->g
.frame
.y
+
941 t
->g
.frame
.height
/ 2;
942 scr
= FScreenGetScrId(
943 &fscr
, FSCREEN_XYPOS
);
944 sprintf(loc
, "@%d", scr
);
947 if (flags
& SHOW_PAGE_X
)
950 (Scr
.Vx
+ t
->g
.frame
.x
+
951 t
->g
.frame
.width
/ 2) /
955 if (flags
& SHOW_PAGE_Y
)
958 (Scr
.Vy
+ t
->g
.frame
.y
+
959 t
->g
.frame
.height
/2) /
960 Scr
.MyDisplayHeight
);
963 if (!(flags
& NO_LAYER
))
970 get_window_borders(t
, &b
);
971 dheight
= t
->g
.frame
.height
-
973 dwidth
= t
->g
.frame
.width
-
975 dwidth
-= t
->hints
.base_width
;
976 dheight
-= t
->hints
.base_height
;
977 dwidth
/= t
->hints
.width_inc
;
978 dheight
/= t
->hints
.height_inc
;
980 sprintf(loc
,"%d",dwidth
);
982 sprintf(loc
,"x%d",dheight
);
984 if (t
->g
.frame
.x
>=0)
986 sprintf(loc
,"+%d",t
->g
.frame
.x
);
990 sprintf(loc
,"%d",t
->g
.frame
.x
);
993 if (t
->g
.frame
.y
>=0)
995 sprintf(loc
,"+%d",t
->g
.frame
.y
);
999 sprintf(loc
,"%d",t
->g
.frame
.y
);
1003 if (IS_STICKY_ACROSS_PAGES(t
) ||
1004 IS_STICKY_ACROSS_DESKS(t
))
1006 strcat(tname
, " S");
1008 if (IS_ICONIFIED(t
))
1013 strcat(t_hot
,tname
);
1015 ffunc
= func
? func
: "WindowListFunc";
1016 tfunc
= safemalloc(strlen(ffunc
) + 36);
1017 /* support two ways for now: window context
1018 * (new) and window id param (old) */
1019 sprintf(tfunc
, "WindowId %lu %s %lu",
1020 FW_W(t
), ffunc
, FW_W(t
));
1022 mr
, t_hot
, tfunc
, False
, False
, False
);
1024 /* Add the title pixmap */
1025 if (FMiniIconsSupported
&& t
->mini_icon
)
1027 MI_MINI_ICON(MR_LAST_ITEM(mr
))[0] =
1029 /* increase the cache count. Otherwise the
1030 * pixmap will be eventually removed from the
1031 * cache by DestroyMenu */
1032 t
->mini_icon
->count
++;
1047 /* force current desk title */
1048 tlabel
= get_desk_title(desk
, flags
, True
);
1049 AddToMenu(mr
, tlabel
, "TITLE", False
, False
, False
);
1058 if (iconified_at_end
)
1060 free(iconifiedList
);
1062 /* Use the WindowList menu style if there is one */
1063 change_mr_menu_style(mr
, "WindowList");
1065 /* Activate select_on_release style */
1066 old_sor_keycode
= MST_SELECT_ON_RELEASE_KEY(mr
);
1068 (!MST_SELECT_ON_RELEASE_KEY(mr
) ||
1069 sor_keyname
!= sor_default_keyname
))
1071 MST_SELECT_ON_RELEASE_KEY(mr
) =
1073 dpy
, FvwmStringToKeysym(dpy
, sor_keyname
));
1076 memset(&mp
, 0, sizeof(mp
));
1078 exc2
= exc_clone_context(exc
, NULL
, 0);
1080 mp
.flags
.has_default_action
= (default_action
&& *default_action
!= 0);
1081 mp
.flags
.is_sticky
= 1;
1082 mp
.flags
.is_submenu
= 0;
1083 mp
.flags
.is_already_mapped
= 0;
1084 mp
.flags
.is_triggered_by_keypress
=
1085 (!default_action
&& exc
->x
.etrigger
->type
== KeyPress
);
1087 mp
.ret_paction
= &ret_action
;
1088 do_menu(&mp
, &mret
);
1089 /* Restore old menu style */
1090 MST_SELECT_ON_RELEASE_KEY(mr
) = old_sor_keycode
;
1095 DestroyMenu(mr
, False
, False
);
1096 if (mret
.rc
== MENU_DOUBLE_CLICKED
&&
1097 default_action
&& *default_action
)
1099 execute_function(cond_rc
, exc2
, default_action
, 0);
1101 if (default_action
!= NULL
)
1103 free(default_action
);
1107 FreeConditionMask(&mask
);
1109 if (sor_keyname
&& sor_keyname
!= sor_default_keyname
)
1113 exc_destroy_context(exc2
);