1 /* This program is free software; you can redistribute it and/or modify
2 * it under the terms of the GNU General Public License as published by
3 * the Free Software Foundation; either version 2 of the License, or
4 * (at your option) any later version.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 /****************************************************************************
17 * This module is all new
19 * A little of it is borrowed from ctwm.
20 * Copyright 1993 Robert Nation. No restrictions are placed on this code,
21 * as long as the copyright notice is preserved
22 ****************************************************************************/
23 /***********************************************************************
25 * fvwm window-list popup code
27 ***********************************************************************/
34 #include "libs/fvwmlib.h"
38 #include "functions.h"
44 #include "conditional.h"
47 extern FvwmWindow
*Tmp_win
;
48 extern FvwmWindow
*ButtonWindow
;
50 #define SHOW_GEOMETRY (1<<0)
51 #define SHOW_ALLDESKS (1<<1)
52 #define SHOW_NORMAL (1<<2)
53 #define SHOW_ICONIC (1<<3)
54 #define SHOW_STICKY (1<<4)
55 #define NO_DESK_SORT (1<<6)
56 #define SHOW_ICONNAME (1<<7)
57 #define SHOW_ALPHABETIC (1<<8)
58 #define SHOW_INFONOTGEO (1<<9)
59 #define SHOW_EVERYTHING (SHOW_GEOMETRY | SHOW_ALLDESKS | SHOW_NORMAL | SHOW_ICONIC | SHOW_STICKY)
61 /* Function to compare window title names
63 static int globalFlags
;
64 static int winCompare(const FvwmWindow
**a
, const FvwmWindow
**b
)
66 if(globalFlags
& SHOW_ICONNAME
)
67 return strcasecmp((*a
)->icon_name
,(*b
)->icon_name
);
69 return strcasecmp((*a
)->name
,(*b
)->name
);
74 * Change by PRB (pete@tecc.co.uk), 31/10/93. Prepend a hot key
75 * specifier to each item in the list. This means allocating the
76 * memory for each item (& freeing it) rather than just using the window
78 void do_windowList(XEvent
*eventp
,Window w
,FvwmWindow
*tmp_win
,
79 unsigned long context
, char *action
,int *Module
)
83 char* ret_action
= NULL
;
85 FvwmWindow
**windowList
;
94 int last_desk_done
= INT_MIN
;
95 int last_desk_displayed
= INT_MIN
;
97 char *t_hot
=NULL
; /* Menu label with hotkey added */
98 char scut
= '0'; /* Current short cut key */
101 int desk
= Scr
.CurrentDesk
;
102 int flags
= SHOW_EVERYTHING
;
105 char *default_action
= NULL
;
109 int low_layer
= 0; /* show all layers by default */
110 int high_layer
= INT_MAX
;
112 int show_listskip
= 0; /* do not show listskip by default */
113 Bool use_hotkey
= True
;
114 KeyCode old_sor_keycode
;
115 char sor_default_keyname
[8] = { 'M', 'e', 't', 'a', '_', 'L' };
116 char *sor_keyname
= sor_default_keyname
;
117 /* Condition vars. */
118 Bool use_condition
= False
;
119 WindowConditionMask mask
;
122 memset(&(mops
.flags
), 0, sizeof(mops
.flags
));
123 memset(&mret
, 0, sizeof(MenuReturn
));
124 if (action
&& *action
)
126 /* Look for condition - CreateFlagString returns NULL if no '(' or '[' */
127 cond_flags
= CreateFlagString(action
, &action
);
130 /* Create window mask */
131 use_condition
= True
;
132 DefaultConditionMask(&mask
);
134 /* override for Current [] */
135 mask
.my_flags
.use_circulate_hit
= 1;
136 mask
.my_flags
.use_circulate_hit_icon
= 1;
138 CreateConditionMask(cond_flags
, &mask
);
142 if (action
&& *action
)
144 /* parse postitioning args */
145 opts
= GetMenuOptions(action
, w
, tmp_win
, NULL
, NULL
, &mops
);
149 while (opts
&& *opts
)
151 opts
= GetNextSimpleOption(opts
, &tok
);
155 if (StrEquals(tok
,"NoHotkeys"))
159 else if (StrEquals(tok
,"Function"))
161 opts
= GetNextSimpleOption(opts
, &func
);
163 else if (StrEquals(tok
,"Desk"))
166 opts
= GetNextSimpleOption(opts
, &tok
);
170 flags
&= ~SHOW_ALLDESKS
;
173 else if (StrEquals(tok
,"CurrentDesk"))
175 desk
= Scr
.CurrentDesk
;
176 flags
&= ~SHOW_ALLDESKS
;
178 else if (StrEquals(tok
,"NotAlphabetic"))
179 flags
&= ~SHOW_ALPHABETIC
;
180 else if (StrEquals(tok
,"Alphabetic"))
181 flags
|= SHOW_ALPHABETIC
;
182 else if (StrEquals(tok
,"NoDeskSort"))
183 flags
|= NO_DESK_SORT
;
184 else if (StrEquals(tok
,"UseIconName"))
185 flags
|= SHOW_ICONNAME
;
186 else if (StrEquals(tok
,"NoGeometry"))
188 flags
&= ~SHOW_GEOMETRY
;
189 flags
&= ~SHOW_INFONOTGEO
;
191 else if (StrEquals(tok
,"NoGeometryWithInfo"))
193 flags
&= ~SHOW_GEOMETRY
;
194 flags
|= SHOW_INFONOTGEO
;
196 else if (StrEquals(tok
,"Geometry"))
198 flags
|= SHOW_GEOMETRY
;
199 flags
&= ~SHOW_INFONOTGEO
;
201 else if (StrEquals(tok
,"NoIcons"))
202 flags
&= ~SHOW_ICONIC
;
203 else if (StrEquals(tok
,"Icons"))
204 flags
|= SHOW_ICONIC
;
205 else if (StrEquals(tok
,"OnlyIcons"))
207 else if (StrEquals(tok
,"NoNormal"))
208 flags
&= ~SHOW_NORMAL
;
209 else if (StrEquals(tok
,"Normal"))
210 flags
|= SHOW_NORMAL
;
211 else if (StrEquals(tok
,"OnlyNormal"))
213 else if (StrEquals(tok
,"NoSticky"))
214 flags
&= ~SHOW_STICKY
;
215 else if (StrEquals(tok
,"Sticky"))
216 flags
|= SHOW_STICKY
;
217 else if (StrEquals(tok
,"OnlySticky"))
219 else if (StrEquals(tok
,"UseListSkip"))
221 else if (StrEquals(tok
,"OnlyListSkip"))
224 these are a bit dubious, but we
225 should keep the OnTop options
228 else if (StrEquals(tok
, "NoOnTop"))
230 if (high_layer
>= Scr
.TopLayer
)
231 high_layer
= Scr
.TopLayer
- 1;
233 else if (StrEquals(tok
, "OnTop"))
235 if (high_layer
< Scr
.TopLayer
)
236 high_layer
= Scr
.TopLayer
;
238 else if (StrEquals(tok
, "OnlyOnTop"))
240 high_layer
= low_layer
= Scr
.TopLayer
;
242 else if (StrEquals(tok
, "NoOnBottom"))
244 if (low_layer
<= Scr
.BottomLayer
)
245 low_layer
= Scr
.BottomLayer
- 1;
247 else if (StrEquals(tok
, "OnBottom"))
249 if (low_layer
> Scr
.BottomLayer
)
250 low_layer
= Scr
.BottomLayer
;
252 else if (StrEquals(tok
, "OnlyOnBottom"))
254 high_layer
= low_layer
= Scr
.BottomLayer
;
256 else if (StrEquals(tok
, "Layer"))
259 opts
= GetNextSimpleOption(opts
, &tok
);
262 low_layer
= high_layer
= atoi(tok
);
264 opts
= GetNextSimpleOption(opts
, &tok
);
267 high_layer
= atoi(tok
);
271 else if (StrEquals(tok
, "SelectOnRelease"))
273 if (sor_keyname
!= sor_default_keyname
)
276 opts
= GetNextSimpleOption(opts
, &sor_keyname
);
278 else if (!opts
|| !*opts
)
279 default_action
= strdup(tok
);
282 fvwm_msg(ERR
,"WindowList","Unknown option '%s'",tok
);
290 if (flags
& SHOW_GEOMETRY
)
292 sprintf(tlabel
,"Desk: %d\tGeometry",desk
);
296 sprintf(tlabel
,"Desk: %d",desk
);
298 mr
= NewMenuRoot(tlabel
);
299 AddToMenu(mr
, tlabel
, "TITLE", FALSE
, FALSE
);
302 for (t
= Scr
.FvwmRoot
.next
; t
!= NULL
; t
= t
->next
)
306 windowList
= malloc(numWindows
*sizeof(t
));
307 if (windowList
== NULL
)
311 /* get the windowlist starting from the current window (if any)*/
312 if ((t
= Scr
.Focus
) == NULL
)
313 t
= Scr
.FvwmRoot
.next
;
314 for (ii
= 0; ii
< numWindows
; ii
++)
320 t
= Scr
.FvwmRoot
.next
;
323 /* Do alphabetic sort */
324 if (flags
& SHOW_ALPHABETIC
)
325 qsort(windowList
,numWindows
,sizeof(t
),
326 (int(*)(const void*,const void*))winCompare
);
328 while(next_desk
!= INT_MAX
)
330 /* Sort window list by desktop number */
331 if((flags
& SHOW_ALLDESKS
) && !(flags
& NO_DESK_SORT
))
333 /* run through the windowlist finding the first desk not already
336 for (ii
= 0; ii
< numWindows
; ii
++)
339 if((t
->Desk
>last_desk_done
)&&(t
->Desk
< next_desk
))
343 if(!(flags
& SHOW_ALLDESKS
))
345 /* if only doing one desk and it hasn't been done */
346 if(last_desk_done
== INT_MIN
)
347 next_desk
= desk
; /* select the desk */
349 next_desk
= INT_MAX
; /* flag completion */
351 if(flags
& NO_DESK_SORT
)
352 next_desk
= INT_MAX
; /* only go through loop once */
354 last_desk_done
= next_desk
;
355 for (ii
= 0; ii
< numWindows
; ii
++)
358 if(((t
->Desk
== next_desk
) || (flags
& NO_DESK_SORT
)))
360 if (!show_listskip
&& DO_SKIP_WINDOW_LIST(t
))
361 continue; /* don't want listskip windows - skip */
362 if (show_listskip
== 2 && !DO_SKIP_WINDOW_LIST(t
))
363 continue; /* don't want no listskip one - skip */
364 if (use_condition
&& !MatchesConditionMask(t
, &mask
))
365 continue; /* doesn't match specified condition */
366 if (!(flags
& SHOW_ICONIC
) && (IS_ICONIFIED(t
)))
367 continue; /* don't want icons - skip */
368 if (!(flags
& SHOW_STICKY
) && (IS_STICKY(t
)))
369 continue; /* don't want sticky ones - skip */
370 if (!(flags
& SHOW_NORMAL
) &&
371 !((IS_ICONIFIED(t
)) || (IS_STICKY(t
))))
372 continue; /* don't want "normal" ones - skip */
373 if ((get_layer(t
) < low_layer
) || (get_layer(t
) > high_layer
))
374 continue; /* don't want this layer */
376 /* add separator between desks when geometry shown but not at the top*/
377 if (t
->Desk
!= last_desk_displayed
)
379 if (last_desk_displayed
!= INT_MIN
)
380 if ((flags
& SHOW_GEOMETRY
) || (flags
& SHOW_INFONOTGEO
))
381 AddToMenu(mr
, NULL
, NULL
, FALSE
, FALSE
);
382 last_desk_displayed
= t
->Desk
;
385 if(flags
& SHOW_ICONNAME
)
390 t_hot
= safemalloc(strlen(name
) + 48);
392 sprintf(t_hot
, "&%c. ", scut
); /* Generate label */
395 if(!(flags
& SHOW_INFONOTGEO
))
400 /* Next shortcut key */
403 else if (scut
== 'Z')
408 if (flags
& SHOW_INFONOTGEO
)
413 sprintf(loc
,"%d:", t
->Desk
);
424 else if (flags
& SHOW_GEOMETRY
)
429 sprintf(loc
,"%d(%d):",t
->Desk
, get_layer(t
));
432 dheight
= t
->frame_g
.height
- t
->title_g
.height
-2*t
->boundary_width
;
433 dwidth
= t
->frame_g
.width
- 2*t
->boundary_width
;
435 dwidth
-= t
->hints
.base_width
;
436 dheight
-= t
->hints
.base_height
;
438 dwidth
/= t
->hints
.width_inc
;
439 dheight
/= t
->hints
.height_inc
;
441 sprintf(loc
,"%d",dwidth
);
443 sprintf(loc
,"x%d",dheight
);
446 sprintf(loc
,"+%d",t
->frame_g
.x
);
448 sprintf(loc
,"%d",t
->frame_g
.x
);
451 sprintf(loc
,"+%d",t
->frame_g
.y
);
453 sprintf(loc
,"%d",t
->frame_g
.y
);
465 tfunc
= safemalloc(40);
466 sprintf(tfunc
,"WindowListFunc %lu", t
->w
);
470 tfunc
= safemalloc(strlen(func
) + 32);
471 sprintf(tfunc
,"%s %lu", func
, t
->w
);
473 AddToMenu(mr
, t_hot
, tfunc
, FALSE
, FALSE
);
476 /* Add the title pixmap */
478 MI_MINI_ICON(MR_LAST_ITEM(mr
))[0] = t
->mini_icon
;
479 t
->mini_icon
->count
++; /* increase the cache count!!
480 otherwise the pixmap will be
481 eventually removed from the
482 cache by DestroyMenu */
494 if (!default_action
&& eventp
&& eventp
->type
== KeyPress
)
495 teventp
= (XEvent
*)1;
499 /* Use the WindowList menu style is there is one */
500 change_mr_menu_style(mr
, "WindowList");
502 /* Activate select_on_release style */
503 old_sor_keycode
= MST_SELECT_ON_RELEASE_KEY(mr
);
505 (!MST_SELECT_ON_RELEASE_KEY(mr
) || sor_keyname
!= sor_default_keyname
))
511 keycode
= XKeysymToKeycode(dpy
, FvwmStringToKeysym(dpy
, sor_keyname
));
513 MST_SELECT_ON_RELEASE_KEY(mr
) =
514 XKeysymToKeycode(dpy
, FvwmStringToKeysym(dpy
, sor_keyname
));
518 mp
.parent_menu
= NULL
;
519 mp
.parent_item
= NULL
;
522 mp
.button_window
= ButtonWindow
;
525 mp
.flags
.has_default_action
= (default_action
&& *default_action
!= 0);
526 mp
.flags
.is_menu_from_frame_or_window_or_titlebar
= False
;
527 mp
.flags
.is_sticky
= True
;
528 mp
.flags
.is_submenu
= False
;
529 mp
.flags
.is_already_mapped
= False
;
532 mp
.ret_paction
= &ret_action
;
535 /* Restore old menu style */
536 MST_SELECT_ON_RELEASE_KEY(mr
) = old_sor_keycode
;
539 DestroyMenu(mr
, False
);
540 if (mret
.rc
== MENU_DOUBLE_CLICKED
&& default_action
&& *default_action
)
541 old_execute_function(
542 default_action
, tmp_win
, eventp
, context
, *Module
, 0 , NULL
);
543 if (default_action
!= NULL
)
544 free(default_action
);
546 FreeConditionMask(&mask
);