add a borders option to client_maximize() to (not) handle border removal
[awesome.git] / tag.c
blob077cfc74c1640ead28887830e7ae72a07a67c1e9
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"
32 extern AwesomeConf globalconf;
34 static void
35 detach_tagclientlink(TagClientLink *tc)
37 TagClientLink *tmp;
39 if(globalconf.tclink == tc)
40 globalconf.tclink = tc->next;
41 else
43 for(tmp = globalconf.tclink; tmp && tmp->next != tc; tmp = tmp->next);
44 tmp->next = tc->next;
47 p_delete(&tc);
50 void
51 tag_client(Client *c, Tag *t)
53 TagClientLink *tc, *new_tc;
55 /* don't tag twice */
56 if(is_client_tagged(c, t))
57 return;
59 new_tc = p_new(TagClientLink, 1);
61 if(!globalconf.tclink)
62 globalconf.tclink = new_tc;
63 else
65 for(tc = globalconf.tclink; tc->next; tc = tc->next);
66 tc->next = new_tc;
69 new_tc->client = c;
70 new_tc->tag = t;
73 void
74 untag_client(Client *c, Tag *t)
76 TagClientLink *tc;
78 for(tc = globalconf.tclink; tc; tc = tc->next)
79 if(tc->client == c && tc->tag == t)
80 detach_tagclientlink(tc);
83 Bool
84 is_client_tagged(Client *c, Tag *t)
86 TagClientLink *tc;
88 if(!c)
89 return False;
91 for(tc = globalconf.tclink; tc; tc = tc->next)
92 if(tc->client == c && tc->tag == t)
93 return True;
95 return False;
98 void
99 tag_client_with_current_selected(Client *c)
101 Tag *tag;
102 VirtScreen vscreen = globalconf.screens[c->screen];
104 for(tag = vscreen.tags; tag; tag = tag->next)
105 if(tag->selected)
106 tag_client(c, tag);
107 else
108 untag_client(c, tag);
111 void
112 tag_client_with_rules(Client *c)
114 Rule *r;
115 Tag *tag;
116 Bool matched = False;
118 for(r = globalconf.rules; r; r = r->next)
119 if(client_match_rule(c, r))
121 c->isfloating = r->isfloating;
123 if(r->screen != RULE_NOSCREEN && r->screen != c->screen)
124 move_client_to_screen(c, r->screen, True);
126 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
127 if(is_tag_match_rules(tag, r))
129 matched = True;
130 tag_client(c, tag);
132 else
133 untag_client(c, tag);
135 if(!matched)
136 tag_client_with_current_selected(c);
137 break;
142 Tag **
143 get_current_tags(int screen)
145 Tag *tag, **tags = NULL;
146 int n = 1;
148 tags = p_new(Tag *, n);
149 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
150 if(tag->selected)
152 p_realloc(&tags, ++n);
153 tags[n - 2] = tag;
156 /* finish with null */
157 tags[n - 1] = NULL;
159 return tags;
162 /** Tag selected window with tag
163 * \param screen Screen ID
164 * \param arg Tag name
165 * \ingroup ui_callback
167 void
168 uicb_client_tag(int screen, char *arg)
170 int tag_id = -1;
171 Tag *tag, *target_tag;
172 Client *sel = globalconf.focus->client;
174 if(!sel)
175 return;
177 if(arg)
179 tag_id = atoi(arg) - 1;
180 if(tag_id != -1)
182 for(target_tag = globalconf.screens[screen].tags; target_tag && tag_id > 0;
183 target_tag = target_tag->next, tag_id--);
184 if(target_tag)
186 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
187 untag_client(sel, tag);
188 tag_client(sel, target_tag);
192 else
193 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
194 tag_client(sel, tag);
196 client_saveprops(sel);
197 arrange(screen);
200 /** Toggle floating state of a client
201 * \param screen Screen ID
202 * \param arg unused
203 * \ingroup ui_callback
205 void
206 uicb_client_togglefloating(int screen, char *arg __attribute__ ((unused)))
208 Client *sel = globalconf.focus->client;
210 if(!sel)
211 return;
213 sel->isfloating = !sel->isfloating;
215 if (arg == NULL)
216 client_resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True, False);
217 else
218 client_resize(sel, sel->x, sel->y, sel->w, sel->h, True, True);
220 client_saveprops(sel);
221 arrange(screen);
224 /** Toggle a tag on client
225 * \param screen Screen ID
226 * \param arg Tag name
227 * \ingroup ui_callback
229 void
230 uicb_client_toggletag(int screen, char *arg)
232 Client *sel = globalconf.focus->client;
233 int i;
234 Tag *tag, *target_tag;
236 if(!sel)
237 return;
239 if(arg)
241 i = atoi(arg) - 1;
242 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
243 target_tag = target_tag->next, i--);
244 if(target_tag)
246 if(is_client_tagged(sel, target_tag))
247 untag_client(sel, target_tag);
248 else
249 tag_client(sel, target_tag);
252 /* check that there's at least one tag selected for this client*/
253 for(tag = globalconf.screens[screen].tags; tag
254 && !is_client_tagged(sel, tag); tag = tag->next)
256 if(!tag)
257 tag_client(sel, target_tag);
259 else
260 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
261 if(is_client_tagged(sel, tag))
262 tag_client(sel, tag);
263 else
264 untag_client(sel, tag);
266 client_saveprops(sel);
267 arrange(screen);
270 /** Add a tag to viewed tags
271 * \param screen Screen ID
272 * \param arg Tag name
273 * \ingroup ui_callback
275 void
276 uicb_tag_toggleview(int screen, char *arg)
278 int i;
279 Tag *tag, *target_tag;
281 if(arg)
283 i = atoi(arg) - 1;
284 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
285 target_tag = target_tag->next, i--);
287 if(target_tag)
288 target_tag->selected = !target_tag->selected;
290 /* check that there's at least one tag selected */
291 for(tag = globalconf.screens[screen].tags; tag && !tag->selected; tag = tag->next);
292 if(!tag)
293 target_tag->selected = True;
295 else
296 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
297 tag->selected = !tag->selected;
299 saveawesomeprops(screen);
300 arrange(screen);
301 ewmh_update_net_current_desktop(get_phys_screen(screen));
304 void
305 tag_view(int screen, int dindex)
307 Tag *target_tag, *tag;
309 if(dindex < 0)
310 return;
312 for(target_tag = globalconf.screens[screen].tags; target_tag && dindex > 0;
313 target_tag = target_tag->next, dindex--);
314 if(target_tag)
316 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
317 tag->selected = False;
318 target_tag->selected = True;
320 saveawesomeprops(screen);
321 arrange(screen);
322 ewmh_update_net_current_desktop(get_phys_screen(screen));
325 /** View tag
326 * \param screen Screen ID
327 * \param arg tag to view
328 * \ingroup ui_callback
330 void
331 uicb_tag_view(int screen, char *arg)
333 Tag *tag;
335 if(arg)
336 tag_view(screen, atoi(arg) - 1);
337 else
338 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
339 tag->selected = True;
342 /** View previously selected tags
343 * \param screen Screen ID
344 * \param arg unused
345 * \ingroup ui_callback
347 void
348 uicb_tag_prev_selected(int screen, char *arg __attribute__ ((unused)))
350 Tag *tag;
351 Bool t;
353 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
355 t = tag->selected;
356 tag->selected = tag->was_selected;
357 tag->was_selected = t;
359 arrange(screen);
360 ewmh_update_net_current_desktop(get_phys_screen(screen));
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 **curtags = get_current_tags(screen);
373 if(!curtags[0]->next)
374 return;
376 curtags[0]->selected = False;
377 curtags[0]->next->selected = True;
379 p_delete(&curtags);
381 saveawesomeprops(screen);
382 arrange(screen);
383 ewmh_update_net_current_desktop(get_phys_screen(screen));
386 /** View previous tag
387 * \param screen Screen ID
388 * \param arg unused
389 * \ingroup ui_callback
391 void
392 uicb_tag_viewprev(int screen, char *arg __attribute__ ((unused)))
394 Tag *tag, **curtags = get_current_tags(screen);
396 for(tag = globalconf.screens[screen].tags; tag && tag->next != curtags[0]; tag = tag->next);
397 if(tag)
399 tag->selected = True;
400 curtags[0]->selected = False;
401 saveawesomeprops(screen);
402 arrange(screen);
404 p_delete(&curtags);
405 ewmh_update_net_current_desktop(get_phys_screen(screen));
407 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80