[docs] rcskeleton improving and completing
[awesome.git] / tag.c
blob9abcef445f316a2b8fa35e9103d40f1500362ffc
1 /*
2 * tag.c - tag management
4 * Copyright © 2007-2008 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 /** Create a new tag. Parameteres values are checked.
35 * \param name tag name
36 * \param layout layout to use
37 * \param mwfact master width factor
38 * \param nmaster number of master windows
39 * \param ncol number of columns for slaves windows
40 * \return a new tag with all these parameters
42 Tag *
43 tag_new(const char *name, Layout *layout, double mwfact, int nmaster, int ncol)
45 Tag *tag;
47 tag = p_new(Tag, 1);
48 tag->name = a_strdup(name);
49 tag->layout = layout;
51 tag->mwfact = mwfact;
52 if(tag->mwfact <= 0 || tag->mwfact >= 1)
53 tag->mwfact = 0.5;
55 if((tag->nmaster = nmaster) < 0)
56 tag->nmaster = 1;
58 if((tag->ncol = ncol) < 1)
59 tag->ncol = 1;
61 return tag;
64 /** Append a tag to a screen.
65 * \param tag the tag to append
66 * \param screen the screen id
68 void
69 tag_append_to_screen(Tag *tag, int screen)
71 int phys_screen = screen_virttophys(screen);
73 tag->screen = screen;
74 tag_list_append(&globalconf.screens[screen].tags, tag);
75 ewmh_update_net_numbers_of_desktop(phys_screen);
76 ewmh_update_net_desktop_names(phys_screen);
77 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
80 /** Push a tag to a screen tag list.
81 * \param tag the tag to push
82 * \param screen the screen
84 void
85 tag_push_to_screen(Tag *tag, int screen)
87 tag->screen = screen;
88 tag_list_push(&globalconf.screens[screen].tags, tag);
89 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
92 /** Tag a client with specified tag.
93 * \param c the client to tag
94 * \param t the tag to tag the client with
96 void
97 tag_client(Client *c, Tag *t)
99 tag_client_node_t *tc;
101 /* don't tag twice */
102 if(is_client_tagged(c, t))
103 return;
105 tc = p_new(tag_client_node_t, 1);
106 tc->client = c;
107 tc->tag = t;
108 tag_client_node_list_push(&globalconf.tclink, tc);
110 client_saveprops(c);
111 widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
112 globalconf.screens[c->screen].need_arrange = True;
115 /** Untag a client with specified tag.
116 * \param c the client to tag
117 * \param t the tag to tag the client with
119 void
120 untag_client(Client *c, Tag *t)
122 tag_client_node_t *tc;
124 for(tc = globalconf.tclink; tc; tc = tc->next)
125 if(tc->client == c && tc->tag == t)
127 tag_client_node_list_detach(&globalconf.tclink, tc);
128 p_delete(&tc);
129 client_saveprops(c);
130 widget_invalidate_cache(c->screen, WIDGET_CACHE_CLIENTS);
131 globalconf.screens[c->screen].need_arrange = True;
132 break;
136 /** Check if a client is tagged with the specified tag.
137 * \param c the client
138 * \param t the tag
139 * \return true if the client is tagged with the tag, false otherwise.
141 Bool
142 is_client_tagged(Client *c, Tag *t)
144 tag_client_node_t *tc;
146 if(!c)
147 return False;
149 for(tc = globalconf.tclink; tc; tc = tc->next)
150 if(tc->client == c && tc->tag == t)
151 return True;
153 return False;
156 /** Tag the client with the currently selected (visible) tags.
157 * \param c the client
159 void
160 tag_client_with_current_selected(Client *c)
162 Tag *tag;
163 VirtScreen vscreen = globalconf.screens[c->screen];
165 for(tag = vscreen.tags; tag; tag = tag->next)
166 if(tag->selected)
167 tag_client(c, tag);
168 else
169 untag_client(c, tag);
172 /** Tag the client according to a rule.
173 * \param c the client
174 * \param r the rule
176 void
177 tag_client_with_rule(Client *c, Rule *r)
179 Tag *tag;
180 Bool matched = False;
182 if(!r) return;
184 /* check if at least one tag match */
185 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
186 if(tag_match_rule(tag, r))
188 matched = True;
189 break;
192 if(matched)
193 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
194 if(tag_match_rule(tag, r))
195 tag_client(c, tag);
196 else
197 untag_client(c, tag);
200 /** Get the current tags for the specified screen.
201 * Returned pointer must be p_delete'd after.
202 * \param screen screen id
203 * \return a double pointer of tag list finished with a NULL element
205 Tag **
206 tags_get_current(int screen)
208 Tag *tag, **tags = NULL;
209 int n = 1;
211 tags = p_new(Tag *, n);
212 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
213 if(tag->selected)
215 p_realloc(&tags, ++n);
216 tags[n - 2] = tag;
219 /* finish with null */
220 tags[n - 1] = NULL;
222 return tags;
225 /** Tag focused client with tag.
226 * \param screen Screen ID
227 * \param arg Tag name
228 * \ingroup ui_callback
230 void
231 uicb_client_tag(int screen, char *arg)
233 int tag_id = -1;
234 Tag *tag, *target_tag;
235 Client *sel = globalconf.focus->client;
237 if(!sel)
238 return;
240 if(arg)
242 tag_id = atoi(arg) - 1;
243 if(tag_id != -1)
245 for(target_tag = globalconf.screens[screen].tags; target_tag && tag_id > 0;
246 target_tag = target_tag->next, tag_id--);
247 if(target_tag)
249 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
250 untag_client(sel, tag);
251 tag_client(sel, target_tag);
255 else
256 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
257 tag_client(sel, tag);
260 /** Toggle a tag on focused client.
261 * \param screen virtual screen id
262 * \param arg tag number
263 * \ingroup ui_callback
265 void
266 uicb_client_toggletag(int screen, char *arg)
268 Client *sel = globalconf.focus->client;
269 int i;
270 Bool is_sticky = True;
271 Tag *tag, *target_tag;
273 if(!sel)
274 return;
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--);
281 if(target_tag)
283 if(is_client_tagged(sel, target_tag))
284 untag_client(sel, target_tag);
285 else
286 tag_client(sel, target_tag);
289 /* check that there's at least one tag selected for this client*/
290 for(tag = globalconf.screens[screen].tags; tag
291 && !is_client_tagged(sel, tag); tag = tag->next);
293 if(!tag)
294 tag_client(sel, target_tag);
296 else
298 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
299 if(!is_client_tagged(sel, tag))
301 is_sticky = False;
302 tag_client(sel, tag);
304 if(is_sticky)
305 tag_client_with_current_selected(sel);
309 /** Add a tag to the list of viewed tags.
310 * \param screen Screen ID
311 * \param arg Tag name
312 * \ingroup ui_callback
314 void
315 uicb_tag_toggleview(int screen, char *arg)
317 int i;
318 Tag *tag, *target_tag,
319 **backtag, **curtags = tags_get_current(screen);
321 if(arg)
323 i = atoi(arg) - 1;
324 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
325 target_tag = target_tag->next, i--);
327 if(target_tag)
328 tag_view(target_tag, !target_tag->selected);
330 else
331 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
332 tag_view(tag, !tag->selected);
334 /* check that there's at least one tag selected */
335 for(tag = globalconf.screens[screen].tags; tag && !tag->selected; tag = tag->next);
336 if(!tag)
337 for(backtag = curtags; *backtag; backtag++)
338 tag_view(*backtag, True);
340 p_delete(&curtags);
343 /** Set a tag to be the only one viewed.
344 * \param target the tag to see
346 static void
347 tag_view_only(Tag *target)
349 Tag *tag;
351 if(!target) return;
353 for(tag = globalconf.screens[target->screen].tags; tag; tag = tag->next)
354 tag_view(tag, tag == target);
357 /** Use an index to set a tag viewable.
358 * \param screen the screen id
359 * \param dindex the index
360 * \param view the view value
362 void
363 tag_view_byindex(int screen, int dindex, Bool view)
365 Tag *tag;
367 if(dindex < 0)
368 return;
370 for(tag = globalconf.screens[screen].tags; tag && dindex > 0;
371 tag = tag->next, dindex--);
372 tag_view(tag, view);
375 /** View only a tag, selected by its index.
376 * \param screen screen id
377 * \param dindex the index
379 void
380 tag_view_only_byindex(int screen, int dindex)
382 Tag *tag;
384 if(dindex < 0)
385 return;
387 for(tag = globalconf.screens[screen].tags; tag && dindex > 0;
388 tag = tag->next, dindex--);
389 tag_view_only(tag);
392 /** View or unview a tag.
393 * \param tag the tag
394 * \param view set visible or not
396 void
397 tag_view(Tag *tag, Bool view)
399 tag->was_selected = tag->selected;
400 tag->selected = view;
401 ewmh_update_net_current_desktop(screen_virttophys(tag->screen));
402 widget_invalidate_cache(tag->screen, WIDGET_CACHE_TAGS);
403 globalconf.screens[tag->screen].need_arrange = True;
406 /** View tag.
407 * \param screen Screen ID
408 * \param arg tag to view
409 * \ingroup ui_callback
411 void
412 uicb_tag_view(int screen, char *arg)
414 Tag *tag;
416 if(arg)
417 tag_view_only_byindex(screen, atoi(arg) - 1);
418 else
419 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
420 tag_view(tag, True);
423 /** View previously selected tags
424 * \param screen Screen ID
425 * \param arg unused
426 * \ingroup ui_callback
428 void
429 uicb_tag_prev_selected(int screen, char *arg __attribute__ ((unused)))
431 Tag *tag;
433 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
434 tag_view(tag, tag->was_selected);
437 /** View next tag.
438 * \param screen Screen ID
439 * \param arg unused
440 * \ingroup ui_callback
442 void
443 uicb_tag_viewnext(int screen, char *arg __attribute__ ((unused)))
445 Tag *tag, **curtags = tags_get_current(screen);
447 tag = tag_list_next_cycle(&globalconf.screens[screen].tags, curtags[0]);
449 tag_view(curtags[0], False);
450 tag_view(tag, True);
452 p_delete(&curtags);
455 /** View previous tag.
456 * \param screen Screen ID
457 * \param arg unused
458 * \ingroup ui_callback
460 void
461 uicb_tag_viewprev(int screen, char *arg __attribute__ ((unused)))
463 Tag *tag, **curtags = tags_get_current(screen);
465 tag = tag_list_prev_cycle(&globalconf.screens[screen].tags, curtags[0]);
467 tag_view(curtags[0], False);
468 tag_view(tag, True);
470 p_delete(&curtags);
473 /** Create a new tag. Argument must be the tag name.
474 * \param screen the screen id
475 * \param arg the tag name
477 void
478 uicb_tag_create(int screen, char *arg)
480 Tag *tag;
482 if(!a_strlen(arg))
483 return;
485 tag = tag_new(arg, globalconf.screens[screen].layouts, 0.5, 1, 1);
486 tag_append_to_screen(tag, screen);
489 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80