bug fix: previous commit broke Zaphod mode in spawn()
[awesome.git] / tag.c
blob8e9ceda3ef9daf484a7aac39c326eabc3a927732
1 /*
2 * tag.c - tag management
3 *
4 * Copyright © 2007 Julien Danjou <julien@danjou.info>
5 *
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 "layout.h"
26 #include "tag.h"
27 #include "util.h"
29 extern Client *sel; /* global client list */
31 typedef struct
33 regex_t *propregex;
34 regex_t *tagregex;
35 } Regs;
37 static Regs *regs = NULL;
39 /** This function returns the index of
40 * the tag given un argument in *tags
41 * \param tag_to_find tag name
42 * \param tags tag list
43 * \param ntags number of tags in tag list
44 * \return index of tag
46 static int
47 idxoftag(const char *tag_to_find, Tag *tags, int ntags)
49 int i;
51 if(!tag_to_find)
52 return 0;
54 for(i = 0; i < ntags; i++)
55 if(!a_strcmp(tags[i].name, tag_to_find))
56 return i;
58 return 0;
61 void
62 applyrules(Client * c, awesome_config *awesomeconf)
64 int i, j, len = 0;
65 regmatch_t tmp;
66 Bool matched = False;
67 XClassHint ch = { 0, 0 };
68 char *prop;
70 len += a_strlen(ch.res_class) + a_strlen(ch.res_name) + a_strlen(c->name);
72 prop = p_new(char, len + 1);
74 /* rule matching */
75 XGetClassHint(c->display, c->win, &ch);
76 snprintf(prop, len + 1, "%s:%s:%s",
77 ch.res_class ? ch.res_class : "", ch.res_name ? ch.res_name : "", c->name);
78 for(i = 0; i < awesomeconf->nrules; i++)
79 if(regs[i].propregex && !regexec(regs[i].propregex, prop, 1, &tmp, 0))
81 c->isfloating = awesomeconf->rules[i].isfloating;
82 for(j = 0; regs[i].tagregex && j < awesomeconf->ntags; j++)
83 if(!regexec(regs[i].tagregex, awesomeconf->tags[j].name, 1, &tmp, 0))
85 matched = True;
86 c->tags[j] = True;
89 p_delete(&prop);
90 if(ch.res_class)
91 XFree(ch.res_class);
92 if(ch.res_name)
93 XFree(ch.res_name);
94 if(!matched)
95 for(i = 0; i < awesomeconf->ntags; i++)
96 c->tags[i] = awesomeconf->tags[i].selected;
99 void
100 compileregs(Rule * rules, int nrules)
102 int i;
103 regex_t *reg;
105 if(regs)
106 return;
107 regs = p_new(Regs, nrules);
108 for(i = 0; i < nrules; i++)
110 if(rules[i].prop)
112 reg = p_new(regex_t, 1);
113 if(regcomp(reg, rules[i].prop, REG_EXTENDED))
114 p_delete(&reg);
115 else
116 regs[i].propregex = reg;
118 if(rules[i].tags)
120 reg = p_new(regex_t, 1);
121 if(regcomp(reg, rules[i].tags, REG_EXTENDED))
122 p_delete(&reg);
123 else
124 regs[i].tagregex = reg;
130 /** Returns True if a client is tagged
131 * with one of the tags
132 * \param c Client
133 * \param tags tag to check
134 * \param ntags number of tags in *tags
135 * \return True or False
137 Bool
138 isvisible(Client * c, int screen, Tag * tags, int ntags)
140 int i;
142 if(c->screen != screen)
143 return False;
145 for(i = 0; i < ntags; i++)
146 if(c->tags[i] && tags[i].selected)
147 return True;
148 return False;
152 /** Tag selected window with tag
153 * \param disp Display ref
154 * \param drawcontext Drawcontext ref
155 * \param arg Tag name
156 * \ingroup ui_callback
158 void
159 uicb_tag(Display *disp,
160 DC *drawcontext,
161 awesome_config *awesomeconf,
162 const char *arg)
164 int i;
166 if(!sel)
167 return;
168 for(i = 0; i < awesomeconf->ntags; i++)
169 sel->tags[i] = arg == NULL;
170 i = idxoftag(arg, awesomeconf->tags, awesomeconf->ntags);
171 if(i >= 0 && i < awesomeconf->ntags)
172 sel->tags[i] = True;
173 saveprops(sel, awesomeconf->ntags);
174 arrange(disp, drawcontext, awesomeconf);
177 /** Toggle floating state of a client
178 * \param disp Display ref
179 * \param drawcontext Drawcontext ref
180 * \param arg unused
181 * \ingroup ui_callback
183 void
184 uicb_togglefloating(Display *disp,
185 DC *drawcontext,
186 awesome_config * awesomeconf,
187 const char *arg __attribute__ ((unused)))
189 if(!sel)
190 return;
191 sel->isfloating = !sel->isfloating;
192 if(sel->isfloating)
193 /*restore last known float dimensions*/
194 resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
195 else
197 /*save last known float dimensions*/
198 sel->rx = sel->x;
199 sel->ry = sel->y;
200 sel->rw = sel->w;
201 sel->rh = sel->h;
203 saveprops(sel, awesomeconf->ntags);
204 arrange(disp, drawcontext, awesomeconf);
207 /** Toggle tag view
208 * \param disp Display ref
209 * \param drawcontext Drawcontext ref
210 * \param arg Tag name
211 * \ingroup ui_callback
213 void
214 uicb_toggletag(Display *disp,
215 DC *drawcontext,
216 awesome_config *awesomeconf,
217 const char *arg)
219 unsigned int i;
220 int j;
222 if(!sel)
223 return;
224 i = idxoftag(arg, awesomeconf->tags, awesomeconf->ntags);
225 sel->tags[i] = !sel->tags[i];
226 for(j = 0; j < awesomeconf->ntags && !sel->tags[j]; j++);
227 if(j == awesomeconf->ntags)
228 sel->tags[i] = True;
229 saveprops(sel, awesomeconf->ntags);
230 arrange(disp, drawcontext, awesomeconf);
233 /** Add a tag to viewed tags
234 * \param disp Display ref
235 * \param drawcontext Drawcontext ref
236 * \param arg Tag name
237 * \ingroup ui_callback
239 void
240 uicb_toggleview(Display *disp,
241 DC *drawcontext,
242 awesome_config *awesomeconf,
243 const char *arg)
245 unsigned int i;
246 int j;
248 i = idxoftag(arg, awesomeconf->tags, awesomeconf->ntags);
249 awesomeconf->tags[i].selected = !awesomeconf->tags[i].selected;
250 for(j = 0; j < awesomeconf->ntags && !awesomeconf->tags[j].selected; j++);
251 if(j == awesomeconf->ntags)
252 awesomeconf->tags[i].selected = True;
253 saveawesomeprops(disp, awesomeconf);
254 arrange(disp, drawcontext, awesomeconf);
257 /** View tag
258 * \param disp Display ref
259 * \param awesomeconf awesome config ref
260 * \param arg tag to view
261 * \ingroup ui_callback
263 void
264 uicb_view(Display *disp,
265 DC *drawcontext,
266 awesome_config *awesomeconf,
267 const char *arg)
269 int i;
271 for(i = 0; i < awesomeconf->ntags; i++)
273 awesomeconf->tags[i].was_selected = awesomeconf->tags[i].selected;
274 awesomeconf->tags[i].selected = arg == NULL;
276 i = idxoftag(arg, awesomeconf->tags, awesomeconf->ntags);
277 if(i >= 0 && i < awesomeconf->ntags)
279 awesomeconf->tags[i].selected = True;
280 awesomeconf->current_layout = awesomeconf->tags[i].layout;
282 saveawesomeprops(disp, awesomeconf);
283 arrange(disp, drawcontext, awesomeconf);
286 /** View previously selected tags
287 * \param disp Display ref
288 * \param awesomeconf awesome config ref
289 * \param arg unused
290 * \ingroup ui_callback
292 void
293 uicb_tag_prev_selected(Display * disp,
294 DC *drawcontext,
295 awesome_config *awesomeconf,
296 const char *arg __attribute__ ((unused)))
298 int i;
299 Bool t;
301 for(i = 0; i < awesomeconf->ntags; i++)
303 t = awesomeconf->tags[i].selected;
304 awesomeconf->tags[i].selected = awesomeconf->tags[i].was_selected;
305 awesomeconf->tags[i].was_selected = t;
307 arrange(disp, drawcontext, awesomeconf);
310 /** View next tag
311 * \param disp Display ref
312 * \param drawcontext Drawcontext ref
313 * \param arg unused
314 * \ingroup ui_callback
316 void
317 uicb_tag_viewnext(Display *disp,
318 DC * drawcontext,
319 awesome_config *awesomeconf,
320 const char *arg __attribute__ ((unused)))
322 int i;
323 int firsttag = -1;
325 for(i = 0; i < awesomeconf->ntags; i++)
327 if(firsttag < 0 && awesomeconf->tags[i].selected)
328 firsttag = i;
329 awesomeconf->tags[i].selected = False;
331 if(++firsttag >= awesomeconf->ntags)
332 firsttag = 0;
333 awesomeconf->tags[firsttag].selected = True;
334 awesomeconf->current_layout = awesomeconf->tags[firsttag].layout;
335 saveawesomeprops(disp, awesomeconf);
336 arrange(disp, drawcontext, awesomeconf);
339 /** View previous tag
340 * \param disp Display ref
341 * \param drawcontext Drawcontext ref
342 * \param arg unused
343 * \ingroup ui_callback
345 void
346 uicb_tag_viewprev(Display *disp,
347 DC *drawcontext,
348 awesome_config *awesomeconf,
349 const char *arg __attribute__ ((unused)))
351 int i;
352 int firsttag = -1;
354 for(i = awesomeconf->ntags - 1; i >= 0; i--)
356 if(firsttag < 0 && awesomeconf->tags[i].selected)
357 firsttag = i;
358 awesomeconf->tags[i].selected = False;
360 if(--firsttag < 0)
361 firsttag = awesomeconf->ntags - 1;
362 awesomeconf->tags[firsttag].selected = True;
363 awesomeconf->current_layout = awesomeconf->tags[firsttag].layout;
364 saveawesomeprops(disp, awesomeconf);
365 arrange(disp, drawcontext, awesomeconf);