Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 646 lines (513 sloc) 12.41 kb
3d12c94 Initial revision
bernd authored
1 /*
2 * calmwm - the calm window manager
3 *
4 * Copyright (c) 2004 Andy Adamson <dros@monkey.org>
5 * Copyright (c) 2004,2005 Marius Aamodt Eriksen <marius@monkey.org>
e5cabb0 - Remove the "all rights reserved" tag at the top of most of the source
oga authored
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3d12c94 Initial revision
bernd authored
18 *
19 * $Id$
20 */
21
22 #include "headers.h"
23 #include "calmwm.h"
24
25 #define CALMWM_NGROUPS 9
26
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
27 int Groupmode = 0;
28 int Groupnamemode = 0;
29 struct group_ctx *Group_active = NULL;
30 struct group_ctx *Group_current = NULL;
31 struct group_ctx Groups[CALMWM_NGROUPS];
32 char Group_name[256];
33 int Groupfocusset = 0;
34 Window Groupfocuswin;
35 int Groupfocusrevert;
36 int Grouphideall = 0;
37 struct group_ctx_q Groupq;
3d12c94 Initial revision
bernd authored
38
39 #define GroupMask (KeyPressMask|ExposureMask)
40
41 static char *shortcut_to_name[] = {
42 "XXX", "one", "two", "three",
43 "four", "five", "six", "seven",
44 "eight", "nine",
45 };
46
47 static void
48 _group_add(struct group_ctx *gc, struct client_ctx *cc)
49 {
50 if (cc == NULL || gc == NULL)
51 errx(1, "_group_add: a ctx is NULL");
52
53 if (cc->group == gc)
54 return;
55
56 if (cc->group != NULL)
57 TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
58
59 TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
60 cc->group = gc;
61 cc->groupcommit = 0;
62 }
63
64 static void
65 _group_remove(struct client_ctx *cc)
66 {
67 if (cc == NULL || cc->group == NULL)
68 errx(1, "_group_remove: a ctx is NULL");
69
70 TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
71 cc->group = NULL;
72 cc->groupcommit = 0;
73 cc->highlight = 0;
74 client_draw_border(cc);
75 }
76
77 static void
78 _group_commit(struct group_ctx *gc)
79 {
80 struct client_ctx *cc;
81
82 if (gc == NULL)
83 errx(1, "_group_commit: ctx is null");
84
85 TAILQ_FOREACH(cc, &gc->clients, group_entry)
86 cc->groupcommit = 1;
87 }
88
89 static void
90 _group_purge(struct group_ctx *gc)
91 {
92 struct client_ctx *cc;
93
94 if (gc == NULL)
95 errx(1, "_group_commit: ctx is null");
96
97 TAILQ_FOREACH(cc, &gc->clients, group_entry)
98 if (cc->groupcommit == 0)
99 _group_remove(cc);
100 }
101
102
103 static void
104 _group_hide(struct group_ctx *gc)
105 {
106 struct client_ctx *cc;
107
108 screen_updatestackingorder();
109
110 gc->nhidden = 0;
111 gc->highstack = 0;
112 TAILQ_FOREACH(cc, &gc->clients, group_entry) {
113 client_hide(cc);
114 gc->nhidden++;
115 if (cc->stackingorder > gc->highstack)
116 gc->highstack = cc->stackingorder;
117 }
118 gc->hidden = 1; /* XXX: equivalent to gc->nhidden > 0 */
119 }
120
121 static void
122 _group_show(struct group_ctx *gc)
123 {
124 struct client_ctx *cc;
125 Window *winlist;
126 u_int i;
127 int lastempty = -1;
128
129 winlist = (Window *) xcalloc(sizeof(*winlist) * (gc->highstack + 1));
130
131 /*
132 * Invert the stacking order as XRestackWindows() expects them
133 * top-to-bottom.
134 */
135 TAILQ_FOREACH(cc, &gc->clients, group_entry) {
136 winlist[gc->highstack - cc->stackingorder] = cc->pwin;
137 client_unhide(cc);
138 }
139
140 /* Un-sparseify */
141 for (i = 0; i <= gc->highstack; i++) {
142 if (!winlist[i] && lastempty == -1)
143 lastempty = i;
144 else if (winlist[i] && lastempty != -1) {
145 winlist[lastempty] = winlist[i];
146 if (++lastempty == i)
147 lastempty = -1;
148 }
149 }
150
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
151 XRestackWindows(X_Dpy, winlist, gc->nhidden);
3d12c94 Initial revision
bernd authored
152 xfree(winlist);
153
154 gc->hidden = 0;
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
155 Group_active = gc;
3d12c94 Initial revision
bernd authored
156 }
157
158
159
160 static void
161 _group_destroy(struct group_ctx *gc)
162 {
163 struct client_ctx *cc;
164
165 if (gc->name != NULL) {
166 xfree(gc->name);
167 gc->name = NULL;
168 }
169
170 while ((cc = TAILQ_FIRST(&gc->clients)) != NULL) {
171 TAILQ_REMOVE(&gc->clients, cc, group_entry);
172 cc->group = NULL;
173 cc->groupcommit = 0;
174 cc->highlight = 0;
175 client_draw_border(cc);
176 }
177 }
178
179 void
180 group_init(void)
181 {
182 int i;
183
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
184 TAILQ_INIT(&Groupq);
3d12c94 Initial revision
bernd authored
185
186 for (i = 0; i < CALMWM_NGROUPS; i++) {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
187 TAILQ_INIT(&Groups[i].clients);
188 Groups[i].hidden = 0;
189 Groups[i].shortcut = i + 1;
190 TAILQ_INSERT_TAIL(&Groupq, &Groups[i], entry);
3d12c94 Initial revision
bernd authored
191 }
192
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
193 Group_current = Group_active = &Groups[0];
3d12c94 Initial revision
bernd authored
194 }
195
196 /*
197 * manipulate the 'current group'
198 */
199
200 #if 0
201 /* set current group to the first empty group
202 * returns 0 on success, -1 if there are no empty groups
203 */
204 int
205 group_new(void)
206 {
207 int i;
208
209 for (i=0; i < CALMWM_NGROUPS; i++) {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
210 if (TAILQ_EMPTY(&Groups[i].clients)) {
211 Group_current = &Groups[i];
3d12c94 Initial revision
bernd authored
212
213 return (0);
214 }
215 }
216
217 return (-1);
218 }
219 #endif
220
221 /* change the current group */
222 int
223 group_select(int idx)
224 {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
225 struct group_ctx *gc = Group_current;
3d12c94 Initial revision
bernd authored
226 struct client_ctx *cc;
227
228 if (idx < 0 || idx >= CALMWM_NGROUPS)
229 return (-1);
230
231 TAILQ_FOREACH(cc, &gc->clients, group_entry) {
232 cc->highlight = 0;
233 client_draw_border(cc);
234 }
235
236 _group_commit(gc);
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
237 Group_current = &Groups[idx];
3d12c94 Initial revision
bernd authored
238
239 group_display_draw(screen_current());
240 return (0);
241 }
242
243 /* enter group mode */
244 void
245 group_enter(void)
246 {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
247 if (Groupmode != 0)
3d12c94 Initial revision
bernd authored
248 errx(1, "group_enter called twice");
249
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
250 if (Group_current == NULL)
251 Group_current = &Groups[0];
3d12c94 Initial revision
bernd authored
252
253 /* setup input buffer */
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
254 Group_name[0] = '\0';
3d12c94 Initial revision
bernd authored
255
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
256 Groupmode = 1;
3d12c94 Initial revision
bernd authored
257
258 group_display_init(screen_current());
259 group_display_draw(screen_current());
260 }
261
262 /* exit group mode */
263 void
264 group_exit(int commit)
265 {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
266 struct group_ctx *gc = Group_current;
3d12c94 Initial revision
bernd authored
267 struct client_ctx *cc;
268
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
269 if (Groupmode != 1)
3d12c94 Initial revision
bernd authored
270 errx(1, "group_exit called twice");
271
272 TAILQ_FOREACH(cc, &gc->clients, group_entry) {
273 cc->highlight = 0;
274 client_draw_border(cc);
275 }
276
277 if (commit) {
278 _group_commit(gc);
279 } else {
280 /* abort */
281 _group_purge(gc);
282 if (!TAILQ_EMPTY(&gc->clients))
283 _group_destroy(gc);
284 }
285
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
286 XUnmapWindow(X_Dpy, screen_current()->groupwin);
3d12c94 Initial revision
bernd authored
287
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
288 if (Groupnamemode) {
289 XSetInputFocus(X_Dpy, Groupfocuswin, Groupfocusrevert,
3d12c94 Initial revision
bernd authored
290 CurrentTime);
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
291 Groupfocusset = 0;
3d12c94 Initial revision
bernd authored
292 }
293
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
294 Groupmode = Groupnamemode = 0;
3d12c94 Initial revision
bernd authored
295 }
296
297 void
298 group_click(struct client_ctx *cc)
299 {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
300 struct group_ctx *gc = Group_current;
3d12c94 Initial revision
bernd authored
301
302 if (gc == cc->group)
303 _group_remove(cc);
304 else
305 _group_add(gc, cc);
306 group_display_draw(screen_current());
307 }
308
309
310 /* Used to add a newly mapped window to the active group */
311
312 void
313 group_sticky(struct client_ctx *cc)
314 {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
315 _group_add(Group_active, cc);
3d12c94 Initial revision
bernd authored
316 }
317
318 void
319 group_sticky_toggle_enter(struct client_ctx *cc)
320 {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
321 struct group_ctx *gc = Group_active;
3d12c94 Initial revision
bernd authored
322
323 if (gc == cc->group) {
324 _group_remove(cc);
325 cc->highlight = CLIENT_HIGHLIGHT_RED;
326 } else {
327 _group_add(gc, cc);
328 cc->highlight = CLIENT_HIGHLIGHT_BLUE;
329 }
330
331 client_draw_border(cc);
332 }
333
334 void
335 group_sticky_toggle_exit(struct client_ctx *cc)
336 {
337 cc->highlight = 0;
338 client_draw_border(cc);
339 }
340
341 /*
342 * selection list display
343 */
344
345 void
346 group_display_init(struct screen_ctx *sc)
347 {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
348 sc->groupwin = XCreateSimpleWindow(X_Dpy, sc->rootwin, 0, 0,
3d12c94 Initial revision
bernd authored
349 1, 1, 1, sc->blackpixl, sc->whitepixl);
350 }
351
352 void
353 group_display_draw(struct screen_ctx *sc)
354 {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
355 struct group_ctx *gc = Group_current;
3d12c94 Initial revision
bernd authored
356 int x, y, dx, dy, fontheight, titlelen;
357 struct client_ctx *cc;
358 char titlebuf[1024];
359 struct fontdesc *font = DefaultFont;
360
361 snprintf(titlebuf, sizeof(titlebuf), "Editing group %d", gc->shortcut);
362
363 x = y = 0;
364
365 fontheight = font_ascent(font) + font_descent(font) + 1;
366 dx = titlelen = font_width(font, titlebuf, strlen(titlebuf));
367 dy = fontheight;
368
369 TAILQ_FOREACH(cc, &gc->clients, group_entry) {
370 cc->highlight = CLIENT_HIGHLIGHT_BLUE;
371 client_draw_border(cc);
372 }
373
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
374 XMoveResizeWindow(X_Dpy, sc->groupwin, x, y, dx, dy);
3d12c94 Initial revision
bernd authored
375
376 /* XXX */
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
377 XSelectInput(X_Dpy, sc->groupwin, GroupMask);
3d12c94 Initial revision
bernd authored
378
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
379 XMapRaised(X_Dpy, sc->groupwin);
380 XClearWindow(X_Dpy, sc->groupwin);
3d12c94 Initial revision
bernd authored
381 font_draw(font, titlebuf, strlen(titlebuf), sc->groupwin,
382 0, font_ascent(font) + 1);
383 }
384
385 void
386 group_display_keypress(KeyCode k)
387 {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
388 struct group_ctx * gc = Group_current;
3d12c94 Initial revision
bernd authored
389 char chr;
390 enum ctltype ctl;
391 int len;
392
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
393 if (!Groupnamemode)
3d12c94 Initial revision
bernd authored
394 return;
395
396 if (input_keycodetrans(k, 0, &ctl, &chr, 1) < 0)
397 goto out;
398
399 switch (ctl) {
400 case CTL_ERASEONE:
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
401 if ((len = strlen(Group_name)) > 0)
402 Group_name[len - 1] = '\0';
3d12c94 Initial revision
bernd authored
403 break;
404 case CTL_RETURN:
405 if (gc->name != NULL)
406 xfree(gc->name);
407
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
408 gc->name = xstrdup(Group_name);
3d12c94 Initial revision
bernd authored
409
410 group_exit(1);
411 return;
412 default:
413 break;
414 }
415
416 if (chr != '\0')
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
417 snprintf(Group_name, sizeof(Group_name), "%s%c",
418 Group_name, chr);
3d12c94 Initial revision
bernd authored
419
420 out:
421 group_display_draw(screen_current());
422 }
423
424 /* if group_hidetoggle would produce no effect, toggle the group's hidden state
425 */
426 void
427 _group_fix_hidden_state(struct group_ctx *gc)
428 {
429 struct client_ctx *cc;
430 int same = 0;
431
432 TAILQ_FOREACH(cc, &gc->clients, group_entry) {
433 if (gc->hidden == ((cc->flags & CLIENT_HIDDEN) ? 1 : 0))
434 same++;
435 }
436
437 if (same == 0)
438 gc->hidden = !gc->hidden;
439 }
440
441 void
442 group_hidetoggle(int idx)
443 {
444 struct group_ctx *gc;
445 #ifdef notyet
446 char buf[128];
447 #endif
448
449 if (idx < 0 || idx >= CALMWM_NGROUPS)
450 err(1, "group_hidetoggle: index out of range (%d)", idx);
451
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
452 gc = &Groups[idx];
3d12c94 Initial revision
bernd authored
453
454 _group_fix_hidden_state(gc);
455
456 if (gc->hidden)
457 _group_show(gc);
458 else {
459 _group_hide(gc);
460 if (TAILQ_EMPTY(&gc->clients))
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
461 Group_active = gc;
3d12c94 Initial revision
bernd authored
462 }
463
464 #ifdef notyet
465 snprintf(buf, sizeof(buf), "Group %d", idx + 1);
466 screen_infomsg(buf);
467 #endif
468 }
469
470 #define GROUP_NEXT(gc, fwd) (fwd) ? \
471 TAILQ_NEXT(gc, entry) : TAILQ_PREV(gc, group_ctx_q, entry)
472
473 /*
474 * Jump to the next/previous active group. If none exist, then just
475 * stay put.
476 */
477 void
478 group_slide(int fwd)
479 {
480 struct group_ctx *gc, *showgroup = NULL;
481
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
482 assert(Group_active != NULL);
3d12c94 Initial revision
bernd authored
483
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
484 gc = Group_active;
3d12c94 Initial revision
bernd authored
485 for (;;) {
486 gc = GROUP_NEXT(gc, fwd);
487 if (gc == NULL)
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
488 gc = fwd ? TAILQ_FIRST(&Groupq) :
489 TAILQ_LAST(&Groupq, group_ctx_q);
490 if (gc == Group_active)
3d12c94 Initial revision
bernd authored
491 break;
492
493 if (!TAILQ_EMPTY(&gc->clients) && showgroup == NULL)
494 showgroup = gc;
495 else if (!gc->hidden)
496 _group_hide(gc);
497 }
498
499 if (showgroup == NULL)
500 return;
501
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
502 _group_hide(Group_active);
3d12c94 Initial revision
bernd authored
503
504 if (showgroup->hidden)
505 _group_show(showgroup);
506 else
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
507 Group_active = showgroup;
3d12c94 Initial revision
bernd authored
508 }
509
510 /* called when a client is deleted */
511 void
512 group_client_delete(struct client_ctx *cc)
513 {
514 if (cc->group == NULL)
515 return;
516
517 TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
518 cc->group = NULL; /* he he */
519 cc->groupcommit = 0;
520 }
521
522 void
523 group_menu(XButtonEvent *e)
524 {
525 struct menu_q menuq;
526 struct menu *mi;
527 int i;
528 struct group_ctx *gc;
529
530 TAILQ_INIT(&menuq);
531
532 for (i = 0; i < CALMWM_NGROUPS; i++) {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
533 gc = &Groups[i];
3d12c94 Initial revision
bernd authored
534
535 if (TAILQ_EMPTY(&gc->clients))
536 continue;
537
538 if (gc->name == NULL)
539 gc->name = xstrdup(shortcut_to_name[gc->shortcut]);
540
541 XCALLOC(mi, struct menu);
542 if (gc->hidden)
543 snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
544 gc->shortcut, gc->name);
545 else
546 snprintf(mi->text, sizeof(mi->text), "%d: %s",
547 gc->shortcut, gc->name);
548 mi->ctx = gc;
549 TAILQ_INSERT_TAIL(&menuq, mi, entry);
550 }
551
552 if (TAILQ_EMPTY(&menuq))
553 return;
554
555 mi = (struct menu *)grab_menu(e, &menuq);
556
557 if (mi == NULL || mi->ctx == NULL)
558 goto cleanup;
559
560 gc = (struct group_ctx *)mi->ctx;
561
562 if (gc->hidden)
563 _group_show(gc);
564 else
565 _group_hide(gc);
566
567 cleanup:
568 while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
569 TAILQ_REMOVE(&menuq, mi, entry);
570 xfree(mi);
571 }
572 }
573
574 void
575 group_namemode(void)
576 {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
577 Groupnamemode = 1;
3d12c94 Initial revision
bernd authored
578
579 group_display_draw(screen_current());
580 }
581
582 void
583 group_alltoggle(void)
584 {
585 int i;
586
587 for (i=0; i < CALMWM_NGROUPS; i++) {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
588 if (Grouphideall)
589 _group_show(&Groups[i]);
3d12c94 Initial revision
bernd authored
590 else
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
591 _group_hide(&Groups[i]);
3d12c94 Initial revision
bernd authored
592 }
593
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
594 if (Grouphideall)
595 Grouphideall = 0;
3d12c94 Initial revision
bernd authored
596 else
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
597 Grouphideall = 1;
3d12c94 Initial revision
bernd authored
598 }
599
600 void
601 group_deletecurrent(void)
602 {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
603 _group_destroy(Group_current);
604 XUnmapWindow(X_Dpy, screen_current()->groupwin);
3d12c94 Initial revision
bernd authored
605
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
606 Groupmode = Groupnamemode = 0;
3d12c94 Initial revision
bernd authored
607 }
608
609 void
610 group_done(void)
611 {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
612 struct group_ctx *gc = Group_current;
3d12c94 Initial revision
bernd authored
613
614 if (gc->name != NULL)
615 xfree(gc->name);
616
617 gc->name = xstrdup(shortcut_to_name[gc->shortcut]);
618
619 group_exit(1);
620 }
621
622 void
623 group_autogroup(struct client_ctx *cc)
624 {
625 struct autogroupwin *aw;
626 struct group_ctx *gc;
627 char group[CALMWM_MAXNAMELEN];
628
629 if (cc->app_class == NULL || cc->app_name == NULL)
630 return;
631
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
632 TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
3d12c94 Initial revision
bernd authored
633 if (strcmp(aw->class, cc->app_class) == 0 &&
634 (aw->name == NULL || strcmp(aw->name, cc->app_name) == 0)) {
635 strlcpy(group, aw->group, sizeof(group));
636 break;
637 }
638 }
639
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
640 TAILQ_FOREACH(gc, &Groupq, entry) {
3d12c94 Initial revision
bernd authored
641 if (strcmp(shortcut_to_name[gc->shortcut], group) == 0)
642 _group_add(gc, cc);
643 }
644
645 }
Something went wrong with that request. Please try again.