💾 Archived View for gemini.rmf-dev.com › repo › Vaati › cwm › files › 03f56e37d788802c875c468179a6e5… captured on 2023-01-29 at 04:31:45. Gemini links have been rewritten to link to archived content
-=-=-=-=-=-=-
0 /*
1 * calmwm - the calm window manager
2 *
3 * Copyright (c) 2004 Marius Aamodt Eriksen <marius@monkey.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 *
17 * $OpenBSD$
18 */
19
20 #include <sys/types.h>
21 #include <sys/queue.h>
22
23 #include <err.h>
24 #include <errno.h>
25 #include <fnmatch.h>
26 #include <glob.h>
27 #include <limits.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32
33 #include "calmwm.h"
34
35 #define PATH_ANY 0x0001
36 #define PATH_EXEC 0x0002
37
38 static void match_path_type(struct menu_q *, char *, int);
39 static int match_substr(char *, char *, int);
40
41 static int
42 match_substr(char *sub, char *str, int zeroidx)
43 {
44 size_t len, sublen;
45 unsigned int n, flen;
46
47 if (sub == NULL || str == NULL)
48 return 0;
49
50 len = strlen(str);
51 sublen = strlen(sub);
52
53 if (sublen > len)
54 return 0;
55
56 if (zeroidx)
57 flen = 0;
58 else
59 flen = len - sublen;
60
61 for (n = 0; n <= flen; n++)
62 if (strncasecmp(sub, str + n, sublen) == 0)
63 return 1;
64
65 return 0;
66 }
67
68 void
69 search_match_client(struct menu_q *menuq, struct menu_q *resultq, char *search)
70 {
71 struct menu *mi, *tierp[3], *before = NULL;
72 struct client_ctx *cc;
73 struct winname *wn;
74
75 (void)memset(tierp, 0, sizeof(tierp));
76
77 TAILQ_INIT(resultq);
78 TAILQ_FOREACH(mi, menuq, entry) {
79 int tier = -1, t;
80 cc = (struct client_ctx *)mi->ctx;
81
82 /* Match on label. */
83 if (match_substr(search, cc->label, 0))
84 tier = 0;
85
86 /* Match on window name history, from present to past. */
87 if (tier < 0) {
88 TAILQ_FOREACH_REVERSE(wn, &cc->nameq, name_q, entry)
89 if (match_substr(search, wn->name, 0)) {
90 tier = 1;
91 break;
92 }
93 }
94
95 /* Match on window resource class. */
96 if ((tier < 0) && match_substr(search, cc->res_class, 0))
97 tier = 2;
98
99 if (tier < 0)
100 continue;
101
102 /* Current window is ranked down. */
103 if ((tier < nitems(tierp) - 1) && (cc->flags & CLIENT_ACTIVE))
104 tier++;
105
106 /* Hidden window is ranked up. */
107 if ((tier > 0) && (cc->flags & CLIENT_HIDDEN))
108 tier--;
109
110 /*
111 * If you have a tierp, insert after it, and make it
112 * the new tierp. If you don't have a tierp, find the
113 * first nonzero tierp above you, insert after it.
114 * Always make your current tierp the newly inserted
115 * entry.
116 */
117 for (t = tier; t >= 0 && ((before = tierp[t]) == NULL); t--)
118 ;
119
120 if (before == NULL)
121 TAILQ_INSERT_HEAD(resultq, mi, resultentry);
122 else
123 TAILQ_INSERT_AFTER(resultq, before, mi, resultentry);
124
125 tierp[tier] = mi;
126 }
127 }
128
129 void
130 search_match_cmd(struct menu_q *menuq, struct menu_q *resultq, char *search)
131 {
132 struct menu *mi;
133 struct cmd_ctx *cmd;
134
135 TAILQ_INIT(resultq);
136 TAILQ_FOREACH(mi, menuq, entry) {
137 cmd = (struct cmd_ctx *)mi->ctx;
138 if (match_substr(search, cmd->name, 0))
139 TAILQ_INSERT_TAIL(resultq, mi, resultentry);
140 }
141 }
142
143 void
144 search_match_group(struct menu_q *menuq, struct menu_q *resultq, char *search)
145 {
146 struct menu *mi;
147 struct group_ctx *gc;
148 char *s;
149
150 TAILQ_INIT(resultq);
151 TAILQ_FOREACH(mi, menuq, entry) {
152 gc = (struct group_ctx *)mi->ctx;
153 xasprintf(&s, "%d %s", gc->num, gc->name);
154 if (match_substr(search, s, 0))
155 TAILQ_INSERT_TAIL(resultq, mi, resultentry);
156 free(s);
157 }
158 }
159
160 static void
161 match_path_type(struct menu_q *resultq, char *search, int flag)
162 {
163 struct menu *mi;
164 char *pattern;
165 glob_t g;
166 int i;
167
168 xasprintf(&pattern, "%s*", search);
169 if (glob(pattern, GLOB_MARK, NULL, &g) != 0)
170 return;
171 for (i = 0; i < g.gl_pathc; i++) {
172 if ((flag & PATH_EXEC) && access(g.gl_pathv[i], X_OK))
173 continue;
174 mi = xcalloc(1, sizeof(*mi));
175 (void)strlcpy(mi->text, g.gl_pathv[i], sizeof(mi->text));
176 TAILQ_INSERT_TAIL(resultq, mi, resultentry);
177 }
178 globfree(&g);
179 free(pattern);
180 }
181
182 void
183 search_match_exec(struct menu_q *menuq, struct menu_q *resultq, char *search)
184 {
185 struct menu *mi, *mj;
186 int r;
187
188 TAILQ_INIT(resultq);
189 TAILQ_FOREACH(mi, menuq, entry) {
190 if (match_substr(search, mi->text, 1) == 0 &&
191 fnmatch(search, mi->text, 0) == FNM_NOMATCH)
192 continue;
193 TAILQ_FOREACH(mj, resultq, resultentry) {
194 r = strcmp(mi->text, mj->text);
195 if (r < 0)
196 TAILQ_INSERT_BEFORE(mj, mi, resultentry);
197 if (r <= 0)
198 break;
199 }
200 if (mj == NULL)
201 TAILQ_INSERT_TAIL(resultq, mi, resultentry);
202 }
203 if (TAILQ_EMPTY(resultq))
204 match_path_type(resultq, search, PATH_EXEC);
205 }
206
207 void
208 search_match_path(struct menu_q *menuq, struct menu_q *resultq, char *search)
209 {
210 TAILQ_INIT(resultq);
211 match_path_type(resultq, search, PATH_ANY);
212 }
213
214 void
215 search_match_text(struct menu_q *menuq, struct menu_q *resultq, char *search)
216 {
217 struct menu *mi;
218
219 TAILQ_INIT(resultq);
220 TAILQ_FOREACH(mi, menuq, entry) {
221 if (match_substr(search, mi->text, 0))
222 TAILQ_INSERT_TAIL(resultq, mi, resultentry);
223 }
224 }
225
226 void
227 search_match_wm(struct menu_q *menuq, struct menu_q *resultq, char *search)
228 {
229 struct menu *mi;
230 struct cmd_ctx *wm;
231
232 TAILQ_INIT(resultq);
233 TAILQ_FOREACH(mi, menuq, entry) {
234 wm = (struct cmd_ctx *)mi->ctx;
235 if ((match_substr(search, wm->name, 0)) ||
236 (match_substr(search, wm->path, 0)))
237 TAILQ_INSERT_TAIL(resultq, mi, resultentry);
238 }
239 }
240
241 void
242 search_print_client(struct menu *mi, int listing)
243 {
244 struct client_ctx *cc = (struct client_ctx *)mi->ctx;
245 char flag = ' ';
246
247 if (cc->flags & CLIENT_ACTIVE)
248 flag = '!';
249 else if (cc->flags & CLIENT_HIDDEN)
250 flag = '&';
251
252 (void)snprintf(mi->print, sizeof(mi->print), "(%d) %c[%s] %s",
253 (cc->gc) ? cc->gc->num : 0, flag,
254 (cc->label) ? cc->label : "", cc->name);
255 }
256
257 void
258 search_print_cmd(struct menu *mi, int listing)
259 {
260 struct cmd_ctx *cmd = (struct cmd_ctx *)mi->ctx;
261
262 (void)snprintf(mi->print, sizeof(mi->print), "%s", cmd->name);
263 }
264
265 void
266 search_print_group(struct menu *mi, int listing)
267 {
268 struct group_ctx *gc = (struct group_ctx *)mi->ctx;
269
270 (void)snprintf(mi->print, sizeof(mi->print),
271 (group_holds_only_hidden(gc)) ? "%d: [%s]" : "%d: %s",
272 gc->num, gc->name);
273 }
274
275 void
276 search_print_text(struct menu *mi, int listing)
277 {
278 (void)snprintf(mi->print, sizeof(mi->print), "%s", mi->text);
279 }
280
281 void
282 search_print_wm(struct menu *mi, int listing)
283 {
284 struct cmd_ctx *wm = (struct cmd_ctx *)mi->ctx;
285
286 (void)snprintf(mi->print, sizeof(mi->print), "%s [%s]",
287 wm->name, wm->path);
288 }
289