Ship forgotten UPGRADE file
[awesome.git] / tag.c
blobbb75d1b348d2aff4b07b36592d0424e3a853312f
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 "rules.h"
28 #include "client.h"
29 #include "ewmh.h"
30 #include "widget.h"
32 extern AwesomeConf globalconf;
34 Tag *
35 tag_new(const char *name, Layout *layout, double mwfact, int nmaster, int ncol)
37 Tag *tag;
39 tag = p_new(Tag, 1);
40 tag->name = a_strdup(name);
41 tag->layout = layout;
42 tag->mwfact = mwfact;
43 tag->nmaster = nmaster;
44 tag->ncol = ncol;
46 return tag;
49 static void
50 tag_append_to_screen(Tag *tag, int screen)
52 tag->screen = screen;
53 tag_list_append(&globalconf.screens[screen].tags, tag);
54 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
57 void
58 tag_push_to_screen(Tag *tag, int screen)
60 tag->screen = screen;
61 tag_list_push(&globalconf.screens[screen].tags, tag);
62 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
65 void
66 tag_client(Client *c, Tag *t)
68 tag_client_node_t *tc;
70 /* don't tag twice */
71 if(is_client_tagged(c, t))
72 return;
74 tc = p_new(tag_client_node_t, 1);
75 tc->client = c;
76 tc->tag = t;
77 tag_client_node_list_push(&globalconf.tclink, tc);
79 client_saveprops(c);
80 widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
81 globalconf.screens[c->screen].need_arrange = True;
84 void
85 untag_client(Client *c, Tag *t)
87 tag_client_node_t *tc;
89 for(tc = globalconf.tclink; tc; tc = tc->next)
90 if(tc->client == c && tc->tag == t)
92 tag_client_node_list_detach(&globalconf.tclink, tc);
93 p_delete(&tc);
94 break;
97 client_saveprops(c);
98 widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
99 globalconf.screens[c->screen].need_arrange = True;
102 Bool
103 is_client_tagged(Client *c, Tag *t)
105 tag_client_node_t *tc;
107 if(!c)
108 return False;
110 for(tc = globalconf.tclink; tc; tc = tc->next)
111 if(tc->client == c && tc->tag == t)
112 return True;
114 return False;
117 void
118 tag_client_with_current_selected(Client *c)
120 Tag *tag;
121 VirtScreen vscreen = globalconf.screens[c->screen];
123 for(tag = vscreen.tags; tag; tag = tag->next)
124 if(tag->selected)
125 tag_client(c, tag);
126 else
127 untag_client(c, tag);
130 void
131 tag_client_with_rule(Client *c, Rule *r)
133 Tag *tag;
134 Bool matched = False;
136 if(!r) return;
138 /* check if at least one tag match */
139 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
140 if(tag_match_rule(tag, r))
142 matched = True;
143 break;
146 if(matched)
147 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
148 if(tag_match_rule(tag, r))
149 tag_client(c, tag);
150 else
151 untag_client(c, tag);
154 Tag **
155 tags_get_current(int screen)
157 Tag *tag, **tags = NULL;
158 int n = 1;
160 tags = p_new(Tag *, n);
161 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
162 if(tag->selected)
164 p_realloc(&tags, ++n);
165 tags[n - 2] = tag;
168 /* finish with null */
169 tags[n - 1] = NULL;
171 return tags;
174 /** Tag selected window with tag
175 * \param screen Screen ID
176 * \param arg Tag name
177 * \ingroup ui_callback
179 void
180 uicb_client_tag(int screen, char *arg)
182 int tag_id = -1;
183 Tag *tag, *target_tag;
184 Client *sel = globalconf.focus->client;
186 if(!sel)
187 return;
189 if(arg)
191 tag_id = atoi(arg) - 1;
192 if(tag_id != -1)
194 for(target_tag = globalconf.screens[screen].tags; target_tag && tag_id > 0;
195 target_tag = target_tag->next, tag_id--);
196 if(target_tag)
198 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
199 untag_client(sel, tag);
200 tag_client(sel, target_tag);
204 else
205 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
206 tag_client(sel, tag);
209 /** Toggle a tag on client
210 * \param screen Screen ID
211 * \param arg Tag name
212 * \ingroup ui_callback
214 void
215 uicb_client_toggletag(int screen, char *arg)
217 Client *sel = globalconf.focus->client;
218 int i;
219 Tag *tag, *target_tag;
221 if(!sel)
222 return;
224 if(arg)
226 i = atoi(arg) - 1;
227 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
228 target_tag = target_tag->next, i--);
229 if(target_tag)
231 if(is_client_tagged(sel, target_tag))
232 untag_client(sel, target_tag);
233 else
234 tag_client(sel, target_tag);
237 /* check that there's at least one tag selected for this client*/
238 for(tag = globalconf.screens[screen].tags; tag
239 && !is_client_tagged(sel, tag); tag = tag->next)
241 if(!tag)
242 tag_client(sel, target_tag);
244 else
245 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
246 if(is_client_tagged(sel, tag))
247 tag_client(sel, tag);
248 else
249 untag_client(sel, tag);
252 /** Add a tag to viewed tags
253 * \param screen Screen ID
254 * \param arg Tag name
255 * \ingroup ui_callback
257 void
258 uicb_tag_toggleview(int screen, char *arg)
260 int i;
261 Tag *tag, *target_tag;
263 if(arg)
265 i = atoi(arg) - 1;
266 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
267 target_tag = target_tag->next, i--);
269 if(target_tag)
270 tag_view(target_tag, !target_tag->selected);
272 /* check that there's at least one tag selected */
273 for(tag = globalconf.screens[screen].tags; tag && !tag->selected; tag = tag->next);
274 if(!tag)
275 tag_view(target_tag, True);
277 else
278 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
279 tag_view(tag, !tag->selected);
282 static void
283 tag_view_only(Tag *target)
285 Tag *tag;
287 if(!target) return;
289 for(tag = globalconf.screens[target->screen].tags; tag; tag = tag->next)
290 tag_view(tag, False);
292 tag_view(target, True);
295 void
296 tag_view_byindex(int screen, int dindex, Bool view)
298 Tag *tag;
300 if(dindex < 0)
301 return;
303 for(tag = globalconf.screens[screen].tags; tag && dindex > 0;
304 tag = tag->next, dindex--);
305 tag_view(tag, view);
308 void
309 tag_view_only_byindex(int screen, int dindex)
311 Tag *tag;
313 if(dindex < 0)
314 return;
316 for(tag = globalconf.screens[screen].tags; tag && dindex > 0;
317 tag = tag->next, dindex--);
318 tag_view_only(tag);
321 void
322 tag_view(Tag *tag, Bool view)
324 tag->was_selected = tag->selected;
325 tag->selected = view;
326 ewmh_update_net_current_desktop(get_phys_screen(tag->screen));
327 widget_invalidate_cache(tag->screen, WIDGET_CACHE_TAGS);
328 saveawesomeprops(tag->screen);
329 globalconf.screens[tag->screen].need_arrange = True;
332 /** View tag
333 * \param screen Screen ID
334 * \param arg tag to view
335 * \ingroup ui_callback
337 void
338 uicb_tag_view(int screen, char *arg)
340 Tag *tag;
342 if(arg)
343 tag_view_only_byindex(screen, atoi(arg) - 1);
344 else
345 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
346 tag_view(tag, True);
349 /** View previously selected tags
350 * \param screen Screen ID
351 * \param arg unused
352 * \ingroup ui_callback
354 void
355 uicb_tag_prev_selected(int screen, char *arg __attribute__ ((unused)))
357 Tag *tag;
359 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
360 tag_view(tag, tag->was_selected);
363 /** View next tag
364 * \param screen Screen ID
365 * \param arg unused
366 * \ingroup ui_callback
368 void
369 uicb_tag_viewnext(int screen, char *arg __attribute__ ((unused)))
371 Tag *tag, **curtags = tags_get_current(screen);
373 tag = tag_list_next_cycle(&globalconf.screens[screen].tags, curtags[0]);
375 tag_view(curtags[0], False);
376 tag_view(tag, True);
378 p_delete(&curtags);
381 /** View previous tag
382 * \param screen Screen ID
383 * \param arg unused
384 * \ingroup ui_callback
386 void
387 uicb_tag_viewprev(int screen, char *arg __attribute__ ((unused)))
389 Tag *tag, **curtags = tags_get_current(screen);
391 tag = tag_list_prev_cycle(&globalconf.screens[screen].tags, curtags[0]);
393 tag_view(curtags[0], False);
394 tag_view(tag, True);
396 p_delete(&curtags);
399 void
400 uicb_tag_create(int screen, char *arg)
402 Tag *tag;
404 if(!a_strlen(arg))
405 return;
407 tag = tag_new(arg, globalconf.screens[screen].layouts, 0.5, 1, 1);
408 tag_append_to_screen(tag, screen);
411 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80