add support for NET_WM_STATE and NET_WM_STATE_STICKY
[awesome.git] / tag.c
blob2172cc64b72696655b902ac172b579d4c4ebae9e
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 "layout.h"
27 #include "tag.h"
28 #include "util.h"
29 #include "rules.h"
30 #include "ewmh.h"
32 extern AwesomeConf globalconf;
34 static void
35 detach_tagclientlink(int screen, TagClientLink *tc)
37 TagClientLink *tmp;
39 if(globalconf.screens[screen].tclink == tc)
40 globalconf.screens[screen].tclink = tc->next;
41 else
43 for(tmp = globalconf.screens[screen].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, int screen)
53 TagClientLink *tc, *new_tc;
55 /* don't tag twice */
56 if(is_client_tagged(c, t, screen))
57 return;
59 new_tc = p_new(TagClientLink, 1);
61 if(!globalconf.screens[screen].tclink)
62 globalconf.screens[screen].tclink = new_tc;
63 else
65 for(tc = globalconf.screens[screen].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, int screen)
76 TagClientLink *tc;
78 for(tc = globalconf.screens[screen].tclink; tc; tc = tc->next)
79 if(tc->client == c && tc->tag == t)
80 detach_tagclientlink(screen, tc);
83 Bool
84 is_client_tagged(Client *c, Tag *t, int screen)
86 TagClientLink *tc;
88 if(!c || c->screen != screen)
89 return False;
91 for(tc = globalconf.screens[screen].tclink; tc; tc = tc->next)
92 if(tc->client == c && tc->tag == t)
93 return True;
94 return False;
97 void
98 tag_client_with_current_selected(Client *c)
100 Tag *tag;
101 VirtScreen vscreen = globalconf.screens[c->screen];
103 for(tag = vscreen.tags; tag; tag = tag->next)
104 if(tag->selected)
105 tag_client(c, tag, c->screen);
106 else
107 untag_client(c, tag, c->screen);
110 void
111 tag_client_with_rules(Client *c)
113 Rule *r;
114 Tag *tag;
115 Bool matched = False;
117 for(r = globalconf.rules; r; r = r->next)
118 if(client_match_rule(c, r))
120 c->isfloating = r->isfloating;
122 if(r->screen != RULE_NOSCREEN && r->screen != c->screen)
123 move_client_to_screen(c, r->screen, True);
125 for(tag = globalconf.screens[c->screen].tags; tag; tag = tag->next)
126 if(is_tag_match_rules(tag, r))
128 matched = True;
129 tag_client(c, tag, c->screen);
131 else
132 untag_client(c, tag, c->screen);
134 if(!matched)
135 tag_client_with_current_selected(c);
136 break;
141 Tag **
142 get_current_tags(int screen)
144 Tag *tag, **tags = NULL;
145 int n = 1;
147 tags = p_new(Tag *, n);
148 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
149 if(tag->selected)
151 p_realloc(&tags, ++n);
152 tags[n - 2] = tag;
155 /* finish with null */
156 tags[n - 1] = NULL;
158 return tags;
161 /** Tag selected window with tag
162 * \param screen Screen ID
163 * \param arg Tag name
164 * \ingroup ui_callback
166 void
167 uicb_client_tag(int screen, char *arg)
169 int tag_id = -1;
170 Tag *tag, *target_tag;
171 Client *sel = globalconf.focus->client;
173 if(!sel)
174 return;
176 if(arg)
178 tag_id = atoi(arg) - 1;
179 if(tag_id != -1)
181 for(target_tag = globalconf.screens[screen].tags; target_tag && tag_id > 0;
182 target_tag = target_tag->next, tag_id--);
183 if(target_tag)
185 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
186 untag_client(sel, tag, screen);
187 tag_client(sel, target_tag, screen);
191 else
192 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
193 tag_client(sel, tag, screen);
195 client_saveprops(sel, screen);
196 arrange(screen);
199 /** Toggle floating state of a client
200 * \param screen Screen ID
201 * \param arg unused
202 * \ingroup ui_callback
204 void
205 uicb_client_togglefloating(int screen, char *arg __attribute__ ((unused)))
207 Client *sel = globalconf.focus->client;
209 if(!sel)
210 return;
212 sel->isfloating = !sel->isfloating;
214 if (arg == NULL)
215 client_resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True, False);
216 else
217 client_resize(sel, sel->x, sel->y, sel->w, sel->h, True, True);
219 client_saveprops(sel, screen);
220 arrange(screen);
223 /** Toggle a tag on client
224 * \param screen Screen ID
225 * \param arg Tag name
226 * \ingroup ui_callback
228 void
229 uicb_client_toggletag(int screen, char *arg)
231 Client *sel = globalconf.focus->client;
232 int i;
233 Tag *tag, *target_tag;
235 if(!sel)
236 return;
238 if(arg)
240 i = atoi(arg) - 1;
241 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
242 target_tag = target_tag->next, i--);
243 if(target_tag)
245 if(is_client_tagged(sel, target_tag, screen))
246 untag_client(sel, target_tag, screen);
247 else
248 tag_client(sel, target_tag, screen);
251 /* check that there's at least one tag selected for this client*/
252 for(tag = globalconf.screens[screen].tags; tag
253 && !is_client_tagged(sel, tag, screen); tag = tag->next)
255 if(!tag)
256 tag_client(sel, target_tag, screen);
258 else
259 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
260 if(is_client_tagged(sel, tag, screen))
261 tag_client(sel, tag, screen);
262 else
263 untag_client(sel, tag, screen);
265 client_saveprops(sel, screen);
266 arrange(screen);
269 /** Add a tag to viewed tags
270 * \param screen Screen ID
271 * \param arg Tag name
272 * \ingroup ui_callback
274 void
275 uicb_tag_toggleview(int screen, char *arg)
277 int i;
278 Tag *tag, *target_tag;
280 if(arg)
282 i = atoi(arg) - 1;
283 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
284 target_tag = target_tag->next, i--);
286 if(target_tag)
287 target_tag->selected = !target_tag->selected;
289 /* check that there's at least one tag selected */
290 for(tag = globalconf.screens[screen].tags; tag && !tag->selected; tag = tag->next);
291 if(!tag)
292 target_tag->selected = True;
294 else
295 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
296 tag->selected = !tag->selected;
298 saveawesomeprops(screen);
299 arrange(screen);
300 ewmh_update_net_current_desktop(get_phys_screen(screen));
303 /** View tag
304 * \param screen Screen ID
305 * \param arg tag to view
306 * \ingroup ui_callback
308 void
309 uicb_tag_view(int screen, char *arg)
311 int i;
312 Tag *tag, *target_tag;
314 if(arg)
316 i = atoi(arg) - 1;
317 for(target_tag = globalconf.screens[screen].tags; target_tag && i > 0;
318 target_tag = target_tag->next, i--);
319 if(target_tag)
321 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
322 tag->selected = False;
323 target_tag->selected = True;
326 else
327 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
328 tag->selected = True;
330 saveawesomeprops(screen);
331 arrange(screen);
332 ewmh_update_net_current_desktop(get_phys_screen(screen));
335 /** View previously selected tags
336 * \param screen Screen ID
337 * \param arg unused
338 * \ingroup ui_callback
340 void
341 uicb_tag_prev_selected(int screen, char *arg __attribute__ ((unused)))
343 Tag *tag;
344 Bool t;
346 for(tag = globalconf.screens[screen].tags; tag; tag = tag->next)
348 t = tag->selected;
349 tag->selected = tag->was_selected;
350 tag->was_selected = t;
352 arrange(screen);
353 ewmh_update_net_current_desktop(get_phys_screen(screen));
356 /** View next tag
357 * \param screen Screen ID
358 * \param arg unused
359 * \ingroup ui_callback
361 void
362 uicb_tag_viewnext(int screen, char *arg __attribute__ ((unused)))
364 Tag **curtags = get_current_tags(screen);
366 if(!curtags[0]->next)
367 return;
369 curtags[0]->selected = False;
370 curtags[0]->next->selected = True;
372 p_delete(&curtags);
374 saveawesomeprops(screen);
375 arrange(screen);
376 ewmh_update_net_current_desktop(get_phys_screen(screen));
379 /** View previous tag
380 * \param screen Screen ID
381 * \param arg unused
382 * \ingroup ui_callback
384 void
385 uicb_tag_viewprev(int screen, char *arg __attribute__ ((unused)))
387 Tag *tag, **curtags = get_current_tags(screen);
389 for(tag = globalconf.screens[screen].tags; tag && tag->next != curtags[0]; tag = tag->next);
390 if(tag)
392 tag->selected = True;
393 curtags[0]->selected = False;
394 saveawesomeprops(screen);
395 arrange(screen);
397 p_delete(&curtags);
398 ewmh_update_net_current_desktop(get_phys_screen(screen));
400 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80