Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 396 lines (322 sloc) 8.304 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
49e218c - add missing prototypes.
okan authored
27 static void _group_add(struct group_ctx *, struct client_ctx *);
28 static void _group_remove(struct client_ctx *);
29 static void _group_hide(struct group_ctx *);
30 static void _group_show(struct group_ctx *);
31 static void _group_fix_hidden_state(struct group_ctx *);
32
75182c6 hit it with the knf stick.
oga authored
33 struct group_ctx *Group_active = NULL;
34 struct group_ctx Groups[CALMWM_NGROUPS];
35 int Grouphideall = 0;
36 struct group_ctx_q Groupq;
3d12c94 Initial revision
bernd authored
37
d1050af shortcut_to_name should not be defined as static in a header file. Put
oga authored
38 const char *shortcut_to_name[] = {
49e218c - add missing prototypes.
okan authored
39 "nogroup", "one", "two", "three", "four", "five", "six",
40 "seven", "eight", "nine"
d1050af shortcut_to_name should not be defined as static in a header file. Put
oga authored
41 };
42
3d12c94 Initial revision
bernd authored
43 static void
44 _group_add(struct group_ctx *gc, struct client_ctx *cc)
45 {
46 if (cc == NULL || gc == NULL)
75182c6 hit it with the knf stick.
oga authored
47 errx(1, "_group_add: a ctx is NULL");
3d12c94 Initial revision
bernd authored
48
49 if (cc->group == gc)
50 return;
51
52 if (cc->group != NULL)
53 TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
54
c750462 One of the most annoying things to do was restart cwm and lose all of
oga authored
55 XChangeProperty(X_Dpy, cc->win, _CWM_GRP, XA_STRING,
56 8, PropModeReplace, gc->name, strlen(gc->name));
57
3d12c94 Initial revision
bernd authored
58 TAILQ_INSERT_TAIL(&gc->clients, cc, group_entry);
59 cc->group = gc;
60 }
61
62 static void
63 _group_remove(struct client_ctx *cc)
64 {
65 if (cc == NULL || cc->group == NULL)
75182c6 hit it with the knf stick.
oga authored
66 errx(1, "_group_remove: a ctx is NULL");
3d12c94 Initial revision
bernd authored
67
c750462 One of the most annoying things to do was restart cwm and lose all of
oga authored
68 XChangeProperty(X_Dpy, cc->win, _CWM_GRP, XA_STRING, 8,
69 PropModeReplace, shortcut_to_name[0],
70 strlen(shortcut_to_name[0]));
71
3d12c94 Initial revision
bernd authored
72 TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
73 cc->group = NULL;
74 }
75
76 static void
77 _group_hide(struct group_ctx *gc)
78 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
79 struct client_ctx *cc;
3d12c94 Initial revision
bernd authored
80
81 screen_updatestackingorder();
82
83 gc->nhidden = 0;
84 gc->highstack = 0;
85 TAILQ_FOREACH(cc, &gc->clients, group_entry) {
86 client_hide(cc);
87 gc->nhidden++;
88 if (cc->stackingorder > gc->highstack)
89 gc->highstack = cc->stackingorder;
90 }
91 gc->hidden = 1; /* XXX: equivalent to gc->nhidden > 0 */
92 }
93
94 static void
95 _group_show(struct group_ctx *gc)
96 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
97 struct client_ctx *cc;
98 Window *winlist;
99 u_int i;
100 int lastempty = -1;
3d12c94 Initial revision
bernd authored
101
f473dc3 Replace a few leftover calls to strdup and calloc with xstrdup and xc…
oga authored
102 winlist = (Window *) xcalloc(sizeof(*winlist), (gc->highstack + 1));
3d12c94 Initial revision
bernd authored
103
104 /*
105 * Invert the stacking order as XRestackWindows() expects them
106 * top-to-bottom.
107 */
108 TAILQ_FOREACH(cc, &gc->clients, group_entry) {
ec8e605 remove pwin, bringing us to one client, one window. we no longer have
okan authored
109 winlist[gc->highstack - cc->stackingorder] = cc->win;
3d12c94 Initial revision
bernd authored
110 client_unhide(cc);
111 }
112
113 /* Un-sparseify */
114 for (i = 0; i <= gc->highstack; i++) {
115 if (!winlist[i] && lastempty == -1)
116 lastempty = i;
117 else if (winlist[i] && lastempty != -1) {
118 winlist[lastempty] = winlist[i];
119 if (++lastempty == i)
120 lastempty = -1;
121 }
122 }
123
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
124 XRestackWindows(X_Dpy, winlist, gc->nhidden);
3d12c94 Initial revision
bernd authored
125 xfree(winlist);
126
127 gc->hidden = 0;
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
128 Group_active = gc;
3d12c94 Initial revision
bernd authored
129 }
130
131 void
132 group_init(void)
133 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
134 int i;
3d12c94 Initial revision
bernd authored
135
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
136 TAILQ_INIT(&Groupq);
3d12c94 Initial revision
bernd authored
137
138 for (i = 0; i < CALMWM_NGROUPS; i++) {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
139 TAILQ_INIT(&Groups[i].clients);
140 Groups[i].hidden = 0;
141 Groups[i].shortcut = i + 1;
c750462 One of the most annoying things to do was restart cwm and lose all of
oga authored
142 Groups[i].name = shortcut_to_name[Groups[i].shortcut];
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
143 TAILQ_INSERT_TAIL(&Groupq, &Groups[i], entry);
3d12c94 Initial revision
bernd authored
144 }
145
eb78032 add a "movetogroup" function, which hides the current window from
sthen authored
146 }
147
148 void
149 group_movetogroup(struct client_ctx *cc, int idx)
150 {
151 if (idx < 0 || idx >= CALMWM_NGROUPS)
152 err(1, "group_movetogroup: index out of range (%d)", idx);
153
154 client_hide(cc);
155 _group_add(&Groups[idx], cc);
3d12c94 Initial revision
bernd authored
156 }
157
36c1aac Rip out, burn, and dance around the grave of group-edit mode.
oga authored
158 /*
159 * Colouring for groups upon add/remove.
3d12c94 Initial revision
bernd authored
160 */
161 void
162 group_sticky_toggle_enter(struct client_ctx *cc)
163 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
164 struct group_ctx *gc;
165
166 gc = Group_active;
3d12c94 Initial revision
bernd authored
167
168 if (gc == cc->group) {
169 _group_remove(cc);
170 cc->highlight = CLIENT_HIGHLIGHT_RED;
171 } else {
172 _group_add(gc, cc);
173 cc->highlight = CLIENT_HIGHLIGHT_BLUE;
174 }
175
176 client_draw_border(cc);
177 }
178
179 void
180 group_sticky_toggle_exit(struct client_ctx *cc)
181 {
182 cc->highlight = 0;
183 client_draw_border(cc);
184 }
185
186 /*
49e218c - add missing prototypes.
okan authored
187 * if group_hidetoggle would produce no effect, toggle the group's hidden state
3d12c94 Initial revision
bernd authored
188 */
49e218c - add missing prototypes.
okan authored
189 static void
3d12c94 Initial revision
bernd authored
190 _group_fix_hidden_state(struct group_ctx *gc)
191 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
192 struct client_ctx *cc;
193 int same = 0;
3d12c94 Initial revision
bernd authored
194
195 TAILQ_FOREACH(cc, &gc->clients, group_entry) {
196 if (gc->hidden == ((cc->flags & CLIENT_HIDDEN) ? 1 : 0))
197 same++;
198 }
199
200 if (same == 0)
201 gc->hidden = !gc->hidden;
202 }
203
204 void
205 group_hidetoggle(int idx)
206 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
207 struct group_ctx *gc;
3d12c94 Initial revision
bernd authored
208
209 if (idx < 0 || idx >= CALMWM_NGROUPS)
210 err(1, "group_hidetoggle: index out of range (%d)", idx);
211
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
212 gc = &Groups[idx];
3d12c94 Initial revision
bernd authored
213
214 _group_fix_hidden_state(gc);
215
216 if (gc->hidden)
217 _group_show(gc);
218 else {
219 _group_hide(gc);
220 if (TAILQ_EMPTY(&gc->clients))
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
221 Group_active = gc;
3d12c94 Initial revision
bernd authored
222 }
223 }
224
3de90d4 Add a new command (currently no default keybindings for it), grouponl…
oga authored
225 void
226 group_only(int idx)
227 {
228 int i;
229
230 if (idx < 0 || idx >= CALMWM_NGROUPS)
231 err(1, "group_only: index out of range (%d)", idx);
232
233 for (i = 0; i < CALMWM_NGROUPS; i++) {
234 if (i == idx) {
235 _group_show(&Groups[i]);
236 } else {
237 _group_hide(&Groups[i]);
238 }
239 }
240 }
241
3d12c94 Initial revision
bernd authored
242 /*
d347aa3 as done with cycle/rcycle, make prev/next group switching one kbfuncs
okan authored
243 * Cycle through active groups. If none exist, then just stay put.
3d12c94 Initial revision
bernd authored
244 */
245 void
d347aa3 as done with cycle/rcycle, make prev/next group switching one kbfuncs
okan authored
246 group_cycle(int reverse)
3d12c94 Initial revision
bernd authored
247 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
248 struct group_ctx *gc, *showgroup = NULL;
3d12c94 Initial revision
bernd authored
249
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
250 assert(Group_active != NULL);
3d12c94 Initial revision
bernd authored
251
556f7a0 Put back the initialisation of gc in group_cycle. No cookie for okan.
oga authored
252 gc = Group_active;
3d12c94 Initial revision
bernd authored
253 for (;;) {
d347aa3 as done with cycle/rcycle, make prev/next group switching one kbfuncs
okan authored
254 gc = reverse ? TAILQ_PREV(gc, group_ctx_q, entry) :
255 TAILQ_NEXT(gc, entry);
3d12c94 Initial revision
bernd authored
256 if (gc == NULL)
d347aa3 as done with cycle/rcycle, make prev/next group switching one kbfuncs
okan authored
257 gc = reverse ? TAILQ_LAST(&Groupq, group_ctx_q) :
258 TAILQ_FIRST(&Groupq);
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
259 if (gc == Group_active)
3d12c94 Initial revision
bernd authored
260 break;
261
262 if (!TAILQ_EMPTY(&gc->clients) && showgroup == NULL)
263 showgroup = gc;
264 else if (!gc->hidden)
265 _group_hide(gc);
266 }
267
268 if (showgroup == NULL)
269 return;
270
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
271 _group_hide(Group_active);
3d12c94 Initial revision
bernd authored
272
273 if (showgroup->hidden)
274 _group_show(showgroup);
275 else
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
276 Group_active = showgroup;
3d12c94 Initial revision
bernd authored
277 }
278
279 /* called when a client is deleted */
280 void
281 group_client_delete(struct client_ctx *cc)
282 {
283 if (cc->group == NULL)
75182c6 hit it with the knf stick.
oga authored
284 return;
3d12c94 Initial revision
bernd authored
285
286 TAILQ_REMOVE(&cc->group->clients, cc, group_entry);
287 cc->group = NULL; /* he he */
288 }
289
290 void
291 group_menu(XButtonEvent *e)
292 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
293 struct group_ctx *gc;
75182c6 hit it with the knf stick.
oga authored
294 struct menu *mi;
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
295 struct menu_q menuq;
75182c6 hit it with the knf stick.
oga authored
296 int i;
3d12c94 Initial revision
bernd authored
297
298 TAILQ_INIT(&menuq);
299
300 for (i = 0; i < CALMWM_NGROUPS; i++) {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
301 gc = &Groups[i];
3d12c94 Initial revision
bernd authored
302
303 if (TAILQ_EMPTY(&gc->clients))
304 continue;
305
306 XCALLOC(mi, struct menu);
307 if (gc->hidden)
308 snprintf(mi->text, sizeof(mi->text), "%d: [%s]",
5c40253 group_ctx->name is only used in this one function, and for now it
oga authored
309 gc->shortcut, shortcut_to_name[gc->shortcut]);
3d12c94 Initial revision
bernd authored
310 else
311 snprintf(mi->text, sizeof(mi->text), "%d: %s",
5c40253 group_ctx->name is only used in this one function, and for now it
oga authored
312 gc->shortcut, shortcut_to_name[gc->shortcut]);
3d12c94 Initial revision
bernd authored
313 mi->ctx = gc;
314 TAILQ_INSERT_TAIL(&menuq, mi, entry);
315 }
316
317 if (TAILQ_EMPTY(&menuq))
318 return;
319
779cf04 Make menu_filter handle mouse movement too. This enables the keyboard
oga authored
320 mi = menu_filter(&menuq, NULL, NULL, 0, NULL, NULL);
3d12c94 Initial revision
bernd authored
321
322 if (mi == NULL || mi->ctx == NULL)
323 goto cleanup;
324
325 gc = (struct group_ctx *)mi->ctx;
326
327 if (gc->hidden)
328 _group_show(gc);
329 else
330 _group_hide(gc);
331
5034a77 KNF, no binary change.
oga authored
332 cleanup:
3d12c94 Initial revision
bernd authored
333 while ((mi = TAILQ_FIRST(&menuq)) != NULL) {
334 TAILQ_REMOVE(&menuq, mi, entry);
335 xfree(mi);
336 }
337 }
338
339 void
340 group_alltoggle(void)
341 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
342 int i;
3d12c94 Initial revision
bernd authored
343
75182c6 hit it with the knf stick.
oga authored
344 for (i = 0; i < CALMWM_NGROUPS; i++) {
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
345 if (Grouphideall)
346 _group_show(&Groups[i]);
3d12c94 Initial revision
bernd authored
347 else
75182c6 hit it with the knf stick.
oga authored
348 _group_hide(&Groups[i]);
3d12c94 Initial revision
bernd authored
349 }
350
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
351 if (Grouphideall)
352 Grouphideall = 0;
3d12c94 Initial revision
bernd authored
353 else
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
354 Grouphideall = 1;
3d12c94 Initial revision
bernd authored
355 }
356
357 void
358 group_autogroup(struct client_ctx *cc)
359 {
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
360 struct autogroupwin *aw;
361 struct group_ctx *gc;
c750462 One of the most annoying things to do was restart cwm and lose all of
oga authored
362 unsigned char *grpstr = NULL;
b23fad3 spacing, declaration lineup to be consistent throughout cwm,
okan authored
363 char group[CALMWM_MAXNAMELEN];
3d12c94 Initial revision
bernd authored
364
365 if (cc->app_class == NULL || cc->app_name == NULL)
366 return;
c750462 One of the most annoying things to do was restart cwm and lose all of
oga authored
367 if (xu_getprop(cc, _CWM_GRP, XA_STRING,
368 (CALMWM_MAXNAMELEN - 1)/sizeof(long), &grpstr) > 0) {
369 strlcpy(group, grpstr, sizeof(group));
370 XFree(grpstr);
371 } else {
372 TAILQ_FOREACH(aw, &Conf.autogroupq, entry) {
373 if (strcmp(aw->class, cc->app_class) == 0 &&
374 (aw->name == NULL ||
375 strcmp(aw->name, cc->app_name) == 0)) {
376 strlcpy(group, aw->group, sizeof(group));
377 break;
378 }
3d12c94 Initial revision
bernd authored
379 }
380 }
381
71f99ab allow an autogroup value of 0 to mean no group. This means you can set
oga authored
382 if (strncmp("nogroup", group, 7) == 0)
383 return;
384
9006bbf convert globals from G_foo to Foo, as per TODO.
jasper authored
385 TAILQ_FOREACH(gc, &Groupq, entry) {
38ff7a9 allow autogrouping and sticky mode to work together
okan authored
386 if (strcmp(shortcut_to_name[gc->shortcut], group) == 0) {
3d12c94 Initial revision
bernd authored
387 _group_add(gc, cc);
38ff7a9 allow autogrouping and sticky mode to work together
okan authored
388 return;
389 }
3d12c94 Initial revision
bernd authored
390 }
391
38ff7a9 allow autogrouping and sticky mode to work together
okan authored
392 if (Conf.flags & CONF_STICKY_GROUPS)
393 _group_add(Group_active, cc);
394
3d12c94 Initial revision
bernd authored
395 }
Something went wrong with that request. Please try again.