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
)
611 /* get the windowlist starting from the current window (if any)*/
612 t
= get_focus_window();
615 t
= Scr
.FvwmRoot
.next
;
617 else if (current_at_end
)
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
;
640 windowList
[ii
- ic
] = t
;
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
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
;
676 case SHOW_ALPHABETIC
| SHOW_ICONNAME
:
677 compare
= iconCompare
;
679 /* Sorting based on class name produces an alphabetic
680 * order so the keyword alphabetic is redundant. */
682 case SORT_BYCLASS
| SHOW_ALPHABETIC
:
683 compare
= classCompare
;
685 case SORT_BYCLASS
| SHOW_ICONNAME
:
686 case SORT_BYCLASS
| SHOW_ICONNAME
| SHOW_ALPHABETIC
:
687 compare
= classIconCompare
;
689 case SORT_BYRESOURCE
:
690 case SORT_BYRESOURCE
| SORT_BYCLASS
:
691 case SORT_BYRESOURCE
| SORT_BYCLASS
| SHOW_ALPHABETIC
:
692 compare
= resourceCompare
;
694 case SORT_BYRESOURCE
| SHOW_ICONNAME
:
695 case SORT_BYRESOURCE
| SHOW_ICONNAME
| SORT_BYCLASS
:
696 case SORT_BYRESOURCE
| SHOW_ICONNAME
| SORT_BYCLASS
| \
698 compare
= resourceIconCompare
;
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. */
705 compare
= visibleCompare
;
709 if ( flags
& SORT_REVERSE
)
711 sort
= compareReverse
;
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 */
729 for (ii
= 0; ii
< numWindows
; ii
++)
732 if (t
->Desk
>last_desk_done
&&
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 */
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
++)
754 if (t
->Desk
!= next_desk
&& !(flags
& NO_DESK_SORT
))
758 if (skiplist_mode
== 0 && DO_SKIP_WINDOW_LIST(t
))
760 /* don't want skiplist windows - skip */
763 if (skiplist_mode
== 2 && !DO_SKIP_WINDOW_LIST(t
))
765 /* don't want no skiplist one - skip */
768 if (use_condition
&& !MatchesConditionMask(t
, &mask
))
770 /* doesn't match specified condition */
773 if (!(flags
& SHOW_ICONIC
) && (IS_ICONIFIED(t
)))
775 /* don't want icons - skip */
778 if (!(flags
& SHOW_STICKY_ACROSS_PAGES
) &&
779 (IS_STICKY_ACROSS_PAGES(t
)))
781 /* don't want sticky ones - skip */
784 if (!(flags
& SHOW_STICKY_ACROSS_DESKS
) &&
785 (IS_STICKY_ACROSS_DESKS(t
)))
787 /* don't want sticky ones - skip */
790 if (!(flags
& SHOW_NORMAL
) &&
792 IS_STICKY_ACROSS_PAGES(t
) ||
793 IS_STICKY_ACROSS_DESKS(t
)))
795 /* don't want "normal" ones - skip */
798 if (get_layer(t
) < low_layer
||
799 get_layer(t
) > high_layer
)
801 /* don't want this layer */
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
))
817 mr
, NULL
, NULL
, False
,
820 if (flags
& TITLE_FOR_ALL_DESKS
)
822 tlabel
= get_desk_title(
823 t
->Desk
, flags
, False
);
826 False
, False
, False
);
830 last_desk_displayed
= t
->Desk
;
832 if (first_desk
&& flags
& TITLE_FOR_ALL_DESKS
)
834 tlabel
= get_desk_title(t
->Desk
, flags
, False
);
836 mr
, tlabel
, "TITLE", False
, False
,
842 if (flags
& SHOW_ICONNAME
)
844 name
= t
->visible_icon_name
;
848 name
= t
->visible_name
;
856 else if (max_label_width
> 0 &&
857 strlen(name
) > max_label_width
)
860 name
[max_label_width
] = '\0';
864 t_hot
= safemalloc(strlen(name
) + 80);
868 sprintf(t_hot
, "&%c. ", scut
);
874 if (!(flags
& SHOW_INFONOTGEO
))
883 /* Next shortcut key */
888 else if (scut
== 'Z')
897 if (flags
& SHOW_INFONOTGEO
)
900 if (!IS_ICONIFIED(t
) &&
901 !(flags
& NO_DESK_NUM
))
903 sprintf(loc
,"%d:", t
->Desk
);
918 else if (flags
& SHOW_GEOMETRY
)
927 if (!(flags
& NO_DESK_NUM
))
929 sprintf(loc
, "%d", t
->Desk
);
932 if (flags
& SHOW_SCREEN
)
934 fscreen_scr_arg fscr
;
938 Scr
.Vx
+ t
->g
.frame
.x
+
939 t
->g
.frame
.width
/ 2;
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
);
948 if (flags
& SHOW_PAGE_X
)
951 (Scr
.Vx
+ t
->g
.frame
.x
+
952 t
->g
.frame
.width
/ 2) /
956 if (flags
& SHOW_PAGE_Y
)
959 (Scr
.Vy
+ t
->g
.frame
.y
+
960 t
->g
.frame
.height
/2) /
961 Scr
.MyDisplayHeight
);
964 if (!(flags
& NO_LAYER
))
971 get_window_borders(t
, &b
);
972 dheight
= t
->g
.frame
.height
-
974 dwidth
= t
->g
.frame
.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
);
984 sprintf(loc
,"x%d",dheight
);
986 if (t
->g
.frame
.x
>=0)
988 sprintf(loc
,"+%d",t
->g
.frame
.x
);
992 sprintf(loc
,"%d",t
->g
.frame
.x
);
995 if (t
->g
.frame
.y
>=0)
997 sprintf(loc
,"+%d",t
->g
.frame
.y
);
1001 sprintf(loc
,"%d",t
->g
.frame
.y
);
1005 if (IS_STICKY_ACROSS_PAGES(t
) ||
1006 IS_STICKY_ACROSS_DESKS(t
))
1008 strcat(tname
, " S");
1010 if (IS_ICONIFIED(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
));
1024 mr
, t_hot
, tfunc
, False
, False
, False
);
1026 /* Add the title pixmap */
1027 if (FMiniIconsSupported
&& t
->mini_icon
)
1029 MI_MINI_ICON(MR_LAST_ITEM(mr
))[0] =
1031 /* increase the cache count. Otherwise the
1032 * pixmap will be eventually removed from the
1033 * cache by DestroyMenu */
1034 t
->mini_icon
->count
++;
1049 /* force current desk title */
1050 tlabel
= get_desk_title(desk
, flags
, True
);
1051 AddToMenu(mr
, tlabel
, "TITLE", False
, False
, False
);
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
);
1070 (!MST_SELECT_ON_RELEASE_KEY(mr
) ||
1071 sor_keyname
!= sor_default_keyname
))
1073 MST_SELECT_ON_RELEASE_KEY(mr
) =
1075 dpy
, FvwmStringToKeysym(dpy
, sor_keyname
));
1078 memset(&mp
, 0, sizeof(mp
));
1080 exc2
= exc_clone_context(exc
, NULL
, 0);
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
);
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
;
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
);
1109 FreeConditionMask(&mask
);
1111 if (sor_keyname
&& sor_keyname
!= sor_default_keyname
)
1115 exc_destroy_context(exc2
);