2 * tag.c - tag management
4 * Copyright © 2007-2008 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.
23 #include <X11/Xutil.h>
32 extern AwesomeConf globalconf
;
34 /** Create a new tag. Parameteres values are checked.
35 * \param name tag name
36 * \param layout layout to use
37 * \param mwfact master width factor
38 * \param nmaster number of master windows
39 * \param ncol number of columns for slaves windows
40 * \return a new tag with all these parameters
43 tag_new(const char *name
, Layout
*layout
, double mwfact
, int nmaster
, int ncol
)
48 tag
->name
= a_strdup(name
);
52 if(tag
->mwfact
<= 0 || tag
->mwfact
>= 1)
55 if((tag
->nmaster
= nmaster
) < 0)
58 if((tag
->ncol
= ncol
) < 1)
64 /** Append a tag to a screen.
65 * \param tag the tag to append
66 * \param screen the screen id
69 tag_append_to_screen(Tag
*tag
, int screen
)
71 int phys_screen
= screen_virttophys(screen
);
74 tag_list_append(&globalconf
.screens
[screen
].tags
, tag
);
75 ewmh_update_net_numbers_of_desktop(phys_screen
);
76 ewmh_update_net_desktop_names(phys_screen
);
77 widget_invalidate_cache(screen
, WIDGET_CACHE_TAGS
);
80 /** Push a tag to a screen tag list.
81 * \param tag the tag to push
82 * \param screen the screen
85 tag_push_to_screen(Tag
*tag
, int screen
)
88 tag_list_push(&globalconf
.screens
[screen
].tags
, tag
);
89 widget_invalidate_cache(screen
, WIDGET_CACHE_TAGS
);
92 /** Tag a client with specified tag.
93 * \param c the client to tag
94 * \param t the tag to tag the client with
97 tag_client(Client
*c
, Tag
*t
)
99 tag_client_node_t
*tc
;
101 /* don't tag twice */
102 if(is_client_tagged(c
, t
))
105 tc
= p_new(tag_client_node_t
, 1);
108 tag_client_node_list_push(&globalconf
.tclink
, tc
);
111 widget_invalidate_cache(c
->screen
, WIDGET_CACHE_CLIENTS
);
112 globalconf
.screens
[c
->screen
].need_arrange
= True
;
115 /** Untag a client with specified tag.
116 * \param c the client to tag
117 * \param t the tag to tag the client with
120 untag_client(Client
*c
, Tag
*t
)
122 tag_client_node_t
*tc
;
124 for(tc
= globalconf
.tclink
; tc
; tc
= tc
->next
)
125 if(tc
->client
== c
&& tc
->tag
== t
)
127 tag_client_node_list_detach(&globalconf
.tclink
, tc
);
130 widget_invalidate_cache(c
->screen
, WIDGET_CACHE_CLIENTS
);
131 globalconf
.screens
[c
->screen
].need_arrange
= True
;
136 /** Check if a client is tagged with the specified tag.
137 * \param c the client
139 * \return true if the client is tagged with the tag, false otherwise.
142 is_client_tagged(Client
*c
, Tag
*t
)
144 tag_client_node_t
*tc
;
149 for(tc
= globalconf
.tclink
; tc
; tc
= tc
->next
)
150 if(tc
->client
== c
&& tc
->tag
== t
)
156 /** Tag the client with the currently selected (visible) tags.
157 * \param c the client
160 tag_client_with_current_selected(Client
*c
)
163 VirtScreen vscreen
= globalconf
.screens
[c
->screen
];
165 for(tag
= vscreen
.tags
; tag
; tag
= tag
->next
)
169 untag_client(c
, tag
);
172 /** Tag the client according to a rule.
173 * \param c the client
177 tag_client_with_rule(Client
*c
, Rule
*r
)
180 Bool matched
= False
;
184 /* check if at least one tag match */
185 for(tag
= globalconf
.screens
[c
->screen
].tags
; tag
; tag
= tag
->next
)
186 if(tag_match_rule(tag
, r
))
193 for(tag
= globalconf
.screens
[c
->screen
].tags
; tag
; tag
= tag
->next
)
194 if(tag_match_rule(tag
, r
))
197 untag_client(c
, tag
);
200 /** Get the current tags for the specified screen.
201 * Returned pointer must be p_delete'd after.
202 * \param screen screen id
203 * \return a double pointer of tag list finished with a NULL element
206 tags_get_current(int screen
)
208 Tag
*tag
, **tags
= NULL
;
211 tags
= p_new(Tag
*, n
);
212 for(tag
= globalconf
.screens
[screen
].tags
; tag
; tag
= tag
->next
)
215 p_realloc(&tags
, ++n
);
219 /* finish with null */
225 /** Tag focused client with tag.
226 * \param screen Screen ID
227 * \param arg Tag name
228 * \ingroup ui_callback
231 uicb_client_tag(int screen
, char *arg
)
234 Tag
*tag
, *target_tag
;
235 Client
*sel
= globalconf
.focus
->client
;
242 tag_id
= atoi(arg
) - 1;
245 for(target_tag
= globalconf
.screens
[screen
].tags
; target_tag
&& tag_id
> 0;
246 target_tag
= target_tag
->next
, tag_id
--);
249 for(tag
= globalconf
.screens
[screen
].tags
; tag
; tag
= tag
->next
)
250 untag_client(sel
, tag
);
251 tag_client(sel
, target_tag
);
256 for(tag
= globalconf
.screens
[screen
].tags
; tag
; tag
= tag
->next
)
257 tag_client(sel
, tag
);
260 /** Toggle a tag on focused client.
261 * \param screen virtual screen id
262 * \param arg tag number
263 * \ingroup ui_callback
266 uicb_client_toggletag(int screen
, char *arg
)
268 Client
*sel
= globalconf
.focus
->client
;
270 Bool is_sticky
= True
;
271 Tag
*tag
, *target_tag
;
279 for(target_tag
= globalconf
.screens
[screen
].tags
; target_tag
&& i
> 0;
280 target_tag
= target_tag
->next
, i
--);
283 if(is_client_tagged(sel
, target_tag
))
284 untag_client(sel
, target_tag
);
286 tag_client(sel
, target_tag
);
289 /* check that there's at least one tag selected for this client*/
290 for(tag
= globalconf
.screens
[screen
].tags
; tag
291 && !is_client_tagged(sel
, tag
); tag
= tag
->next
);
294 tag_client(sel
, target_tag
);
298 for(tag
= globalconf
.screens
[screen
].tags
; tag
; tag
= tag
->next
)
299 if(!is_client_tagged(sel
, tag
))
302 tag_client(sel
, tag
);
305 tag_client_with_current_selected(sel
);
309 /** Add a tag to the list of viewed tags.
310 * \param screen Screen ID
311 * \param arg Tag name
312 * \ingroup ui_callback
315 uicb_tag_toggleview(int screen
, char *arg
)
318 Tag
*tag
, *target_tag
,
319 **backtag
, **curtags
= tags_get_current(screen
);
324 for(target_tag
= globalconf
.screens
[screen
].tags
; target_tag
&& i
> 0;
325 target_tag
= target_tag
->next
, i
--);
328 tag_view(target_tag
, !target_tag
->selected
);
331 for(tag
= globalconf
.screens
[screen
].tags
; tag
; tag
= tag
->next
)
332 tag_view(tag
, !tag
->selected
);
334 /* check that there's at least one tag selected */
335 for(tag
= globalconf
.screens
[screen
].tags
; tag
&& !tag
->selected
; tag
= tag
->next
);
337 for(backtag
= curtags
; *backtag
; backtag
++)
338 tag_view(*backtag
, True
);
343 /** Set a tag to be the only one viewed.
344 * \param target the tag to see
347 tag_view_only(Tag
*target
)
353 for(tag
= globalconf
.screens
[target
->screen
].tags
; tag
; tag
= tag
->next
)
354 tag_view(tag
, tag
== target
);
357 /** Use an index to set a tag viewable.
358 * \param screen the screen id
359 * \param dindex the index
360 * \param view the view value
363 tag_view_byindex(int screen
, int dindex
, Bool view
)
370 for(tag
= globalconf
.screens
[screen
].tags
; tag
&& dindex
> 0;
371 tag
= tag
->next
, dindex
--);
375 /** View only a tag, selected by its index.
376 * \param screen screen id
377 * \param dindex the index
380 tag_view_only_byindex(int screen
, int dindex
)
387 for(tag
= globalconf
.screens
[screen
].tags
; tag
&& dindex
> 0;
388 tag
= tag
->next
, dindex
--);
392 /** View or unview a tag.
394 * \param view set visible or not
397 tag_view(Tag
*tag
, Bool view
)
399 tag
->was_selected
= tag
->selected
;
400 tag
->selected
= view
;
401 ewmh_update_net_current_desktop(screen_virttophys(tag
->screen
));
402 widget_invalidate_cache(tag
->screen
, WIDGET_CACHE_TAGS
);
403 globalconf
.screens
[tag
->screen
].need_arrange
= True
;
407 * \param screen Screen ID
408 * \param arg tag to view
409 * \ingroup ui_callback
412 uicb_tag_view(int screen
, char *arg
)
417 tag_view_only_byindex(screen
, atoi(arg
) - 1);
419 for(tag
= globalconf
.screens
[screen
].tags
; tag
; tag
= tag
->next
)
423 /** View previously selected tags
424 * \param screen Screen ID
426 * \ingroup ui_callback
429 uicb_tag_prev_selected(int screen
, char *arg
__attribute__ ((unused
)))
433 for(tag
= globalconf
.screens
[screen
].tags
; tag
; tag
= tag
->next
)
434 tag_view(tag
, tag
->was_selected
);
438 * \param screen Screen ID
440 * \ingroup ui_callback
443 uicb_tag_viewnext(int screen
, char *arg
__attribute__ ((unused
)))
445 Tag
*tag
, **curtags
= tags_get_current(screen
);
447 tag
= tag_list_next_cycle(&globalconf
.screens
[screen
].tags
, curtags
[0]);
449 tag_view(curtags
[0], False
);
455 /** View previous tag.
456 * \param screen Screen ID
458 * \ingroup ui_callback
461 uicb_tag_viewprev(int screen
, char *arg
__attribute__ ((unused
)))
463 Tag
*tag
, **curtags
= tags_get_current(screen
);
465 tag
= tag_list_prev_cycle(&globalconf
.screens
[screen
].tags
, curtags
[0]);
467 tag_view(curtags
[0], False
);
473 /** Create a new tag. Argument must be the tag name.
474 * \param screen the screen id
475 * \param arg the tag name
478 uicb_tag_create(int screen
, char *arg
)
485 tag
= tag_new(arg
, globalconf
.screens
[screen
].layouts
, 0.5, 1, 1);
486 tag_append_to_screen(tag
, screen
);
489 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80