2 * tasklist.c - task 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.
26 #include "common/markup.h"
27 #include "common/tokenize.h"
29 extern awesome_t globalconf
;
31 /** Link a client and a label */
36 /** The client label */
38 /** The client label len */
42 /** Delete a client label.
43 * \param l The client label.
46 client_label_wipe(client_label_t
*l
)
51 DO_ARRAY(client_label_t
, client_label
, client_label_wipe
)
53 typedef struct tasklist_object_data_t tasklist_object_data_t
;
54 /** Link an object with a client label array and other infos */
55 struct tasklist_object_data_t
59 /** The box width for each client */
61 /** The client label array for the object */
62 client_label_array_t client_labels
;
64 tasklist_object_data_t
*prev
, *next
;
68 tasklist_object_data_delete(tasklist_object_data_t
**l
)
70 client_label_array_wipe(&(*l
)->client_labels
);
74 DO_SLIST(tasklist_object_data_t
, tasklist_object_data
, tasklist_object_data_delete
)
76 /** The tasklist private data structure. */
81 tasklist_object_data_t
*objects_data
;
84 /** Get an object data by its object.
85 * \param od The object data list.
86 * \param p The object.
87 * \return A object data or NULL if not found.
89 static tasklist_object_data_t
*
90 tasklist_object_data_getbyobj(tasklist_object_data_t
*od
, void *p
)
92 tasklist_object_data_t
*o
;
94 for(o
= od
; o
; o
= o
->next
)
101 /** Draw a tasklist widget.
102 * \param ctx The draw context.
103 * \param screen The screen number.
104 * \param w The widget node we are called from.
105 * \param offset The offset to draw at.
106 * \param used The already used width.
107 * \param p A pointer to the object we're drawing onto.
108 * \param type The object type.
109 * \return The widget width.
112 tasklist_draw(draw_context_t
*ctx
, int screen
,
114 int offset
, int used
, void *p
,
118 tasklist_data_t
*d
= w
->widget
->data
;
120 int i
= 0, icon_width
= 0, box_width_rest
= 0;
122 draw_parser_data_t pdata
, *parser_data
;
123 tasklist_object_data_t
*odata
;
125 if(used
>= ctx
->width
)
126 return (w
->area
.width
= 0);
128 if(!(odata
= tasklist_object_data_getbyobj(d
->objects_data
, p
)))
130 odata
= p_new(tasklist_object_data_t
, 1);
132 tasklist_object_data_list_push(&d
->objects_data
, odata
);
135 client_label_array_wipe(&odata
->client_labels
);
136 client_label_array_init(&odata
->client_labels
);
138 for(c
= globalconf
.clients
; c
; c
= c
->next
)
139 if(!c
->skip
&& !c
->skiptb
)
142 luaA_client_userdata_new(globalconf
.L
, c
);
143 /* push screen we're at */
144 lua_pushnumber(globalconf
.L
, screen
+ 1);
145 /* call label function with client as argument and wait for one
147 if(luaA_dofunction(globalconf
.L
, d
->label
, 2, 1))
149 /* If we got a string as returned value, we got something to write:
150 * a label. So we store it in a client_label_t structure, pushed
151 * into the client_label_array_t which is owned by the object. */
152 if(lua_isstring(globalconf
.L
, -1))
156 cl
.label
= a_strdup(lua_tolstring(globalconf
.L
, -1, &cl
.label_len
));
157 client_label_array_append(&odata
->client_labels
, cl
);
160 lua_pop(globalconf
.L
, 1);
164 if(!odata
->client_labels
.len
)
165 return (w
->area
.width
= 0);
167 odata
->box_width
= (ctx
->width
- used
) / odata
->client_labels
.len
;
168 /* compute how many pixel we left empty */
169 box_width_rest
= (ctx
->width
- used
) % odata
->client_labels
.len
;
171 w
->area
.x
= widget_calculate_offset(ctx
->width
,
172 0, offset
, w
->widget
->align
);
176 for(i
= 0; i
< odata
->client_labels
.len
; i
++)
182 draw_parser_data_init(&pdata
);
184 pdata
.connection
= ctx
->connection
;
185 pdata
.phys_screen
= ctx
->phys_screen
;
187 /* Actually look for the proper background color, since
188 * otherwise the background statusbar color is used instead */
189 if(draw_text_markup_expand(&pdata
,
190 odata
->client_labels
.tab
[i
].label
,
191 odata
->client_labels
.tab
[i
].label_len
))
193 parser_data
= &pdata
;
194 if(pdata
.has_bg_color
)
196 /* draw a background for icons */
197 area
.x
= w
->area
.x
+ odata
->box_width
* i
;
199 area
.height
= ctx
->height
;
200 area
.width
= odata
->box_width
;
201 draw_rectangle(ctx
, area
, 1.0, true, &pdata
.bg_color
);
207 if((image
= draw_image_new(odata
->client_labels
.tab
[i
].client
->icon_path
)))
209 icon_width
= ((double) ctx
->height
/ (double) image
->height
) * image
->width
;
210 draw_image(ctx
, w
->area
.x
+ odata
->box_width
* i
,
211 w
->area
.y
, ctx
->height
, image
);
212 draw_image_delete(&image
);
215 if(!icon_width
&& odata
->client_labels
.tab
[i
].client
->icon
)
217 netwm_icon_t
*icon
= odata
->client_labels
.tab
[i
].client
->icon
;
218 icon_width
= ((double) ctx
->height
/ (double) icon
->height
)
220 draw_image_from_argb_data(ctx
,
221 w
->area
.x
+ odata
->box_width
* i
,
223 icon
->width
, icon
->height
,
224 ctx
->height
, icon
->image
);
230 area
.x
= w
->area
.x
+ icon_width
+ odata
->box_width
* i
;
232 area
.width
= odata
->box_width
- icon_width
;
233 area
.height
= ctx
->height
;
235 /* if we're on last elem, it has the last pixels left */
236 if(i
== odata
->client_labels
.len
- 1)
237 area
.width
+= box_width_rest
;
239 draw_text(ctx
, globalconf
.font
, area
,
240 odata
->client_labels
.tab
[i
].label
,
241 odata
->client_labels
.tab
[i
].label_len
,
243 draw_parser_data_wipe(parser_data
);
246 w
->area
.width
= ctx
->width
- used
;
247 w
->area
.height
= ctx
->height
;
249 return w
->area
.width
;
252 /** Handle button click on tasklist.
253 * \param w The widget node.
254 * \param ev The button press event.
255 * \param screen The screen where the click was.
256 * \param object The object we're onto.
257 * \param type The type object.
260 tasklist_button_press(widget_node_t
*w
,
261 xcb_button_press_event_t
*ev
,
267 tasklist_data_t
*d
= w
->widget
->data
;
269 tasklist_object_data_t
*odata
;
271 odata
= tasklist_object_data_getbyobj(d
->objects_data
, object
);
273 if(!odata
|| !odata
->client_labels
.len
)
276 ci
= (ev
->event_x
- w
->area
.x
) / odata
->box_width
;
278 for(b
= w
->widget
->buttons
; b
; b
= b
->next
)
279 if(ev
->detail
== b
->button
&& XUTIL_MASK_CLEAN(ev
->state
) == b
->mod
&& b
->fct
)
281 luaA_pushpointer(globalconf
.L
, object
, type
);
282 luaA_client_userdata_new(globalconf
.L
, odata
->client_labels
.tab
[ci
].client
);
283 luaA_dofunction(globalconf
.L
, b
->fct
, 2, 0);
288 * \param L The Lua VM state.
289 * \param token The key token.
290 * \return The number of elements pushed on stack.
292 * \lfield show_icons Show icons near client title.
293 * \lfield label Function used to get the string to display as the window title.
294 * It gets the client and a screen number as argument, and must return a string.
297 luaA_tasklist_index(lua_State
*L
, awesome_token_t token
)
299 widget_t
**widget
= luaA_checkudata(L
, 1, "widget");
300 tasklist_data_t
*d
= (*widget
)->data
;
304 case A_TK_SHOW_ICONS
:
305 lua_pushboolean(L
, d
->show_icons
);
308 lua_rawgeti(L
, LUA_REGISTRYINDEX
, d
->label
);
315 /** Newindex function for tasklist widget.
316 * \param L The Lua VM state.
317 * \param token The key token.
318 * \return The number of elements pushed on stack.
321 luaA_tasklist_newindex(lua_State
*L
, awesome_token_t token
)
323 widget_t
**widget
= luaA_checkudata(L
, 1, "widget");
324 tasklist_data_t
*d
= (*widget
)->data
;
328 case A_TK_SHOW_ICONS
:
329 d
->show_icons
= luaA_checkboolean(L
, 3);
332 luaA_registerfct(L
, &d
->label
);
338 widget_invalidate_bywidget(*widget
);
343 /** Destructor for the tasklist widget.
344 * \param widget The widget to destroy.
347 tasklist_destructor(widget_t
*widget
)
349 tasklist_data_t
*d
= widget
->data
;
350 tasklist_object_data_list_wipe(&d
->objects_data
);
354 /** Tasklist detach function.
355 * \param widget The widget which is detaching.
356 * \param object The object we are leaving.
359 tasklist_detach(widget_t
*widget
, void *object
)
361 tasklist_data_t
*d
= widget
->data
;
362 tasklist_object_data_t
*od
;
364 if((od
= tasklist_object_data_getbyobj(d
->objects_data
, object
)))
366 tasklist_object_data_list_detach(&d
->objects_data
, od
);
367 tasklist_object_data_delete(&od
);
371 /** Create a new widget tasklist.
372 * \param align The widget alignment, which is flex anyway.
373 * \return A brand new tasklist widget.
376 tasklist_new(alignment_t align
__attribute__ ((unused
)))
381 w
= p_new(widget_t
, 1);
382 widget_common_new(w
);
383 w
->draw
= tasklist_draw
;
384 w
->button_press
= tasklist_button_press
;
385 w
->align
= AlignFlex
;
386 w
->index
= luaA_tasklist_index
;
387 w
->newindex
= luaA_tasklist_newindex
;
388 w
->data
= d
= p_new(tasklist_data_t
, 1);
389 w
->destructor
= tasklist_destructor
;
390 w
->detach
= tasklist_detach
;
392 d
->show_icons
= true;
393 d
->label
= LUA_REFNIL
;
395 /* Set cache property */
396 w
->cache_flags
= WIDGET_CACHE_CLIENTS
| WIDGET_CACHE_TAGS
;
401 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80