1 /*
2  * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3  * Copyright (C) 2008-2020 Kim Woelders
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to
7  * deal in the Software without restriction, including without limitation the
8  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9  * sell copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies of the Software, its documentation and marketing & publicity
14  * materials, and acknowledgment shall be given in the documentation, materials
15  * and software packages that this Software was used.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 #include "config.h"
25 
26 #include <ctype.h>
27 #include <string.h>
28 
29 #include "E.h"
30 #include "ewins.h"
31 #include "groups.h"
32 #include "util.h"
33 
34 EWin               *
EwinFindByPtr(const EWin * ewin)35 EwinFindByPtr(const EWin * ewin)
36 {
37    EWin               *const *ewins;
38    int                 i, num;
39 
40    ewins = EwinListGetAll(&num);
41    for (i = 0; i < num; i++)
42      {
43 	if (ewin == ewins[i])
44 	   return ewins[i];
45      }
46    return NULL;
47 }
48 
49 EWin               *
EwinFindByClient(EX_Window win)50 EwinFindByClient(EX_Window win)
51 {
52    EWin               *const *ewins;
53    int                 i, num;
54 
55    ewins = EwinListGetAll(&num);
56    for (i = 0; i < num; i++)
57      {
58 	if (win == EwinGetClientXwin(ewins[i]))
59 	   return ewins[i];
60      }
61    return NULL;
62 }
63 
64 EWin               *
EwinFindGroupMember(EWin * ewin)65 EwinFindGroupMember(EWin * ewin)
66 {
67    EWin               *ewin2;
68    EWin               *const *ewins;
69    int                 i, num;
70 
71    ewin2 = EwinFindByClient(ewin->icccm.group);
72    if (ewin2 && ewin2 != ewin)
73       return ewin2;
74 
75    ewins = EwinListGetAll(&num);
76    for (i = 0; i < num; i++)
77      {
78 	ewin2 = ewins[i];
79 	if (ewin2 == ewin)
80 	   continue;
81 	if (ewin2->state.iconified)
82 	   continue;
83 	if (ewin2->icccm.group == ewin->icccm.group)
84 	   return ewin2;
85      }
86 
87    return NULL;
88 }
89 
90 EWin              **
EwinsFindByExpr(const char * match,int * pnum,int * pflags)91 EwinsFindByExpr(const char *match, int *pnum, int *pflags)
92 {
93    EWin               *ewin, **lst;
94    EWin               *const *ewins;
95    int                 type;
96    int                 i, num, len, nfound, match_one, flags;
97 
98    if (pnum)
99       *pnum = 0;
100 
101    if (!match || !match[0])
102       return NULL;
103 
104    ewin = NULL;
105    flags = 0;
106 
107    if (!strcmp(match, "*") || !strcmp(match, "=") || !strcmp(match, "current"))
108      {
109 	ewin = GetContextEwin();
110 	if (!ewin)
111 	   ewin = GetFocusEwin();
112 	if (match[0] == '=')
113 	   flags = 1;		/* Nogroup */
114 	goto do_one;
115      }
116 
117    if (isdigit(match[0]))
118      {
119 	unsigned int        win;
120 
121 	sscanf(match, "%x", &win);
122 	ewin = EwinFindByClient(win);
123 	goto do_one;
124      }
125 
126    match_one = 1;
127    if (!strcmp(match, "all"))
128      {
129 	type = 'a';
130 	match_one = 0;
131 	flags = 1;		/* Nogroup */
132      }
133    else if (match[0] == '=')
134      {
135 	type = 's';
136 	match++;
137 	flags = 1;		/* Nogroup */
138      }
139    else if (strchr(match, '*'))
140      {
141 	type = 'w';
142 	match_one = 0;
143 	flags = 1;		/* Nogroup */
144      }
145    else
146      {
147 	type = 's';
148      }
149 
150    len = strlen(match);
151    if (len <= 0)
152       return NULL;
153 
154    ewins = EwinListGetAll(&num);
155    if (!ewins)
156       return NULL;
157 
158    nfound = 0;
159    lst = NULL;
160    for (i = 0; i < num; i++)
161      {
162 	ewin = ewins[i];
163 
164 	if (type == 'a')	/* All */
165 	  {
166 	  }
167 	else if (type == 'w')	/* Wildcard */
168 	  {
169 	     if (!matchregexp(match, EwinGetIcccmName(ewin)))
170 		continue;
171 	  }
172 	else			/* Match name (substring) */
173 	  {
174 	     const char         *name;
175 
176 	     name = EwinGetIcccmName(ewin);
177 	     if (!name)
178 		continue;
179 	     if (!Estrcasestr(name, match))
180 		continue;
181 	  }
182 	nfound++;
183 	lst = EREALLOC(EWin *, lst, nfound);
184 	lst[nfound - 1] = ewin;
185 	if (match_one)
186 	   break;
187      }
188    goto done;
189 
190  do_one:
191    if (!ewin)
192       return NULL;
193    nfound = 1;
194    lst = EMALLOC(EWin *, 1);
195    if (!lst)
196       return NULL;
197    lst[0] = ewin;
198 
199  done:
200    if (pnum)
201       *pnum = nfound;
202    if (pflags)
203       *pflags = flags;
204    return lst;
205 }
206 
207 EWin               *
EwinFindByExpr(const char * match)208 EwinFindByExpr(const char *match)
209 {
210    EWin               *ewin, **lst;
211 
212    lst = EwinsFindByExpr(match, NULL, NULL);
213    if (!lst)
214       return NULL;
215    ewin = lst[0];
216    Efree(lst);
217    return ewin;
218 }
219 
220 EWin              **
ListWinGroupMembersForEwin(const EWin * ewin,int action,char nogroup,int * pnum)221 ListWinGroupMembersForEwin(const EWin * ewin, int action, char nogroup,
222 			   int *pnum)
223 {
224 
225    EWin              **gwins, *ew;
226    EWin               *const *ewins;
227    Group              *grp;
228    int                 i, num, gwcnt;
229 
230    if (!ewin)
231      {
232 	*pnum = 0;
233 	return NULL;
234      }
235 
236    gwcnt = 0;
237    gwins = NULL;
238 
239    if (nogroup || ewin->num_groups <= 0)
240       goto done;
241 
242    ewins = EwinListGetAll(&num);
243    if (!ewins)			/* Should not be possible */
244       goto done;
245 
246    /* Loop through window stack, bottom up */
247    for (i = num - 1; i >= 0; i--)
248      {
249 	ew = ewins[i];
250 
251 	if (ew == ewin)
252 	   goto do_add;
253 
254 	/* To get consistent behaviour, limit groups to a single desktop for now: */
255 	if (EoGetDesk(ew) != EoGetDesk(ewin))
256 	   continue;
257 
258 	grp = EwinsInGroup(ewin, ew);
259 	if (!grp)
260 	   continue;
261 
262 	if (!GroupMatchAction(grp, action))
263 	   continue;
264 
265       do_add:
266 	gwins = EREALLOC(EWin *, gwins, gwcnt + 1);
267 	gwins[gwcnt] = ew;
268 	gwcnt++;
269      }
270 
271  done:
272    if (!gwins)
273      {
274 	gwins = EMALLOC(EWin *, 1);
275 	gwins[0] = (EWin *) ewin;
276 	gwcnt = 1;
277      }
278    *pnum = gwcnt;
279    return gwins;
280 }
281