screen: reset statusbar and windows properly on padding changes
[awesome.git] / widgets / taglist.c
blobd2eac6bbfee0064ea0deb08b0c2b6a7c4a8fa88c
1 /*
2 * taglist.c - tag list widget
4 * Copyright © 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 "client.h"
23 #include "widget.h"
24 #include "tag.h"
25 #include "lua.h"
26 #include "common/tokenize.h"
28 extern awesome_t globalconf;
30 /** Data type used to store where we draw the taglist for a particular object.
31 * This is filled in the draw function, and use later when we get a click.
33 typedef struct taglist_drawn_area_t taglist_drawn_area_t;
34 struct taglist_drawn_area_t
36 void *object;
37 area_array_t areas;
38 taglist_drawn_area_t *next, *prev;
41 /** Delete a taglist_drawn_area_t object.
42 * \param a The drawn area to delete.
44 static void
45 taglist_drawn_area_delete(taglist_drawn_area_t **a)
47 area_array_wipe(&(*a)->areas);
48 p_delete(a);
51 DO_SLIST(taglist_drawn_area_t, taglist_drawn_area, taglist_drawn_area_delete);
53 /** Taglist widget private data */
54 typedef struct
56 taglist_drawn_area_t *drawn_area;
57 luaA_ref label;
58 } taglist_data_t;
60 static taglist_drawn_area_t *
61 taglist_drawn_area_getbyobj(taglist_drawn_area_t *list, void *p)
63 taglist_drawn_area_t *t;
65 for(t = list; t; t = t->next)
66 if(t->object == p)
67 return t;
69 return NULL;
72 /** Draw a taglist.
73 * \param ctx The draw context.
74 * \param screen The screen we're drawing for.
75 * \param w The widget node we're drawing for.
76 * \param offset Offset to draw at.
77 * \param used Space already used.
78 * \param object The object pointer we're drawing onto.
79 * \param type The object type.
80 * \return The width used.
82 static int
83 taglist_draw(draw_context_t *ctx, int screen, widget_node_t *w,
84 int offset,
85 int used __attribute__ ((unused)),
86 void *object,
87 awesome_type_t type)
89 taglist_data_t *data = w->widget->data;
90 area_t area;
91 taglist_drawn_area_t *tda;
92 int prev_width = 0;
94 tag_array_t *tags = &globalconf.screens[screen].tags;
95 const char **text = p_alloca(const char *, tags->len);
96 size_t *len = p_alloca(size_t, tags->len);
97 draw_parser_data_t *pdata = p_alloca(draw_parser_data_t, tags->len);
99 w->area.width = w->area.y = 0;
101 /* Lookup for our taglist_drawn_area.
102 * This will be used to store area where we draw tag list for each object. */
103 if(!(tda = taglist_drawn_area_getbyobj(data->drawn_area, object)))
105 /* Oh, we did not find a drawn area for our object. First time? */
106 tda = p_new(taglist_drawn_area_t, 1);
107 tda->object = object;
108 taglist_drawn_area_list_push(&data->drawn_area, tda);
111 tda->areas.len = 0;
113 /* First compute text and widget width */
114 for(int i = 0; i < tags->len; i++)
116 tag_t *tag = tags->tab[i];
117 p_clear(&area, 1);
119 luaA_tag_userdata_new(globalconf.L, tag);
120 if(luaA_dofunction(globalconf.L, data->label, 1, 1))
122 if(lua_isstring(globalconf.L, -1))
123 text[i] = lua_tolstring(globalconf.L, -1, &len[i]);
125 lua_pop(globalconf.L, 1);
127 draw_parser_data_init(&pdata[i]);
128 area = draw_text_extents(ctx->connection, ctx->phys_screen,
129 globalconf.font, text[i], len[i], &pdata[i]);
131 if(pdata[i].bg_image)
132 area.width = MAX(area.width,
133 pdata[i].bg_resize ? ((double) pdata[i].bg_image->width / (double) pdata[i].bg_image->height) * w->area.height : pdata[i].bg_image->width);
135 w->area.width += area.width;
137 area_array_append(&tda->areas, area);
140 /* Now that we have widget width we can compute widget x coordinate */
141 w->area.x = widget_calculate_offset(ctx->width, w->area.width,
142 offset, w->widget->align);
144 for(int i = 0; i < tags->len; i++)
146 area_t *r = &tda->areas.tab[i];
148 r->x = w->area.x + prev_width;
149 prev_width += r->width;
150 draw_text(ctx, globalconf.font, *r, text[i], len[i], &pdata[i]);
151 draw_parser_data_wipe(&pdata[i]);
154 w->area.height = ctx->height;
155 return w->area.width;
158 /** Handle button click on tasklist.
159 * \param w The widget node.
160 * \param ev The button press event.
161 * \param screen The screen where the click was.
162 * \param object The object we're onto.
163 * \param type The type object.
165 static void
166 taglist_button_press(widget_node_t *w,
167 xcb_button_press_event_t *ev,
168 int screen,
169 void *object,
170 awesome_type_t type)
172 tag_array_t *tags = &globalconf.screens[screen].tags;
173 button_t *b;
174 taglist_data_t *data = w->widget->data;
175 taglist_drawn_area_t *tda;
177 /* Find the good drawn area list */
178 if((tda = taglist_drawn_area_getbyobj(data->drawn_area, object)))
179 for(b = w->widget->buttons; b; b = b->next)
180 if(ev->detail == b->button && XUTIL_MASK_CLEAN(ev->state) == b->mod && b->fct)
181 for(int i = 0; i < MIN(tags->len, tda->areas.len); i++)
183 tag_t *tag = tags->tab[i];
184 area_t *area = &tda->areas.tab[i];
185 if(ev->event_x >= AREA_LEFT(*area)
186 && ev->event_x < AREA_RIGHT(*area))
188 luaA_pushpointer(globalconf.L, object, type);
189 luaA_tag_userdata_new(globalconf.L, tag);
190 luaA_dofunction(globalconf.L, b->fct, 2, 0);
191 return;
196 /** Taglist widget.
197 * \param L The Lua VM state.
198 * \param token The key token.
199 * \return The number of elements pushed on stack.
200 * \luastack
201 * \lfield label Function used to get the string to display as the tag title.
202 * It gets the tag as argument, and must return a string.
204 static int
205 luaA_taglist_index(lua_State *L, awesome_token_t token)
207 widget_t **widget = luaA_checkudata(L, 1, "widget");
208 taglist_data_t *d = (*widget)->data;
210 switch(token)
212 case A_TK_LABEL:
213 lua_rawgeti(L, LUA_REGISTRYINDEX, d->label);
214 return 1;
215 default:
216 return 0;
220 /** Newindex function for taglist.
221 * \param L The Lua VM state.
222 * \param token The key token.
223 * \return The number of elements pushed on stack.
225 static int
226 luaA_taglist_newindex(lua_State *L, awesome_token_t token)
228 widget_t **widget = luaA_checkudata(L, 1, "widget");
229 taglist_data_t *d = (*widget)->data;
231 switch(token)
233 case A_TK_LABEL:
234 luaA_registerfct(L, &d->label);
235 break;
236 default:
237 return 0;
240 widget_invalidate_bywidget(*widget);
242 return 0;
245 /** Taglist destructor.
246 * \param widget The widget to destroy.
248 static void
249 taglist_destructor(widget_t *widget)
251 taglist_data_t *d = widget->data;
253 taglist_drawn_area_list_wipe(&d->drawn_area);
254 p_delete(&d);
257 /** Taglist detach function.
258 * \param widget The widget which is detaching.
259 * \param object The object we are leaving.
261 static void
262 taglist_detach(widget_t *widget, void *object)
264 taglist_data_t *d = widget->data;
265 taglist_drawn_area_t *tda;
267 if((tda = taglist_drawn_area_getbyobj(d->drawn_area, object)))
269 taglist_drawn_area_list_detach(&d->drawn_area, tda);
270 taglist_drawn_area_delete(&tda);
274 /** Create a brand new taglist widget.
275 * \param align Widget alignment.
276 * \return A taglist widget.
278 widget_t *
279 taglist_new(alignment_t align)
281 widget_t *w;
282 taglist_data_t *d;
284 w = p_new(widget_t, 1);
285 widget_common_new(w);
286 w->index = luaA_taglist_index;
287 w->newindex = luaA_taglist_newindex;
288 w->align = align;
289 w->draw = taglist_draw;
290 w->button_press = taglist_button_press;
291 w->destructor = taglist_destructor;
292 w->detach = taglist_detach;
294 w->data = d = p_new(taglist_data_t, 1);
295 d->label = LUA_REFNIL;
297 /* Set cache property */
298 w->cache_flags = WIDGET_CACHE_TAGS | WIDGET_CACHE_CLIENTS;
300 return w;
303 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80