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.
6  *
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.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, see: <http://www.gnu.org/licenses/>
14  */
15 
16 #include "config.h"
17 
18 #include <limits.h>
19 #include "libs/wild.h"
20 #include "FvwmIconMan.h"
21 
22 #define HASHTAB_SIZE 257
23 
24 typedef WinList HashTab[HASHTAB_SIZE];
25 static HashTab hash_tab;
26 
print_stringlist(StringList * list)27 void print_stringlist (StringList *list)
28 {
29   StringEl *p;
30   char *s;
31 
32   ConsoleDebug (WINLIST, "\tmask = 0x%x\n", list->mask);
33   for (p = list->list; p; p = p->next) {
34     switch (p->type) {
35     case ALL_NAME:
36       s = "all";
37       break;
38 
39     case TITLE_NAME:
40       s = "title";
41       break;
42 
43     case ICON_NAME:
44       s = "icon";
45       break;
46 
47     case RESOURCE_NAME:
48       s = "resource";
49       break;
50 
51     case CLASS_NAME:
52       s = "class";
53       break;
54 
55     default:
56       s = "unknown type";
57     }
58     ConsoleDebug (WINLIST, "\t%s = %s\n", s, p->string);
59   }
60 }
61 
add_to_stringlist(StringList * list,char * s)62 void add_to_stringlist (StringList *list, char *s)
63 {
64   StringEl *new;
65   NameType type;
66   char *pat;
67 
68   ConsoleDebug (WINLIST, "In add_to_stringlist: %s\n", s);
69 
70   pat = strchr (s, '=');
71   if (pat) {
72     *pat++ = '\0';
73     if (!strcasecmp (s, "icon"))
74       type = ICON_NAME;
75     else if (!strcasecmp (s, "title"))
76       type = TITLE_NAME;
77     else if (!strcasecmp (s, "resource"))
78       type = RESOURCE_NAME;
79     else if (!strcasecmp (s, "class"))
80       type = CLASS_NAME;
81     else {
82       ConsoleMessage ("Bad element in show/dontshow list: %s\n", s);
83       return;
84     }
85   }
86   else {
87     pat = s;
88     type = ALL_NAME;
89   }
90 
91   ConsoleDebug (WINLIST, "add_to_stringlist: %s %s\n",
92 		type == ALL_NAME ? "all" : s, pat);
93 
94   new = (StringEl *)safemalloc (sizeof (StringEl));
95   new->string = (char *)safemalloc ((strlen (pat) + 1) * sizeof (char));
96   new->type = type;
97 
98   strcpy (new->string, pat);
99   new->next = list->list;
100   if (list->list)
101     list->mask |= type;
102   else
103     list->mask = type;
104   list->list = new;
105 
106   ConsoleDebug (WINLIST, "Exiting add_to_stringlist\n");
107 }
108 
matches_string(NameType type,char * pattern,char * tname,char * iname,char * rname,char * cname)109 static int matches_string (NameType type, char *pattern, char *tname,
110 			   char *iname, char *rname, char *cname)
111 {
112   int ans = 0;
113 
114   ConsoleDebug (WINLIST, "matches_string: type: 0x%x pattern: %s\n",
115 		type, pattern);
116   ConsoleDebug (WINLIST, "\tstrings: %s:%s %s:%s\n", tname, iname,
117 		rname, cname);
118 
119   if (tname && (type == ALL_NAME || type == TITLE_NAME)) {
120     ans |= matchWildcards (pattern, tname);
121   }
122   if (iname && (type == ALL_NAME || type == ICON_NAME)) {
123     ans |= matchWildcards (pattern, iname);
124   }
125   if (rname && (type == ALL_NAME || type == RESOURCE_NAME)) {
126     ans |= matchWildcards (pattern, rname);
127   }
128   if (cname && (type == ALL_NAME || type == CLASS_NAME)) {
129     ans |= matchWildcards (pattern, cname);
130   }
131 
132   ConsoleDebug (WINLIST, "\tmatches_string: %d\n", ans);
133   return ans;
134 }
135 
check_resolution(WinManager * manager,WinData * win)136 int check_resolution(WinManager *manager, WinData *win)
137 {
138   int flag = 0;
139   int reverse = 0;
140   rectangle g;
141 
142   assert (manager);
143 
144   if (IS_ICONIFIED(win) && !IS_ICON_SUPPRESSED(win))
145   {
146 	  g = win->icon_g;
147   }
148   else
149   {
150 	  g.x = win->x;
151 	  g.y = win->y;
152 	  g.width = win->width;
153 	  g.height = win->height;
154   }
155   switch (manager->res) {
156   case SHOW_GLOBAL:
157     flag = 1;
158     break;
159 
160   case NO_SHOW_DESKTOP:
161     reverse = 1;
162     /* fall through to next case */
163   case SHOW_DESKTOP:
164     if (IS_STICKY_ACROSS_PAGES(win) || win->desknum == globals.desknum)
165       flag = 1;
166     break;
167 
168   case NO_SHOW_PAGE:
169     reverse = 1;
170     /* fall through to next case */
171   case SHOW_PAGE:
172     if (IS_STICKY_ACROSS_PAGES(win)) {
173       flag = 1;
174     } else if (win->desknum == globals.desknum) {
175       /* win and screen intersect if they are not disjoint in x and y */
176       flag = fvwmrect_do_rectangles_intersect(&g, &manager->managed_g);
177     }
178     break;
179 
180   case NO_SHOW_SCREEN:
181     reverse = 1;
182     /* fall through to next case */
183   case SHOW_SCREEN:
184     if (win->desknum == globals.desknum) {
185       /* win and screen intersect if they are not disjoint in x and y */
186       flag = fvwmrect_do_rectangles_intersect(&g, &manager->managed_g);
187     }
188     break;
189   }
190   flag ^= reverse;
191 
192   return flag;
193 }
194 
iconmanager_show(WinManager * man,char * tname,char * iname,char * rname,char * cname)195 static int iconmanager_show (WinManager *man, char *tname, char *iname,
196 			     char *rname, char *cname)
197 {
198   StringEl *string;
199   int in_showlist = 0, in_dontshowlist = 0;
200 
201   assert (man);
202 
203 #ifdef FVWM_DEBUG_MSGS
204   ConsoleDebug (WINLIST, "In iconmanager_show: %s:%s : %s %s\n", tname, iname,
205 		rname, cname);
206   ConsoleDebug (WINLIST, "dontshow:\n");
207   print_stringlist (&man->dontshow);
208   ConsoleDebug (WINLIST, "show:\n");
209   print_stringlist (&man->show);
210 #endif /* FVWM_DEBUG_MSGS */
211 
212   for (string = man->dontshow.list; string; string = string->next) {
213     ConsoleDebug (WINLIST, "Matching: %s\n", string->string);
214     if (matches_string (string->type, string->string, tname, iname,
215 			rname, cname)) {
216       ConsoleDebug (WINLIST, "Don't show\n");
217       in_dontshowlist = 1;
218       break;
219     }
220   }
221 
222   if (!in_dontshowlist) {
223     if (man->show.list == NULL) {
224       in_showlist = 1;
225     }
226     else {
227       for (string = man->show.list; string; string = string->next) {
228 	ConsoleDebug (WINLIST, "Matching: %s\n", string->string);
229 	if (matches_string (string->type, string->string, tname, iname,
230 			    rname, cname)) {
231 	  ConsoleDebug (WINLIST, "Show\n");
232 	  in_showlist = 1;
233 	  break;
234 	}
235       }
236     }
237   }
238 
239   ConsoleDebug (WINLIST, "returning: %d %d %d\n", in_dontshowlist,
240 		in_showlist, !in_dontshowlist && in_showlist);
241 
242   return (!in_dontshowlist && in_showlist);
243 }
244 
new_windata(void)245 WinData *new_windata (void)
246 {
247   WinData *new = (WinData *)safemalloc (sizeof (WinData));
248 
249   memset(new, 0, sizeof(WinData));
250   new->desknum = ULONG_MAX;
251   new->x = ULONG_MAX;
252   new->y = ULONG_MAX;
253   new->app_id = ULONG_MAX;
254 
255   return new;
256 }
257 
free_windata(WinData * p)258 void free_windata (WinData *p)
259 {
260   if (globals.select_win == p) {
261     ConsoleMessage ("Internal error in free_windata\n");
262     globals.select_win = NULL;
263     abort();
264   }
265 
266   Free (p->resname);
267   Free (p->classname);
268   Free (p->iconname);
269   Free (p->titlename);
270   Free (p->display_string);
271   Free (p);
272 }
273 
274 
275 /* This ALWAYS gets called when one of the name strings changes */
276 
figure_win_manager(WinData * win,Uchar name_mask)277 WinManager *figure_win_manager (WinData *win, Uchar name_mask)
278 {
279   int i;
280   char *tname = win->titlename;
281   char *iname = win->iconname;
282   char *rname = win->resname;
283   char *cname = win->classname;
284   WinManager *man;
285 
286   assert (tname || iname || rname || cname);
287   ConsoleDebug (WINLIST, "set_win_manager: %s %s %s %s\n", tname, iname, rname, cname);
288 
289   for (i = 0, man = &globals.managers[0]; i < globals.num_managers;
290        i++, man++) {
291     if (iconmanager_show (man, tname, iname, rname, cname) &&
292 	check_resolution(man, win)) {
293       if (man != win->manager) {
294 	assert (man->magic == 0x12344321);
295       }
296       return man;
297     }
298   }
299 
300   /* No manager wants this window */
301   return NULL;
302 }
303 
check_win_complete(WinData * p)304 int check_win_complete (WinData *p)
305 {
306   if (p->complete)
307     return 1;
308 
309   ConsoleDebug (WINLIST, "Checking completeness:\n");
310   ConsoleDebug (WINLIST, "\ttitlename: %s\n",
311 		(p->titlename ? p->titlename : "No Title name"));
312   ConsoleDebug (WINLIST, "\ticonname: %s\n",
313 		(p->iconname ? p->iconname : "No Icon name"));
314   ConsoleDebug (WINLIST, "\tres: %s\n",
315 		(p->resname ? p->resname : "No p->resname"));
316   ConsoleDebug (WINLIST, "\tclass: %s\n",
317 		(p->classname ? p->classname : "No p->classname"));
318   ConsoleDebug (WINLIST, "\tdisplaystring: %s\n",
319 		(p->display_string ? p->display_string :
320 		 "No p->display_string"));
321   ConsoleDebug (WINLIST, "\t(x, y): (%ld, %ld)\n", p->x, p->y);
322   ConsoleDebug (WINLIST, "\tapp_id: 0x%lx %d\n", p->app_id, p->app_id_set);
323   ConsoleDebug (WINLIST, "\tdesknum: %ld\n", p->desknum);
324   ConsoleDebug (WINLIST, "\tmanager: 0x%lx\n", (unsigned long)p->manager);
325 
326   if (p->geometry_set &&
327       p->resname &&
328       p->classname &&
329       p->iconname &&
330       p->titlename &&
331       p->app_id_set) {
332     p->complete = 1;
333     ConsoleDebug (WINLIST, "\tcomplete: 1\n\n");
334     return 1;
335   }
336 
337   ConsoleDebug (WINLIST, "\tcomplete: 0\n\n");
338   return 0;
339 }
340 
init_winlists(void)341 void init_winlists (void)
342 {
343   int i;
344   for (i = 0; i < HASHTAB_SIZE; i++) {
345     hash_tab[i].n = 0;
346     hash_tab[i].head = NULL;
347     hash_tab[i].tail = NULL;
348   }
349 }
350 
delete_win_hashtab(WinData * win)351 void delete_win_hashtab (WinData *win)
352 {
353   int entry;
354   WinList *list;
355 
356   entry = win->app_id & 0xff;
357   list = &hash_tab[entry];
358 
359   if (win->win_prev)
360     win->win_prev->win_next = win->win_next;
361   else
362     list->head = win->win_next;
363   if (win->win_next)
364     win->win_next->win_prev = win->win_prev;
365   else
366     list->tail = win->win_prev;
367   list->n--;
368 }
369 
insert_win_hashtab(WinData * win)370 void insert_win_hashtab (WinData *win)
371 {
372   int entry;
373   WinList *list;
374   WinData *p;
375 
376   entry = win->app_id & 0xff;
377   list = &hash_tab[entry];
378 
379   for (p = list->head; p && win->app_id > p->app_id;
380        p = p->win_next);
381 
382   if (p) {
383     /* insert win before p */
384     win->win_next = p;
385     win->win_prev = p->win_prev;
386     if (p->win_prev)
387       p->win_prev->win_next = win;
388     else
389       list->head = win;
390     p->win_prev = win;
391   }
392   else {
393     /* put win at end of list */
394     win->win_next = NULL;
395     win->win_prev = list->tail;
396     if (list->tail)
397       list->tail->win_next = win;
398     else
399       list->head = win;
400     list->tail = win;
401   }
402   list->n++;
403 }
404 
find_win_hashtab(Ulong id)405 WinData *find_win_hashtab (Ulong id)
406 {
407   WinList *list;
408   int entry = id & 0xff;
409   WinData *p;
410 
411   list = &hash_tab[entry];
412 
413   for (p = list->head; p && p->app_id != id; p = p->win_next);
414 
415   return p;
416 }
417 
walk_hashtab(void (* func)(void *))418 void walk_hashtab (void (*func)(void *))
419 {
420   int i;
421   WinData *p;
422 
423   for (i = 0; i < HASHTAB_SIZE; i++) {
424     for (p = hash_tab[i].head; p; p = p->win_next)
425       func (p);
426   }
427 }
428 
accumulate_walk_hashtab(int (* func)(void *))429 int accumulate_walk_hashtab (int (*func)(void *))
430 {
431   int i, ret = 0;
432   WinData *p;
433 
434   for (i = 0; i < HASHTAB_SIZE; i++) {
435     for (p = hash_tab[i].head; p; p = p->win_next)
436       ret += func (p);
437   }
438 
439   return ret;
440 }
441