bug fix: XClassHint not copied correctly
[awesome.git] / tag.c
blobdf83e7a380d9ac0552d67ec34ab8d2ad669c0899
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 XGetClassHint(c->display, c->win, &ch);
72 len = a_strlen(ch.res_class) + a_strlen(ch.res_name) + a_strlen(c->name);
74 prop = p_new(char, len + 3);
76 /* rule matching */
77 snprintf(prop, len + 3, "%s:%s:%s",
78 ch.res_class ? ch.res_class : "", ch.res_name ? ch.res_name : "", c->name);
79 for(i = 0; i < awesomeconf->nrules; i++)
80 if(regs[i].propregex && !regexec(regs[i].propregex, prop, 1, &tmp, 0))
82 c->isfloating = awesomeconf->rules[i].isfloating;
83 for(j = 0; regs[i].tagregex && j < awesomeconf->ntags; j++)
84 if(!regexec(regs[i].tagregex, awesomeconf->tags[j].name, 1, &tmp, 0))
86 matched = True;
87 c->tags[j] = True;
90 p_delete(&prop);
91 if(ch.res_class)
92 XFree(ch.res_class);
93 if(ch.res_name)
94 XFree(ch.res_name);
95 if(!matched)
96 for(i = 0; i < awesomeconf->ntags; i++)
97 c->tags[i] = awesomeconf->tags[i].selected;
100 void
101 compileregs(Rule * rules, int nrules)
103 int i;
104 regex_t *reg;
106 if(regs)
107 return;
108 regs = p_new(Regs, nrules);
109 for(i = 0; i < nrules; i++)
111 if(rules[i].prop)
113 reg = p_new(regex_t, 1);
114 if(regcomp(reg, rules[i].prop, REG_EXTENDED))
115 p_delete(&reg);
116 else
117 regs[i].propregex = reg;
119 if(rules[i].tags)
121 reg = p_new(regex_t, 1);
122 if(regcomp(reg, rules[i].tags, REG_EXTENDED))
123 p_delete(&reg);
124 else
125 regs[i].tagregex = reg;
131 /** Returns True if a client is tagged
132 * with one of the tags
133 * \param c Client
134 * \param tags tag to check
135 * \param ntags number of tags in *tags
136 * \return True or False
138 Bool
139 isvisible(Client * c, int screen, Tag * tags, int ntags)
141 int i;
143 if(c->screen != screen)
144 return False;
146 for(i = 0; i < ntags; i++)
147 if(c->tags[i] && tags[i].selected)
148 return True;
149 return False;
153 /** Tag selected window with tag
154 * \param disp Display ref
155 * \param drawcontext Drawcontext ref
156 * \param arg Tag name
157 * \ingroup ui_callback
159 void
160 uicb_tag(Display *disp,
161 DC *drawcontext,
162 awesome_config *awesomeconf,
163 const char *arg)
165 int i;
167 if(!sel)
168 return;
169 for(i = 0; i < awesomeconf->ntags; i++)
170 sel->tags[i] = arg == NULL;
171 i = idxoftag(arg, awesomeconf->tags, awesomeconf->ntags);
172 if(i >= 0 && i < awesomeconf->ntags)
173 sel->tags[i] = True;
174 saveprops(sel, awesomeconf->ntags);
175 arrange(disp, drawcontext, awesomeconf);
178 /** Toggle floating state of a client
179 * \param disp Display ref
180 * \param drawcontext Drawcontext ref
181 * \param arg unused
182 * \ingroup ui_callback
184 void
185 uicb_togglefloating(Display *disp,
186 DC *drawcontext,
187 awesome_config * awesomeconf,
188 const char *arg __attribute__ ((unused)))
190 if(!sel)
191 return;
192 sel->isfloating = !sel->isfloating;
193 if(sel->isfloating)
194 /*restore last known float dimensions*/
195 resize(sel, sel->rx, sel->ry, sel->rw, sel->rh, True);
196 else
198 /*save last known float dimensions*/
199 sel->rx = sel->x;
200 sel->ry = sel->y;
201 sel->rw = sel->w;
202 sel->rh = sel->h;
204 saveprops(sel, awesomeconf->ntags);
205 arrange(disp, drawcontext, awesomeconf);
208 /** Toggle tag view
209 * \param disp Display ref
210 * \param drawcontext Drawcontext ref
211 * \param arg Tag name
212 * \ingroup ui_callback
214 void
215 uicb_toggletag(Display *disp,
216 DC *drawcontext,
217 awesome_config *awesomeconf,
218 const char *arg)
220 unsigned int i;
221 int j;
223 if(!sel)
224 return;
225 i = idxoftag(arg, awesomeconf->tags, awesomeconf->ntags);
226 sel->tags[i] = !sel->tags[i];
227 for(j = 0; j < awesomeconf->ntags && !sel->tags[j]; j++);
228 if(j == awesomeconf->ntags)
229 sel->tags[i] = True;
230 saveprops(sel, awesomeconf->ntags);
231 arrange(disp, drawcontext, awesomeconf);
234 /** Add a tag to viewed tags
235 * \param disp Display ref
236 * \param drawcontext Drawcontext ref
237 * \param arg Tag name
238 * \ingroup ui_callback
240 void
241 uicb_toggleview(Display *disp,
242 DC *drawcontext,
243 awesome_config *awesomeconf,
244 const char *arg)
246 unsigned int i;
247 int j;
249 i = idxoftag(arg, awesomeconf->tags, awesomeconf->ntags);
250 awesomeconf->tags[i].selected = !awesomeconf->tags[i].selected;
251 for(j = 0; j < awesomeconf->ntags && !awesomeconf->tags[j].selected; j++);
252 if(j == awesomeconf->ntags)
253 awesomeconf->tags[i].selected = True;
254 saveawesomeprops(disp, awesomeconf);
255 arrange(disp, drawcontext, awesomeconf);
258 /** View tag
259 * \param disp Display ref
260 * \param awesomeconf awesome config ref
261 * \param arg tag to view
262 * \ingroup ui_callback
264 void
265 uicb_view(Display *disp,
266 DC *drawcontext,
267 awesome_config *awesomeconf,
268 const char *arg)
270 int i;
272 for(i = 0; i < awesomeconf->ntags; i++)
274 awesomeconf->tags[i].was_selected = awesomeconf->tags[i].selected;
275 awesomeconf->tags[i].selected = arg == NULL;
277 i = idxoftag(arg, awesomeconf->tags, awesomeconf->ntags);
278 if(i >= 0 && i < awesomeconf->ntags)
280 awesomeconf->tags[i].selected = True;
281 awesomeconf->current_layout = awesomeconf->tags[i].layout;
283 saveawesomeprops(disp, awesomeconf);
284 arrange(disp, drawcontext, awesomeconf);
287 /** View previously selected tags
288 * \param disp Display ref
289 * \param awesomeconf awesome config ref
290 * \param arg unused
291 * \ingroup ui_callback
293 void
294 uicb_tag_prev_selected(Display * disp,
295 DC *drawcontext,
296 awesome_config *awesomeconf,
297 const char *arg __attribute__ ((unused)))
299 int i;
300 Bool t;
302 for(i = 0; i < awesomeconf->ntags; i++)
304 t = awesomeconf->tags[i].selected;
305 awesomeconf->tags[i].selected = awesomeconf->tags[i].was_selected;
306 awesomeconf->tags[i].was_selected = t;
308 arrange(disp, drawcontext, awesomeconf);
311 /** View next tag
312 * \param disp Display ref
313 * \param drawcontext Drawcontext ref
314 * \param arg unused
315 * \ingroup ui_callback
317 void
318 uicb_tag_viewnext(Display *disp,
319 DC * drawcontext,
320 awesome_config *awesomeconf,
321 const char *arg __attribute__ ((unused)))
323 int i;
324 int firsttag = -1;
326 for(i = 0; i < awesomeconf->ntags; i++)
328 if(firsttag < 0 && awesomeconf->tags[i].selected)
329 firsttag = i;
330 awesomeconf->tags[i].selected = False;
332 if(++firsttag >= awesomeconf->ntags)
333 firsttag = 0;
334 awesomeconf->tags[firsttag].selected = True;
335 awesomeconf->current_layout = awesomeconf->tags[firsttag].layout;
336 saveawesomeprops(disp, awesomeconf);
337 arrange(disp, drawcontext, awesomeconf);
340 /** View previous tag
341 * \param disp Display ref
342 * \param drawcontext Drawcontext ref
343 * \param arg unused
344 * \ingroup ui_callback
346 void
347 uicb_tag_viewprev(Display *disp,
348 DC *drawcontext,
349 awesome_config *awesomeconf,
350 const char *arg __attribute__ ((unused)))
352 int i;
353 int firsttag = -1;
355 for(i = awesomeconf->ntags - 1; i >= 0; i--)
357 if(firsttag < 0 && awesomeconf->tags[i].selected)
358 firsttag = i;
359 awesomeconf->tags[i].selected = False;
361 if(--firsttag < 0)
362 firsttag = awesomeconf->ntags - 1;
363 awesomeconf->tags[firsttag].selected = True;
364 awesomeconf->current_layout = awesomeconf->tags[firsttag].layout;
365 saveawesomeprops(disp, awesomeconf);
366 arrange(disp, drawcontext, awesomeconf);