awful: create history dir if does not exists
[awesome.git] / widget.c
blobcb4ea47015c0b3e73bb7d9433420270e21d61320
1 /*
2 * widget.c - widget managing
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 <math.h>
24 #include <xcb/xcb.h>
25 #include <xcb/xcb_atom.h>
27 #include "widget.h"
28 #include "titlebar.h"
29 #include "common/atoms.h"
31 extern awesome_t globalconf;
33 DO_LUA_NEW(extern, widget_t, widget, "widget", widget_ref)
34 DO_LUA_GC(widget_t, widget, "widget", widget_unref)
35 DO_LUA_EQ(widget_t, widget, "widget")
37 #include "widgetgen.h"
39 /** Compute offset for drawing the first pixel of a widget.
40 * \param barwidth The statusbar width.
41 * \param widgetwidth The widget width.
42 * \param alignment The widget alignment on statusbar.
43 * \return The x coordinate to draw at.
45 int
46 widget_calculate_offset(int barwidth, int widgetwidth, int offset, int alignment)
48 switch(alignment)
50 case AlignLeft:
51 case AlignFlex:
52 return offset;
54 return barwidth - offset - widgetwidth;
57 /** Common function for button press event on widget.
58 * It will look into configuration to find the callback function to call.
59 * \param w The widget node.
60 * \param ev The button press event the widget received.
61 * \param screen The screen number.
62 * \param p The object where user clicked.
63 * \param type The object type.
65 static void
66 widget_common_button_press(widget_node_t *w,
67 xcb_button_press_event_t *ev,
68 int screen __attribute__ ((unused)),
69 void *p,
70 awesome_type_t type)
72 button_t *b;
74 for(b = w->widget->buttons; b; b = b->next)
75 if(ev->detail == b->button && XUTIL_MASK_CLEAN(ev->state) == b->mod && b->fct)
77 luaA_pushpointer(globalconf.L, p, type);
78 luaA_dofunction(globalconf.L, b->fct, 1, 0);
82 /** Render a list of widgets.
83 * \param wnode The list of widgets.
84 * \param ctx The draw context where to render.
85 * \param rotate_px The rotate pixmap: where to rotate and render the final
86 * \param screen The logical screen used to render.
87 * \param position The object position.
88 * \param x The x coordinates of the object.
89 * \param y The y coordinates of the object.
90 * pixmap when the object position is right or left.
91 * \param object The object pointer.
92 * \param type The object type.
93 * \todo Remove GC.
95 void
96 widget_render(widget_node_t *wnode, draw_context_t *ctx, xcb_gcontext_t gc, xcb_pixmap_t rotate_px,
97 int screen, position_t position,
98 int x, int y, void *object, awesome_type_t type)
100 xcb_pixmap_t rootpix;
101 xcb_screen_t *s;
102 widget_node_t *w;
103 int left = 0, right = 0;
104 char *data;
105 xcb_get_property_reply_t *prop_r;
106 xcb_get_property_cookie_t prop_c;
107 area_t rectangle = { 0, 0, 0, 0 };
109 rectangle.width = ctx->width;
110 rectangle.height = ctx->height;
112 if(ctx->bg.alpha != 0xffff)
114 s = xutil_screen_get(globalconf.connection, ctx->phys_screen);
115 prop_c = xcb_get_property_unchecked(globalconf.connection, false, s->root, _XROOTPMAP_ID,
116 PIXMAP, 0, 1);
117 if((prop_r = xcb_get_property_reply(globalconf.connection, prop_c, NULL)))
119 if(prop_r->value_len
120 && (data = xcb_get_property_value(prop_r))
121 && (rootpix = *(xcb_pixmap_t *) data))
122 switch(position)
124 case Left:
125 draw_rotate(ctx,
126 rootpix, ctx->pixmap,
127 s->width_in_pixels, s->height_in_pixels,
128 ctx->width, ctx->height,
129 M_PI_2,
130 y + ctx->width,
131 - x);
132 break;
133 case Right:
134 draw_rotate(ctx,
135 rootpix, ctx->pixmap,
136 s->width_in_pixels, s->height_in_pixels,
137 ctx->width, ctx->height,
138 - M_PI_2,
139 - y,
140 x + ctx->height);
141 break;
142 default:
143 xcb_copy_area(globalconf.connection, rootpix,
144 rotate_px, gc,
145 x, y,
146 0, 0,
147 ctx->width, ctx->height);
148 break;
150 p_delete(&prop_r);
154 draw_rectangle(ctx, rectangle, 1.0, true, &ctx->bg);
156 for(w = wnode; w; w = w->next)
157 if(w->widget->align == AlignLeft && w->widget->isvisible)
158 left += w->widget->draw(ctx, screen, w, left, (left + right), object, type);
160 /* renders right widget from last to first */
161 for(w = *widget_node_list_last(&wnode); w; w = w->prev)
162 if(w->widget->align == AlignRight && w->widget->isvisible)
163 right += w->widget->draw(ctx, screen, w, right, (left + right), object, type);
165 for(w = wnode; w; w = w->next)
166 if(w->widget->align == AlignFlex && w->widget->isvisible)
167 left += w->widget->draw(ctx, screen, w, left, (left + right), object, type);
169 switch(position)
171 case Right:
172 draw_rotate(ctx, ctx->pixmap, rotate_px,
173 ctx->width, ctx->height,
174 ctx->height, ctx->width,
175 M_PI_2, ctx->height, 0);
176 break;
177 case Left:
178 draw_rotate(ctx, ctx->pixmap, rotate_px,
179 ctx->width, ctx->height,
180 ctx->height, ctx->width,
181 - M_PI_2, 0, ctx->width);
182 break;
183 default:
184 break;
189 /** Common function for creating a widget.
190 * \param widget The allocated widget.
192 void
193 widget_common_new(widget_t *widget)
195 widget->align = AlignLeft;
196 widget->button_press = widget_common_button_press;
199 /** Invalidate widgets which should be refresh upon
200 * external modifications. widget_t who watch flags will
201 * be set to be refreshed.
202 * \param screen Virtual screen number.
203 * \param flags Cache flags to invalidate.
205 void
206 widget_invalidate_cache(int screen, int flags)
208 statusbar_t *statusbar;
209 widget_node_t *widget;
211 for(statusbar = globalconf.screens[screen].statusbar;
212 statusbar;
213 statusbar = statusbar->next)
214 for(widget = statusbar->widgets; widget; widget = widget->next)
215 if(widget->widget->cache_flags & flags)
217 statusbar->need_update = true;
218 break;
222 /** Set a statusbar needs update because it has widget, or redraw a titlebar.
223 * \todo Probably needs more optimization.
224 * \param widget The widget to look for.
226 void
227 widget_invalidate_bywidget(widget_t *widget)
229 int screen;
230 statusbar_t *statusbar;
231 widget_node_t *witer;
232 client_t *c;
234 for(screen = 0; screen < globalconf.screens_info->nscreen; screen++)
235 for(statusbar = globalconf.screens[screen].statusbar;
236 statusbar;
237 statusbar = statusbar->next)
238 if(!statusbar->need_update)
239 for(witer = statusbar->widgets; witer; witer = witer->next)
240 if(witer->widget == widget)
242 statusbar->need_update = true;
243 break;
246 for(c = globalconf.clients; c; c = c->next)
247 if(c->titlebar && !c->titlebar->need_update)
248 for(witer = c->titlebar->widgets; witer; witer = witer->next)
249 if(witer->widget == widget)
250 c->titlebar->need_update = true;
253 /** Create a new widget.
254 * \param L The Lua VM state.
256 * \luastack
257 * \lparam A table with at least a name and a type value. Optional attributes
258 * are: align.
259 * \lreturn A brand new widget.
261 static int
262 luaA_widget_new(lua_State *L)
264 const char *buf, *type;
265 widget_t *w = NULL;
266 widget_constructor_t *wc;
267 alignment_t align;
268 size_t len;
270 luaA_checktable(L, 2);
272 buf = luaA_getopt_lstring(L, 2, "align", "left", &len);
273 align = draw_align_fromstr(buf, len);
275 if(!(buf = luaA_getopt_string(L, 2, "name", NULL)))
276 luaL_error(L, "object widget must have a name");
278 type = luaA_getopt_string(L, 2, "type", NULL);
280 if((wc = name_func_lookup(type, WidgetList)))
281 w = wc(align);
282 else
283 luaL_error(L, "unkown widget type: %s", type);
285 w->type = wc;
287 /* Set visible by default. */
288 w->isvisible = true;
290 w->name = a_strdup(buf);
292 return luaA_widget_userdata_new(L, w);
295 /** Add a mouse button bindings to a widget.
296 * \param L The Lua VM state.
298 * \luastack
299 * \lvalue A widget.
300 * \lparam A mouse button bindings object.
302 static int
303 luaA_widget_mouse_add(lua_State *L)
305 widget_t **widget = luaA_checkudata(L, 1, "widget");
306 button_t **b = luaA_checkudata(L, 2, "mouse");
308 button_list_push(&(*widget)->buttons, *b);
309 button_ref(b);
311 return 0;
314 /** Remove a mouse button bindings from a widget.
315 * \param L The Lua VM state.
317 * \luastack
318 * \lvalue A widget.
319 * \lparam A mouse button bindings object.
321 static int
322 luaA_widget_mouse_remove(lua_State *L)
324 widget_t **widget = luaA_checkudata(L, 1, "widget");
325 button_t **b = luaA_checkudata(L, 2, "mouse");
327 button_list_detach(&(*widget)->buttons, *b);
328 button_unref(b);
330 return 0;
333 /** Convert a widget into a printable string.
334 * \param L The Lua VM state.
336 * \luastack
337 * \lvalue A widget.
339 static int
340 luaA_widget_tostring(lua_State *L)
342 widget_t **p = luaA_checkudata(L, 1, "widget");
343 lua_pushfstring(L, "[widget udata(%p) name(%s)]", *p, (*p)->name);
344 return 1;
347 /** Generic widget.
348 * \param L The Lua VM state.
349 * \return The number of elements pushed on stack.
350 * \luastack
351 * \lfield visible The widget visibility.
352 * \lfield name The widget name.
354 static int
355 luaA_widget_index(lua_State *L)
357 size_t len;
358 widget_t **widget = luaA_checkudata(L, 1, "widget");
359 const char *buf = luaL_checklstring(L, 2, &len);
360 awesome_token_t token;
362 if(luaA_usemetatable(L, 1, 2))
363 return 1;
365 switch((token = a_tokenize(buf, len)))
367 case A_TK_VISIBLE:
368 lua_pushboolean(L, (*widget)->isvisible);
369 return 1;
370 case A_TK_NAME:
371 lua_pushstring(L, (*widget)->name);
372 return 1;
373 default:
374 break;
377 return (*widget)->index ? (*widget)->index(L, token) : 0;
380 /** Generic widget newindex.
381 * \param L The Lua VM state.
382 * \return The number of elements pushed on stack.
384 static int
385 luaA_widget_newindex(lua_State *L)
387 size_t len;
388 widget_t **widget = luaA_checkudata(L, 1, "widget");
389 const char *buf = luaL_checklstring(L, 2, &len);
390 awesome_token_t token;
392 switch((token = a_tokenize(buf, len)))
394 case A_TK_VISIBLE:
395 (*widget)->isvisible = luaA_checkboolean(L, 3);
396 return 0;
397 default:
398 break;
401 return (*widget)->newindex ? (*widget)->newindex(L, token) : 0;
404 /** Generic widget set.
405 * \param L The Lua VM state.
406 * \param idx The table of widgets index.
407 * \param object The object the widget will be attached to.
408 * \param widgets The widgets to fill.
409 * \return The number of elements pushed on stack.
411 void
412 luaA_widget_set(lua_State *L, int idx, void *object, widget_node_t **widgets)
414 widget_node_t *witer;
416 luaA_checktable(L, idx);
418 /* remove all widgets */
419 for(witer = *widgets; witer; witer = *widgets)
421 if(witer->widget->detach)
422 witer->widget->detach(witer->widget, object);
423 widget_unref(&witer->widget);
424 widget_node_list_detach(widgets, witer);
425 p_delete(&witer);
428 /* now read all widgets and add them */
429 lua_pushnil(L);
430 while(lua_next(L, idx))
432 widget_t **widget = luaA_checkudata(L, -1, "widget");
433 widget_node_t *w = p_new(widget_node_t, 1);
434 w->widget = *widget;
435 widget_node_list_append(widgets, w);
436 widget_ref(widget);
437 lua_pop(L, 1);
441 /** Generic widget get.
442 * \param L The Lua VM state.
443 * \param widget The widget list.
444 * \return The number of elements pushed on stack.
447 luaA_widget_get(lua_State *L, widget_node_t *widgets)
449 widget_node_t *witer;
450 int i = 0;
452 lua_newtable(L);
454 for(witer = widgets; witer; witer = witer->next)
456 luaA_widget_userdata_new(L, witer->widget);
457 lua_rawseti(L, -2, ++i);
460 return 1;
463 const struct luaL_reg awesome_widget_methods[] =
465 { "__call", luaA_widget_new },
466 { NULL, NULL }
468 const struct luaL_reg awesome_widget_meta[] =
470 { "mouse_add", luaA_widget_mouse_add },
471 { "mouse_remove", luaA_widget_mouse_remove },
472 { "__index", luaA_widget_index },
473 { "__newindex", luaA_widget_newindex },
474 { "__gc", luaA_widget_gc },
475 { "__eq", luaA_widget_eq },
476 { "__tostring", luaA_widget_tostring },
477 { NULL, NULL }
480 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80