change codename
[awesome.git] / tag.c
blobad8aca4babe64c9eaab6cef66f1ecfa3d8effb7d
1 /*
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.
22 #include "screen.h"
23 #include "tag.h"
24 #include "client.h"
25 #include "ewmh.h"
26 #include "widget.h"
27 #include "luaa.h"
29 /** Tag type */
30 struct tag
32 LUA_OBJECT_HEADER
33 /** Tag name */
34 char *name;
35 /** Screen */
36 screen_t *screen;
37 /** true if selected */
38 bool selected;
39 /** clients in this tag */
40 client_array_t clients;
43 static lua_class_t tag_class;
44 LUA_OBJECT_FUNCS(tag_class, tag_t, tag)
47 void
48 tag_unref_simplified(tag_t **tag)
50 luaA_object_unref(globalconf.L, *tag);
53 /** Garbage collect a tag.
54 * \param L The Lua VM state.
55 * \return 0.
57 static int
58 luaA_tag_gc(lua_State *L)
60 tag_t *tag = luaA_checkudata(L, 1, &tag_class);
61 client_array_wipe(&tag->clients);
62 p_delete(&tag->name);
63 return luaA_object_gc(L);
66 OBJECT_EXPORT_PROPERTY(tag, tag_t, selected)
67 OBJECT_EXPORT_PROPERTY(tag, tag_t, name)
69 /** View or unview a tag.
70 * \param L The Lua VM state.
71 * \param udx The index of the tag on the stack.
72 * \param view Set visible or not.
74 static void
75 tag_view(lua_State *L, int udx, bool view)
77 tag_t *tag = luaA_checkudata(L, udx, &tag_class);
78 if(tag->selected != view)
80 tag->selected = view;
82 if(tag->screen)
84 int screen_index = screen_array_indexof(&globalconf.screens, tag->screen);
86 banning_need_update(tag->screen);
88 ewmh_update_net_current_desktop(screen_virttophys(screen_index));
90 if(globalconf.hooks.tags != LUA_REFNIL)
92 lua_pushnumber(globalconf.L, screen_index + 1);
93 luaA_object_push(globalconf.L, tag);
94 if(view)
95 lua_pushliteral(globalconf.L, "select");
96 else
97 lua_pushliteral(globalconf.L, "unselect");
98 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.tags, 3, 0);
102 luaA_object_emit_signal(L, udx, "property::selected", 0);
106 /** Append a tag to a screen.
107 * \param L The Lua VM state.
108 * \param udx The tag index on the stack.
109 * \param s The screen.
111 void
112 tag_append_to_screen(lua_State *L, int udx, screen_t *s)
114 tag_t *tag = luaA_checkudata(globalconf.L, udx, &tag_class);
116 /* can't attach a tag twice */
117 if(tag->screen)
119 lua_remove(L, udx);
120 return;
123 int screen_index = screen_array_indexof(&globalconf.screens, s);
124 int phys_screen = screen_virttophys(screen_index);
126 tag->screen = s;
127 tag_array_append(&s->tags, luaA_object_ref_class(globalconf.L, udx, &tag_class));
128 ewmh_update_net_numbers_of_desktop(phys_screen);
129 ewmh_update_net_desktop_names(phys_screen);
131 luaA_object_push(globalconf.L, tag);
132 luaA_object_emit_signal(L, -1, "property::screen", 0);
133 lua_pop(L, 1);
135 /* call hook */
136 if(globalconf.hooks.tags != LUA_REFNIL)
138 lua_pushnumber(globalconf.L, screen_index + 1);
139 luaA_object_push(globalconf.L, tag);
140 lua_pushliteral(globalconf.L, "add");
141 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.tags, 3, 0);
144 luaA_object_push(globalconf.L, tag);
145 screen_emit_signal(globalconf.L, s, "tag::attach", 1);
148 /** Remove a tag from screen. Tag must be on a screen and have no clients.
149 * \param tag The tag to remove.
151 void
152 tag_remove_from_screen(tag_t *tag)
154 if(!tag->screen)
155 return;
157 int screen_index = screen_array_indexof(&globalconf.screens, tag->screen);
158 int phys_screen = screen_virttophys(screen_index);
159 tag_array_t *tags = &tag->screen->tags;
161 for(int i = 0; i < tags->len; i++)
162 if(tags->tab[i] == tag)
164 tag_array_take(tags, i);
165 break;
168 /* tag was selected? If so, reban */
169 if(tag->selected)
170 banning_need_update(tag->screen);
172 ewmh_update_net_numbers_of_desktop(phys_screen);
173 ewmh_update_net_desktop_names(phys_screen);
175 /* call hook */
176 if(globalconf.hooks.tags != LUA_REFNIL)
178 lua_pushnumber(globalconf.L, screen_index + 1);
179 luaA_object_push(globalconf.L, tag);
180 lua_pushliteral(globalconf.L, "remove");
181 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.tags, 3, 0);
184 screen_t *s = tag->screen;
185 tag->screen = NULL;
187 luaA_object_push(globalconf.L, tag);
188 luaA_object_emit_signal(globalconf.L, -1, "property::screen", 0);
189 screen_emit_signal(globalconf.L, s, "tag::detach", 1);
191 luaA_object_unref(globalconf.L, tag);
194 static void
195 tag_client_emit_signal(lua_State *L, tag_t *t, client_t *c, const char *signame)
197 luaA_object_push(L, c);
198 luaA_object_push(L, t);
199 /* emit signal on client, with new tag as argument */
200 luaA_object_emit_signal(L, -2, signame, 1);
201 /* re push tag */
202 luaA_object_push(L, t);
203 /* move tag before client */
204 lua_insert(L, -2);
205 luaA_object_emit_signal(L, -2, signame, 1);
206 /* Remove tag */
207 lua_pop(L, 1);
210 /** Tag a client with the tag on top of the stack.
211 * \param c the client to tag
213 void
214 tag_client(client_t *c)
216 tag_t *t = luaA_object_ref_class(globalconf.L, -1, &tag_class);
218 /* don't tag twice */
219 if(is_client_tagged(c, t))
221 luaA_object_unref(globalconf.L, t);
222 return;
225 client_array_append(&t->clients, c);
226 ewmh_client_update_desktop(c);
227 banning_need_update((c)->screen);
229 /* call hook */
230 if(globalconf.hooks.tagged != LUA_REFNIL)
232 luaA_object_push(globalconf.L, c);
233 luaA_object_push(globalconf.L, t);
234 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.tagged, 2, 0);
236 tag_client_emit_signal(globalconf.L, t, c, "tagged");
239 /** Untag a client with specified tag.
240 * \param c the client to tag
241 * \param t the tag to tag the client with
243 void
244 untag_client(client_t *c, tag_t *t)
246 for(int i = 0; i < t->clients.len; i++)
247 if(t->clients.tab[i] == c)
249 client_array_take(&t->clients, i);
250 banning_need_update((c)->screen);
251 ewmh_client_update_desktop(c);
252 /* call hook */
253 if(globalconf.hooks.tagged != LUA_REFNIL)
255 luaA_object_push(globalconf.L, c);
256 luaA_object_push(globalconf.L, t);
257 luaA_dofunction_from_registry(globalconf.L, globalconf.hooks.tagged, 2, 0);
259 tag_client_emit_signal(globalconf.L, t, c, "untagged");
260 luaA_object_unref(globalconf.L, t);
261 return;
265 /** Check if a client is tagged with the specified tag.
266 * \param c the client
267 * \param t the tag
268 * \return true if the client is tagged with the tag, false otherwise.
270 bool
271 is_client_tagged(client_t *c, tag_t *t)
273 for(int i = 0; i < t->clients.len; i++)
274 if(t->clients.tab[i] == c)
275 return true;
277 return false;
280 /** Get the index of the first selected tag.
281 * \param screen Screen.
282 * \return Its index.
285 tags_get_first_selected_index(screen_t *screen)
287 foreach(tag, screen->tags)
288 if((*tag)->selected)
289 return tag_array_indexof(&screen->tags, tag);
290 return 0;
293 /** Set a tag to be the only one viewed.
294 * \param target the tag to see
296 static void
297 tag_view_only(tag_t *target)
299 if(target)
300 foreach(tag, target->screen->tags)
302 luaA_object_push(globalconf.L, *tag);
303 tag_view(globalconf.L, -1, *tag == target);
304 lua_pop(globalconf.L, 1);
308 /** View only a tag, selected by its index.
309 * \param screen Screen.
310 * \param dindex The index.
312 void
313 tag_view_only_byindex(screen_t *screen, int dindex)
315 tag_array_t *tags = &screen->tags;
317 if(dindex < 0 || dindex >= tags->len)
318 return;
319 tag_view_only(tags->tab[dindex]);
322 /** Create a new tag.
323 * \param L The Lua VM state.
324 * \luastack
325 * \lparam A name.
326 * \lreturn A new tag object.
328 static int
329 luaA_tag_new(lua_State *L)
331 if(lua_isstring(L, 2))
333 /* compat code */
334 luaA_deprecate(L, "new syntax");
336 size_t len;
337 const char *name = luaL_checklstring(L, 2, &len);
338 tag_t *tag = tag_new(globalconf.L);
340 a_iso2utf8(name, len, &tag->name, NULL);
342 return 1;
345 return luaA_class_new(L, &tag_class);
348 /** Get or set the clients attached to this tag.
349 * \param L The Lua VM state.
350 * \return The number of elements pushed on stack.
351 * \luastack
352 * \lparam None or a table of clients to set.
353 * \lreturn A table with the clients attached to this tags.
355 static int
356 luaA_tag_clients(lua_State *L)
358 tag_t *tag = luaA_checkudata(L, 1, &tag_class);
359 client_array_t *clients = &tag->clients;
360 int i;
362 if(lua_gettop(L) == 2)
364 luaA_checktable(L, 2);
365 foreach(c, tag->clients)
367 /* Only untag if we aren't going to add this tag again */
368 bool found = false;
369 lua_pushnil(L);
370 while(lua_next(L, 2))
372 client_t *tc = luaA_checkudata(L, -1, &client_class);
373 /* Pop the value from lua_next */
374 lua_pop(L, 1);
375 if (tc != *c)
376 continue;
378 /* Pop the key from lua_next */
379 lua_pop(L, 1);
380 found = true;
381 break;
383 if(!found)
384 untag_client(*c, tag);
386 lua_pushnil(L);
387 while(lua_next(L, 2))
389 client_t *c = luaA_client_checkudata(L, -1);
390 /* push tag on top of the stack */
391 lua_pushvalue(L, 1);
392 tag_client(c);
393 lua_pop(L, 1);
397 lua_createtable(L, clients->len, 0);
398 for(i = 0; i < clients->len; i++)
400 if(clients->tab[i]->type == WINDOW_TYPE_DESKTOP)
401 continue;
402 luaA_object_push(L, clients->tab[i]);
403 lua_rawseti(L, -2, i + 1);
406 return 1;
409 LUA_OBJECT_EXPORT_PROPERTY(tag, tag_t, name, lua_pushstring)
410 LUA_OBJECT_EXPORT_PROPERTY(tag, tag_t, selected, lua_pushboolean)
412 /** Set the tag name.
413 * \param L The Lua VM state.
414 * \param tag The tag to name.
415 * \return The number of elements pushed on stack.
417 static int
418 luaA_tag_set_name(lua_State *L, tag_t *tag)
420 size_t len;
421 const char *buf = luaL_checklstring(L, -1, &len);
422 p_delete(&tag->name);
423 a_iso2utf8(buf, len, &tag->name, NULL);
424 luaA_object_emit_signal(L, -3, "property::name", 0);
425 return 0;
428 /** Set the tag selection status.
429 * \param L The Lua VM state.
430 * \param tag The tag to set the selection status for.
431 * \return The number of elements pushed on stack.
433 static int
434 luaA_tag_set_selected(lua_State *L, tag_t *tag)
436 tag_view(L, -3, luaA_checkboolean(L, -1));
437 return 0;
440 /** Set the tag screen.
441 * \param L The Lua VM state.
442 * \param tag The tag to set the screen for.
443 * \return The number of elements pushed on stack.
445 static int
446 luaA_tag_set_screen(lua_State *L, tag_t *tag)
448 int screen;
449 if(lua_isnil(L, -1))
450 screen = -1;
451 else
453 screen = luaL_checknumber(L, -1) - 1;
454 luaA_checkscreen(screen);
457 tag_remove_from_screen(tag);
459 if(screen != -1)
460 tag_append_to_screen(L, -3, &globalconf.screens.tab[screen]);
462 return 0;
465 /** Get the tag screen.
466 * \param L The Lua VM state.
467 * \param tag The tag to get the screen for.
468 * \return The number of elements pushed on stack.
470 static int
471 luaA_tag_get_screen(lua_State *L, tag_t *tag)
473 if(!tag->screen)
474 return 0;
475 lua_pushnumber(L, screen_array_indexof(&globalconf.screens, tag->screen) + 1);
476 return 1;
479 void
480 tag_class_setup(lua_State *L)
482 static const struct luaL_reg tag_methods[] =
484 LUA_CLASS_METHODS(tag)
485 { "__call", luaA_tag_new },
486 { NULL, NULL }
489 static const struct luaL_reg tag_meta[] =
491 LUA_OBJECT_META(tag)
492 LUA_CLASS_META
493 { "clients", luaA_tag_clients },
494 { "__gc", luaA_tag_gc },
495 { NULL, NULL },
498 luaA_class_setup(L, &tag_class, "tag", (lua_class_allocator_t) tag_new,
499 luaA_class_index_miss_property, luaA_class_newindex_miss_property,
500 tag_methods, tag_meta);
501 luaA_class_add_property(&tag_class, A_TK_NAME,
502 (lua_class_propfunc_t) luaA_tag_set_name,
503 (lua_class_propfunc_t) luaA_tag_get_name,
504 (lua_class_propfunc_t) luaA_tag_set_name);
505 luaA_class_add_property(&tag_class, A_TK_SCREEN,
506 (lua_class_propfunc_t) NULL,
507 (lua_class_propfunc_t) luaA_tag_get_screen,
508 (lua_class_propfunc_t) luaA_tag_set_screen);
509 luaA_class_add_property(&tag_class, A_TK_SELECTED,
510 (lua_class_propfunc_t) luaA_tag_set_selected,
511 (lua_class_propfunc_t) luaA_tag_get_selected,
512 (lua_class_propfunc_t) luaA_tag_set_selected);
515 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80