simplify restack()
[awesome.git] / tag.c
blob9b702c3c3072f81e11f7006e27342e5da4a0081b
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 Tag *
36 tag_new(const char *name, Layout *layout, double mwfact, int nmaster, int ncol)
38 Tag *tag;
40 tag = p_new(Tag, 1);
41 tag->name = a_strdup(name);
42 tag->layout = layout;
43 tag->mwfact = mwfact;
44 tag->nmaster = nmaster;
45 tag->ncol = ncol;
47 return tag;
50 static void
51 tag_append_to_screen(Tag *tag, int screen)
53 tag->screen = screen;
54 tag_list_append(&globalconf.screens[screen].tags, tag);
55 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
58 void
59 tag_push_to_screen(Tag *tag, int screen)
61 tag->screen = screen;
62 tag_list_push(&globalconf.screens[screen].tags, tag);
63 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
66 void
67 tag_client(Client *c, Tag *t)
69 tag_client_node_t *tc;
71 /* don't tag twice */
72 if(is_client_tagged(c, t))
73 return;
75 tc = p_new(tag_client_node_t, 1);
76 tc->client = c;
77 tc->tag = t;
78 tag_client_node_list_push(&globalconf.tclink, tc);
80 client_saveprops(c);
81 widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
82 globalconf.screens[c->screen].need_arrange = True;
85 void
86 untag_client(Client *c, Tag *t)
88 tag_client_node_t *tc;
90 for(tc = globalconf.tclink; tc; tc = tc->next)
91 if(tc->client == c && tc->tag == t)
93 tag_client_node_list_detach(&globalconf.tclink, tc);
94 p_delete(&tc);
95 break;
98 client_saveprops(c);
99 widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
100 globalconf.screens[c->screen].need_arrange = True;
103 Bool
104 is_client_tagged(Client *c, Tag *t)
106 tag_client_node_t *tc;
108 if(!c)
109 return False;
111 for(tc = globalconf.tclink; tc; tc = tc->next)
112 if(tc->client == c && tc->tag == t)
113 return True;
115 return False;
118 void
119 tag_client_with_current_selected(Client *c)
121 Tag *tag;
122 VirtScreen vscreen = globalconf.screens[c->screen];
124 for(tag = vscreen.tags; tag; tag = tag->next)
125 if(tag->selected)
126 tag_client(c, tag);
127 else
128 untag_client(c, tag);
131 void
132 tag_client_with_rule(Client *c, Rule *r)
134 Tag *tag;
135 Bool matched = False;
137 if(!r) return;
139 /* check if at least one tag match */
140 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
141 if(tag_match_rule(tag, r))
143 matched = True;
144 break;
147 if(matched)
148 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
149 if(tag_match_rule(tag, r))
150 tag_client(c, tag);
151 else
152 untag_client(c, tag);
155 Tag **
156 get_current_tags(int screen)
158 Tag *tag, **tags = NULL;
159 int n = 1;
161 tags = p_new(Tag *, n);
162 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
163 if(tag->selected)
165 p_realloc(&tags, ++n);
166 tags[n - 2] = tag;
169 /* finish with null */
170 tags[n - 1] = NULL;
172 return tags;
175 /** Tag selected window with tag
176 * \param screen Screen ID
177 * \param arg Tag name
178 * \ingroup ui_callback
180 void
181 uicb_client_tag(int screen, char *arg)
183 int tag_id = -1;
184 Tag *tag, *target_tag;
185 Client *sel = globalconf.focus->client;
187 if(!sel)
188 return;
190 if(arg)
192 tag_id = atoi(arg) - 1;
193 if(tag_id != -1)
195 for(target_tag = globalconf.screens[screen].tags; target_tag && tag_id > 0;
196 target_tag = target_tag->next, tag_id--);
197 if(target_tag)
199 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
200 untag_client(sel, tag);
201 tag_client(sel, target_tag);
205 else
206 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
207 tag_client(sel, tag);
210 /** Toggle a tag on client
211 * \param screen Screen ID
212 * \param arg Tag name
213 * \ingroup ui_callback
215 void
216 uicb_client_toggletag(int screen, char *arg)
218 Client *sel = globalconf.focus->client;
219 int i;
220 Tag *tag, *target_tag;
222 if(!sel)
223 return;
225 if(arg)
227 i = atoi(arg) - 1;
228 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
229 target_tag = target_tag->next, i--);
230 if(target_tag)
232 if(is_client_tagged(sel, target_tag))
233 untag_client(sel, target_tag);
234 else
235 tag_client(sel, target_tag);
238 /* check that there's at least one tag selected for this client*/
239 for(tag = globalconf.screens[screen].tags; tag
240 && !is_client_tagged(sel, tag); tag = tag->next)
242 if(!tag)
243 tag_client(sel, target_tag);
245 else
246 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
247 if(is_client_tagged(sel, tag))
248 tag_client(sel, tag);
249 else
250 untag_client(sel, tag);
253 /** Add a tag to viewed tags
254 * \param screen Screen ID
255 * \param arg Tag name
256 * \ingroup ui_callback
258 void
259 uicb_tag_toggleview(int screen, char *arg)
261 int i;
262 Tag *tag, *target_tag;
264 if(arg)
266 i = atoi(arg) - 1;
267 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
268 target_tag = target_tag->next, i--);
270 if(target_tag)
271 tag_view(target_tag, !target_tag->selected);
273 /* check that there's at least one tag selected */
274 for(tag = globalconf.screens[screen].tags; tag && !tag->selected; tag = tag->next);
275 if(!tag)
276 tag_view(target_tag, True);
278 else
279 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
280 tag_view(tag, !tag->selected);
283 static void
284 tag_view_only(Tag *target)
286 Tag *tag;
288 if(!target) return;
290 for(tag = globalconf.screens[target->screen].tags; tag; tag = tag->next)
291 tag_view(tag, False);
293 tag_view(target, True);
296 void
297 tag_view_only_byindex(int screen, int dindex)
299 Tag *tag;
301 if(dindex < 0)
302 return;
304 for(tag = globalconf.screens[screen].tags; tag && dindex > 0;
305 tag = tag->next, dindex--);
306 tag_view_only(tag);
309 void
310 tag_view(Tag *tag, Bool view)
312 tag->selected = view;
313 ewmh_update_net_current_desktop(get_phys_screen(tag->screen));
314 widget_invalidate_cache(tag->screen, WIDGET_CACHE_TAGS);
315 saveawesomeprops(tag->screen);
316 globalconf.screens[tag->screen].need_arrange = True;
319 /** View tag
320 * \param screen Screen ID
321 * \param arg tag to view
322 * \ingroup ui_callback
324 void
325 uicb_tag_view(int screen, char *arg)
327 Tag *tag;
329 if(arg)
330 tag_view_only_byindex(screen, atoi(arg) - 1);
331 else
332 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
333 tag_view(tag, True);
336 /** View previously selected tags
337 * \param screen Screen ID
338 * \param arg unused
339 * \ingroup ui_callback
341 void
342 uicb_tag_prev_selected(int screen, char *arg __attribute__ ((unused)))
344 Tag *tag;
345 Bool t;
347 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
349 t = tag->selected;
350 tag_view(tag, tag->was_selected);
351 tag->was_selected = t;
355 /** View next tag
356 * \param screen Screen ID
357 * \param arg unused
358 * \ingroup ui_callback
360 void
361 uicb_tag_viewnext(int screen, char *arg __attribute__ ((unused)))
363 Tag *tag, **curtags = get_current_tags(screen);
365 tag = tag_list_next_cycle(&globalconf.screens[screen].tags, curtags[0]);
367 tag_view(curtags[0], False);
368 tag_view(tag, True);
370 p_delete(&curtags);
373 /** View previous tag
374 * \param screen Screen ID
375 * \param arg unused
376 * \ingroup ui_callback
378 void
379 uicb_tag_viewprev(int screen, char *arg __attribute__ ((unused)))
381 Tag *tag, **curtags = get_current_tags(screen);
383 tag = tag_list_prev_cycle(&globalconf.screens[screen].tags, curtags[0]);
385 tag_view(curtags[0], False);
386 tag_view(tag, True);
388 p_delete(&curtags);
391 void
392 uicb_tag_create(int screen, char *arg)
394 Tag *tag;
396 if(!a_strlen(arg))
397 return;
399 tag = tag_new(arg, globalconf.screens[screen].layouts, 0.5, 1, 1);
400 tag_append_to_screen(tag, screen);
403 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80