add support for Button6 and Button7
[awesome.git] / tag.c
blobc583ba54590324f8dd4b5f83f6d32e67286544d6
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 break;
137 default:
138 break;
141 if(r->screen != RULE_NOSCREEN && r->screen != c->screen)
142 move_client_to_screen(c, r->screen, True);
144 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
145 if(is_tag_match_rules(tag, r))
147 matched = True;
148 tag_client(c, tag);
150 else
151 untag_client(c, tag);
153 if(!matched)
154 tag_client_with_current_selected(c);
155 break;
160 Tag **
161 get_current_tags(int screen)
163 Tag *tag, **tags = NULL;
164 int n = 1;
166 tags = p_new(Tag *, n);
167 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
168 if(tag->selected)
170 p_realloc(&tags, ++n);
171 tags[n - 2] = tag;
174 /* finish with null */
175 tags[n - 1] = NULL;
177 return tags;
180 /** Tag selected window with tag
181 * \param screen Screen ID
182 * \param arg Tag name
183 * \ingroup ui_callback
185 void
186 uicb_client_tag(int screen, char *arg)
188 int tag_id = -1;
189 Tag *tag, *target_tag;
190 Client *sel = globalconf.focus->client;
192 if(!sel)
193 return;
195 if(arg)
197 tag_id = atoi(arg) - 1;
198 if(tag_id != -1)
200 for(target_tag = globalconf.screens[screen].tags; target_tag && tag_id > 0;
201 target_tag = target_tag->next, tag_id--);
202 if(target_tag)
204 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
205 untag_client(sel, tag);
206 tag_client(sel, target_tag);
210 else
211 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
212 tag_client(sel, tag);
214 client_saveprops(sel);
215 arrange(screen);
218 /** Toggle a tag on client
219 * \param screen Screen ID
220 * \param arg Tag name
221 * \ingroup ui_callback
223 void
224 uicb_client_toggletag(int screen, char *arg)
226 Client *sel = globalconf.focus->client;
227 int i;
228 Tag *tag, *target_tag;
230 if(!sel)
231 return;
233 if(arg)
235 i = atoi(arg) - 1;
236 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
237 target_tag = target_tag->next, i--);
238 if(target_tag)
240 if(is_client_tagged(sel, target_tag))
241 untag_client(sel, target_tag);
242 else
243 tag_client(sel, target_tag);
246 /* check that there's at least one tag selected for this client*/
247 for(tag = globalconf.screens[screen].tags; tag
248 && !is_client_tagged(sel, tag); tag = tag->next)
250 if(!tag)
251 tag_client(sel, target_tag);
253 else
254 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
255 if(is_client_tagged(sel, tag))
256 tag_client(sel, tag);
257 else
258 untag_client(sel, tag);
260 client_saveprops(sel);
261 arrange(screen);
264 /** Add a tag to viewed tags
265 * \param screen Screen ID
266 * \param arg Tag name
267 * \ingroup ui_callback
269 void
270 uicb_tag_toggleview(int screen, char *arg)
272 int i;
273 Tag *tag, *target_tag;
275 if(arg)
277 i = atoi(arg) - 1;
278 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
279 target_tag = target_tag->next, i--);
281 if(target_tag)
282 target_tag->selected = !target_tag->selected;
284 /* check that there's at least one tag selected */
285 for(tag = globalconf.screens[screen].tags; tag && !tag->selected; tag = tag->next);
286 if(!tag)
287 target_tag->selected = True;
289 else
290 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
291 tag->selected = !tag->selected;
293 saveawesomeprops(screen);
294 arrange(screen);
295 ewmh_update_net_current_desktop(get_phys_screen(screen));
296 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
299 void
300 tag_view(int screen, int dindex)
302 Tag *target_tag, *tag;
304 if(dindex < 0)
305 return;
307 for(target_tag = globalconf.screens[screen].tags; target_tag && dindex > 0;
308 target_tag = target_tag->next, dindex--);
309 if(target_tag)
311 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
312 tag->selected = False;
313 target_tag->selected = True;
315 saveawesomeprops(screen);
316 arrange(screen);
317 ewmh_update_net_current_desktop(get_phys_screen(screen));
318 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
321 /** View tag
322 * \param screen Screen ID
323 * \param arg tag to view
324 * \ingroup ui_callback
326 void
327 uicb_tag_view(int screen, char *arg)
329 Tag *tag;
331 if(arg)
332 tag_view(screen, atoi(arg) - 1);
333 else
335 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
336 tag->selected = True;
337 saveawesomeprops(screen);
338 arrange(screen);
339 ewmh_update_net_current_desktop(get_phys_screen(screen));
340 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
344 /** View previously selected tags
345 * \param screen Screen ID
346 * \param arg unused
347 * \ingroup ui_callback
349 void
350 uicb_tag_prev_selected(int screen, char *arg __attribute__ ((unused)))
352 Tag *tag;
353 Bool t;
355 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
357 t = tag->selected;
358 tag->selected = tag->was_selected;
359 tag->was_selected = t;
361 arrange(screen);
362 ewmh_update_net_current_desktop(get_phys_screen(screen));
363 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
366 /** View next tag
367 * \param screen Screen ID
368 * \param arg unused
369 * \ingroup ui_callback
371 void
372 uicb_tag_viewnext(int screen, char *arg __attribute__ ((unused)))
374 Tag **curtags = get_current_tags(screen);
376 if(!curtags[0]->next)
377 return;
379 curtags[0]->selected = False;
380 curtags[0]->next->selected = True;
382 p_delete(&curtags);
384 saveawesomeprops(screen);
385 arrange(screen);
386 ewmh_update_net_current_desktop(get_phys_screen(screen));
387 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
390 /** View previous tag
391 * \param screen Screen ID
392 * \param arg unused
393 * \ingroup ui_callback
395 void
396 uicb_tag_viewprev(int screen, char *arg __attribute__ ((unused)))
398 Tag *tag, **curtags = get_current_tags(screen);
400 for(tag = globalconf.screens[screen].tags; tag && tag->next != curtags[0]; tag = tag->next);
401 if(tag)
403 tag->selected = True;
404 curtags[0]->selected = False;
405 saveawesomeprops(screen);
406 arrange(screen);
408 p_delete(&curtags);
409 ewmh_update_net_current_desktop(get_phys_screen(screen));
410 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
413 void
414 uicb_tag_create(int screen, char *arg)
416 Tag *last_tag, *tag;
418 if(!a_strlen(arg))
419 return;
421 for(last_tag = globalconf.screens[screen].tags; last_tag && last_tag->next; last_tag = last_tag->next);
422 last_tag->next = tag = p_new(Tag, 1);
423 tag->name = a_strdup(arg);
424 tag->layout = globalconf.screens[screen].layouts;
425 tag->mwfact = 0.5;
426 tag->nmaster = 1;
427 tag->ncol = 1;
428 widget_invalidate_cache(screen, WIDGET_CACHE_TAGS);
431 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80