Mute version check (unless it fails)
[awesome.git] / tag.c
blobd4e3779231d549031f45fb6f0f7fbfccc6f780a1
1 /*
2 * tag.c - tag management
4 * Copyright © 2007 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include <stdio.h>
23 #include <X11/Xutil.h>
25 #include "screen.h"
26 #include "tag.h"
27 #include "util.h"
28 #include "rules.h"
29 #include "client.h"
30 #include "ewmh.h"
31 #include "widget.h"
33 extern AwesomeConf globalconf;
35 static void
36 detach_tagclientlink(TagClientLink *tc)
38 TagClientLink *tmp;
40 if(globalconf.tclink == tc)
41 globalconf.tclink = tc->next;
42 else
44 for(tmp = globalconf.tclink; tmp && tmp->next != tc; tmp = tmp->next);
45 tmp->next = tc->next;
48 p_delete(&tc);
51 void
52 tag_client(Client *c, Tag *t)
54 TagClientLink *tc, *new_tc;
56 /* don't tag twice */
57 if(is_client_tagged(c, t))
58 return;
60 new_tc = p_new(TagClientLink, 1);
62 if(!globalconf.tclink)
63 globalconf.tclink = new_tc;
64 else
66 for(tc = globalconf.tclink; tc->next; tc = tc->next);
67 tc->next = new_tc;
70 new_tc->client = c;
71 new_tc->tag = t;
73 widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
76 void
77 untag_client(Client *c, Tag *t)
79 TagClientLink *tc;
81 for(tc = globalconf.tclink; tc; tc = tc->next)
82 if(tc->client == c && tc->tag == t)
84 detach_tagclientlink(tc);
85 break;
88 widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
91 Bool
92 is_client_tagged(Client *c, Tag *t)
94 TagClientLink *tc;
96 if(!c)
97 return False;
99 for(tc = globalconf.tclink; tc; tc = tc->next)
100 if(tc->client == c && tc->tag == t)
101 return True;
103 return False;
106 void
107 tag_client_with_current_selected(Client *c)
109 Tag *tag;
110 VirtScreen vscreen = globalconf.screens[c->screen];
112 for(tag = vscreen.tags; tag; tag = tag->next)
113 if(tag->selected)
114 tag_client(c, tag);
115 else
116 untag_client(c, tag);
119 void
120 tag_client_with_rules(Client *c)
122 Rule *r;
123 Tag *tag;
124 Bool matched = False;
126 for(r = globalconf.rules; r; r = r->next)
127 if(client_match_rule(c, r))
129 switch(r->isfloating)
131 case Tile:
132 c->isfloating = False;
133 break;
134 case Float:
135 c->isfloating = True;
136 client_resize(c, c->f_geometry, False);
137 break;
138 default:
139 break;
142 if(r->screen != RULE_NOSCREEN && r->screen != c->screen)
143 move_client_to_screen(c, r->screen, True);
145 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
146 if(is_tag_match_rules(tag, r))
148 matched = True;
149 tag_client(c, tag);
151 else
152 untag_client(c, tag);
154 if(!matched)
155 tag_client_with_current_selected(c);
156 break;
161 Tag **
162 get_current_tags(int screen)
164 Tag *tag, **tags = NULL;
165 int n = 1;
167 tags = p_new(Tag *, n);
168 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
169 if(tag->selected)
171 p_realloc(&tags, ++n);
172 tags[n - 2] = tag;
175 /* finish with null */
176 tags[n - 1] = NULL;
178 return tags;
181 /** Tag selected window with tag
182 * \param screen Screen ID
183 * \param arg Tag name
184 * \ingroup ui_callback
186 void
187 uicb_client_tag(int screen, char *arg)
189 int tag_id = -1;
190 Tag *tag, *target_tag;
191 Client *sel = globalconf.focus->client;
193 if(!sel)
194 return;
196 if(arg)
198 tag_id = atoi(arg) - 1;
199 if(tag_id != -1)
201 for(target_tag = globalconf.screens[screen].tags; target_tag && tag_id > 0;
202 target_tag = target_tag->next, tag_id--);
203 if(target_tag)
205 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
206 untag_client(sel, tag);
207 tag_client(sel, target_tag);
211 else
212 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
213 tag_client(sel, tag);
215 client_saveprops(sel);
216 arrange(screen);
219 /** Toggle a tag on client
220 * \param screen Screen ID
221 * \param arg Tag name
222 * \ingroup ui_callback
224 void
225 uicb_client_toggletag(int screen, char *arg)
227 Client *sel = globalconf.focus->client;
228 int i;
229 Tag *tag, *target_tag;
231 if(!sel)
232 return;
234 if(arg)
236 i = atoi(arg) - 1;
237 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
238 target_tag = target_tag->next, i--);
239 if(target_tag)
241 if(is_client_tagged(sel, target_tag))
242 untag_client(sel, target_tag);
243 else
244 tag_client(sel, target_tag);
247 /* check that there's at least one tag selected for this client*/
248 for(tag = globalconf.screens[screen].tags; tag
249 && !is_client_tagged(sel, tag); tag = tag->next)
251 if(!tag)
252 tag_client(sel, target_tag);
254 else
255 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
256 if(is_client_tagged(sel, tag))
257 tag_client(sel, tag);
258 else
259 untag_client(sel, tag);
261 client_saveprops(sel);
262 arrange(screen);
265 /** Add a tag to viewed tags
266 * \param screen Screen ID
267 * \param arg Tag name
268 * \ingroup ui_callback
270 void
271 uicb_tag_toggleview(int screen, char *arg)
273 int i;
274 Tag *tag, *target_tag;
276 if(arg)
278 i = atoi(arg) - 1;
279 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
280 target_tag = target_tag->next, i--);
282 if(target_tag)
283 target_tag->selected = !target_tag->selected;
285 /* check that there's at least one tag selected */
286 for(tag = globalconf.screens[screen].tags; tag && !tag->selected; tag = tag->next);
287 if(!tag)
288 target_tag->selected = True;
290 else
291 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
292 tag->selected = !tag->selected;
294 saveawesomeprops(screen);
295 arrange(screen);
296 ewmh_update_net_current_desktop(get_phys_screen(screen));
297 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
300 void
301 tag_view(int screen, int dindex)
303 Tag *target_tag, *tag;
305 if(dindex < 0)
306 return;
308 for(target_tag = globalconf.screens[screen].tags; target_tag && dindex > 0;
309 target_tag = target_tag->next, dindex--);
310 if(target_tag)
312 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
313 tag->selected = False;
314 target_tag->selected = True;
316 saveawesomeprops(screen);
317 arrange(screen);
318 ewmh_update_net_current_desktop(get_phys_screen(screen));
319 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
322 /** View tag
323 * \param screen Screen ID
324 * \param arg tag to view
325 * \ingroup ui_callback
327 void
328 uicb_tag_view(int screen, char *arg)
330 Tag *tag;
332 if(arg)
333 tag_view(screen, atoi(arg) - 1);
334 else
336 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
337 tag->selected = True;
338 saveawesomeprops(screen);
339 arrange(screen);
340 ewmh_update_net_current_desktop(get_phys_screen(screen));
341 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
345 /** View previously selected tags
346 * \param screen Screen ID
347 * \param arg unused
348 * \ingroup ui_callback
350 void
351 uicb_tag_prev_selected(int screen, char *arg __attribute__ ((unused)))
353 Tag *tag;
354 Bool t;
356 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
358 t = tag->selected;
359 tag->selected = tag->was_selected;
360 tag->was_selected = t;
362 arrange(screen);
363 ewmh_update_net_current_desktop(get_phys_screen(screen));
364 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
367 /** View next tag
368 * \param screen Screen ID
369 * \param arg unused
370 * \ingroup ui_callback
372 void
373 uicb_tag_viewnext(int screen, char *arg __attribute__ ((unused)))
375 Tag **curtags = get_current_tags(screen);
377 if(!curtags[0]->next)
378 return;
380 curtags[0]->selected = False;
381 curtags[0]->next->selected = True;
383 p_delete(&curtags);
385 saveawesomeprops(screen);
386 arrange(screen);
387 ewmh_update_net_current_desktop(get_phys_screen(screen));
388 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
391 /** View previous tag
392 * \param screen Screen ID
393 * \param arg unused
394 * \ingroup ui_callback
396 void
397 uicb_tag_viewprev(int screen, char *arg __attribute__ ((unused)))
399 Tag *tag, **curtags = get_current_tags(screen);
401 for(tag = globalconf.screens[screen].tags; tag && tag->next != curtags[0]; tag = tag->next);
402 if(tag)
404 tag->selected = True;
405 curtags[0]->selected = False;
406 saveawesomeprops(screen);
407 arrange(screen);
409 p_delete(&curtags);
410 ewmh_update_net_current_desktop(get_phys_screen(screen));
411 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
414 void
415 uicb_tag_create(int screen, char *arg)
417 Tag *last_tag, *tag;
419 if(!a_strlen(arg))
420 return;
422 for(last_tag = globalconf.screens[screen].tags; last_tag && last_tag->next; last_tag = last_tag->next);
423 last_tag->next = tag = p_new(Tag, 1);
424 tag->name = a_strdup(arg);
425 tag->layout = globalconf.screens[screen].layouts;
426 tag->mwfact = 0.5;
427 tag->nmaster = 1;
428 tag->ncol = 1;
429 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
432 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80