ta{g,sk}list: fix memory leak on removal
[awesome.git] / wibox.c
blob48cf3dc93604bc06d8a268ad4ccf4ba0cd0312af
1 /*
2 * wibox.c - wibox functions
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 "screen.h"
23 #include "wibox.h"
24 #include "titlebar.h"
25 #include "client.h"
26 #include "ewmh.h"
27 #include "screen.h"
28 #include "window.h"
29 #include "common/xcursor.h"
30 #include "common/xutil.h"
32 DO_LUA_TOSTRING(wibox_t, wibox, "wibox")
34 /** Take care of garbage collecting a wibox.
35 * \param L The Lua VM state.
36 * \return The number of elements pushed on stack, 0!
38 static int
39 luaA_wibox_gc(lua_State *L)
41 wibox_t *wibox = luaL_checkudata(L, 1, "wibox");
42 luaA_ref_array_wipe(&wibox->refs);
43 p_delete(&wibox->cursor);
44 simplewindow_wipe(&wibox->sw);
45 button_array_wipe(&wibox->buttons);
46 image_unref(L, wibox->bg_image);
47 luaL_unref(L, LUA_REGISTRYINDEX, wibox->widgets_table);
48 luaL_unref(L, LUA_REGISTRYINDEX, wibox->mouse_enter);
49 luaL_unref(L, LUA_REGISTRYINDEX, wibox->mouse_leave);
50 widget_node_array_wipe(&wibox->widgets);
51 return 0;
54 void
55 wibox_unref_simplified(wibox_t **item)
57 wibox_unref(globalconf.L, *item);
60 static void
61 wibox_need_update(wibox_t *wibox)
63 wibox->need_update = true;
64 wibox->mouse_over = NULL;
67 static void
68 wibox_map(wibox_t *wibox)
70 xcb_map_window(globalconf.connection, wibox->sw.window);
71 /* We must make sure the wibox does not display garbage */
72 wibox_need_update(wibox);
73 /* Stack this wibox correctly */
74 client_stack();
77 static void
78 wibox_move(wibox_t *wibox, int16_t x, int16_t y)
80 if(wibox->sw.window)
82 simplewindow_move(&wibox->sw, x, y);
83 wibox->screen = screen_getbycoord(wibox->screen, x, y);
85 else
87 wibox->sw.geometry.x = x;
88 wibox->sw.geometry.y = y;
92 static void
93 wibox_resize(wibox_t *wibox, uint16_t width, uint16_t height)
95 if(wibox->sw.window)
96 simplewindow_resize(&wibox->sw, width, height);
97 else
99 wibox->sw.geometry.width = width;
100 wibox->sw.geometry.height = height;
102 wibox_need_update(wibox);
105 static void
106 wibox_setposition(wibox_t *wibox, position_t p)
108 if(p != wibox->position)
110 switch((wibox->position = p))
112 case Bottom:
113 case Top:
114 case Floating:
115 simplewindow_orientation_set(&wibox->sw, East);
116 break;
117 case Left:
118 simplewindow_orientation_set(&wibox->sw, North);
119 break;
120 case Right:
121 simplewindow_orientation_set(&wibox->sw, South);
122 break;
124 /* reset width/height to 0 */
125 if(wibox->position != Floating)
126 wibox->sw.geometry.width = wibox->sw.geometry.height = 0;
128 /* recompute position */
129 wibox_position_update(wibox);
131 /* reset all wibox position */
132 foreach(w, wibox->screen->wiboxes)
133 wibox_position_update(*w);
135 ewmh_update_workarea(screen_virttophys(screen_array_indexof(&globalconf.screens, wibox->screen)));
137 wibox_need_update(wibox);
141 /** Kick out systray windows.
142 * \param phys_screen Physical screen number.
144 static void
145 wibox_systray_kickout(int phys_screen)
147 xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
149 if(globalconf.screens.tab[phys_screen].systray.parent != s->root)
151 /* Who! Check that we're not deleting a wibox with a systray, because it
152 * may be its parent. If so, we reparent to root before, otherwise it will
153 * hurt very much. */
154 xcb_reparent_window(globalconf.connection,
155 globalconf.screens.tab[phys_screen].systray.window,
156 s->root, -512, -512);
158 globalconf.screens.tab[phys_screen].systray.parent = s->root;
162 static void
163 wibox_systray_refresh(wibox_t *wibox)
165 if(!wibox->screen)
166 return;
168 for(int i = 0; i < wibox->widgets.len; i++)
170 widget_node_t *systray = &wibox->widgets.tab[i];
171 if(systray->widget->type == widget_systray)
173 uint32_t config_back[] = { wibox->sw.ctx.bg.pixel };
174 uint32_t config_win_vals[4];
175 uint32_t config_win_vals_off[2] = { -512, -512 };
176 xembed_window_t *em;
177 int phys_screen = wibox->sw.ctx.phys_screen;
179 if(wibox->isvisible
180 && systray->widget->isvisible
181 && systray->geometry.width)
183 /* Set background of the systray window. */
184 xcb_change_window_attributes(globalconf.connection,
185 globalconf.screens.tab[phys_screen].systray.window,
186 XCB_CW_BACK_PIXEL, config_back);
187 /* Map it. */
188 xcb_map_window(globalconf.connection, globalconf.screens.tab[phys_screen].systray.window);
189 /* Move it. */
190 switch(wibox->sw.orientation)
192 case North:
193 config_win_vals[0] = systray->geometry.y;
194 config_win_vals[1] = wibox->sw.geometry.height - systray->geometry.x - systray->geometry.width;
195 config_win_vals[2] = systray->geometry.height;
196 config_win_vals[3] = systray->geometry.width;
197 break;
198 case South:
199 config_win_vals[0] = systray->geometry.y;
200 config_win_vals[1] = systray->geometry.x;
201 config_win_vals[2] = systray->geometry.height;
202 config_win_vals[3] = systray->geometry.width;
203 break;
204 case East:
205 config_win_vals[0] = systray->geometry.x;
206 config_win_vals[1] = systray->geometry.y;
207 config_win_vals[2] = systray->geometry.width;
208 config_win_vals[3] = systray->geometry.height;
209 break;
211 /* reparent */
212 if(globalconf.screens.tab[phys_screen].systray.parent != wibox->sw.window)
214 xcb_reparent_window(globalconf.connection,
215 globalconf.screens.tab[phys_screen].systray.window,
216 wibox->sw.window,
217 config_win_vals[0], config_win_vals[1]);
218 globalconf.screens.tab[phys_screen].systray.parent = wibox->sw.window;
220 xcb_configure_window(globalconf.connection,
221 globalconf.screens.tab[phys_screen].systray.window,
222 XCB_CONFIG_WINDOW_X
223 | XCB_CONFIG_WINDOW_Y
224 | XCB_CONFIG_WINDOW_WIDTH
225 | XCB_CONFIG_WINDOW_HEIGHT,
226 config_win_vals);
227 /* width = height = systray height */
228 config_win_vals[2] = config_win_vals[3] = systray->geometry.height;
229 config_win_vals[0] = 0;
231 else
232 return wibox_systray_kickout(phys_screen);
234 switch(wibox->sw.orientation)
236 case North:
237 config_win_vals[1] = systray->geometry.width - config_win_vals[3];
238 for(int j = 0; j < globalconf.embedded.len; j++)
240 em = &globalconf.embedded.tab[j];
241 if(em->phys_screen == phys_screen)
243 if(config_win_vals[1] - config_win_vals[2] >= (uint32_t) wibox->sw.geometry.y)
245 xcb_map_window(globalconf.connection, em->win);
246 xcb_configure_window(globalconf.connection, em->win,
247 XCB_CONFIG_WINDOW_X
248 | XCB_CONFIG_WINDOW_Y
249 | XCB_CONFIG_WINDOW_WIDTH
250 | XCB_CONFIG_WINDOW_HEIGHT,
251 config_win_vals);
252 config_win_vals[1] -= config_win_vals[3];
254 else
255 xcb_configure_window(globalconf.connection, em->win,
256 XCB_CONFIG_WINDOW_X
257 | XCB_CONFIG_WINDOW_Y,
258 config_win_vals_off);
261 break;
262 case South:
263 config_win_vals[1] = 0;
264 for(int j = 0; j < globalconf.embedded.len; j++)
266 em = &globalconf.embedded.tab[j];
267 if(em->phys_screen == phys_screen)
269 /* if(y + width <= wibox.y + systray.right) */
270 if(config_win_vals[1] + config_win_vals[3] <= (uint32_t) wibox->sw.geometry.y + AREA_RIGHT(systray->geometry))
272 xcb_map_window(globalconf.connection, em->win);
273 xcb_configure_window(globalconf.connection, em->win,
274 XCB_CONFIG_WINDOW_X
275 | XCB_CONFIG_WINDOW_Y
276 | XCB_CONFIG_WINDOW_WIDTH
277 | XCB_CONFIG_WINDOW_HEIGHT,
278 config_win_vals);
279 config_win_vals[1] += config_win_vals[3];
281 else
282 xcb_configure_window(globalconf.connection, em->win,
283 XCB_CONFIG_WINDOW_X
284 | XCB_CONFIG_WINDOW_Y,
285 config_win_vals_off);
288 break;
289 case East:
290 config_win_vals[1] = 0;
291 for(int j = 0; j < globalconf.embedded.len; j++)
293 em = &globalconf.embedded.tab[j];
294 if(em->phys_screen == phys_screen)
296 /* if(x + width < systray.x + systray.width) */
297 if(config_win_vals[0] + config_win_vals[2] <= (uint32_t) AREA_RIGHT(systray->geometry) + wibox->sw.geometry.x)
299 xcb_map_window(globalconf.connection, em->win);
300 xcb_configure_window(globalconf.connection, em->win,
301 XCB_CONFIG_WINDOW_X
302 | XCB_CONFIG_WINDOW_Y
303 | XCB_CONFIG_WINDOW_WIDTH
304 | XCB_CONFIG_WINDOW_HEIGHT,
305 config_win_vals);
306 config_win_vals[0] += config_win_vals[2];
308 else
309 xcb_configure_window(globalconf.connection, em->win,
310 XCB_CONFIG_WINDOW_X
311 | XCB_CONFIG_WINDOW_Y,
312 config_win_vals_off);
315 break;
317 break;
322 /* Only called by wibox_position_update() */
323 static void
324 wibox_position_update_floating(wibox_t *wibox)
326 area_t wingeom = wibox->sw.geometry;
328 /* We only make sure the wibox is at least 1x1 pixel big. */
329 wingeom.width = MAX(1, wibox->sw.geometry.width);
330 wingeom.height = MAX(1, wibox->sw.geometry.height);
332 if(wingeom.width != wibox->sw.geometry.width
333 || wingeom.height != wibox->sw.geometry.height)
334 wibox_resize(wibox, wingeom.width, wingeom.height);
337 /* Only called by wibox_position_update() */
338 static void
339 wibox_position_update_non_floating(wibox_t *wibox)
341 area_t area, wingeom = wibox->sw.geometry;
342 bool ignore = false;
344 /* Everything we do below needs the wibox' screen.
345 * No screen, nothing to do.
347 if (!wibox->screen)
348 return;
350 /* This wibox limits the space available to clients and thus clients
351 * need to be repositioned.
353 wibox->screen->need_arrange = true;
355 /* Place wibox'es at the edge of the screen, struts come later. */
356 area = screen_area_get(wibox->screen, NULL,
357 &wibox->screen->padding, false);
359 /* Top and Bottom wibox_t have prio */
360 foreach(_w, wibox->screen->wiboxes)
362 wibox_t *w = *_w;
363 /* Ignore every wibox after me that is in the same position */
364 if(wibox == w)
366 ignore = true;
367 continue;
369 else if((ignore && wibox->position == w->position) || !w->isvisible)
370 continue;
371 switch(w->position)
373 case Floating:
374 break;
375 case Left:
376 if(wibox->position == Left)
377 area.x += wibox->sw.geometry.width;
378 break;
379 case Right:
380 if(wibox->position == Right)
381 area.x -= wibox->sw.geometry.width;
382 break;
383 case Top:
384 switch(wibox->position)
386 case Top:
387 area.y += w->sw.geometry.height;
388 break;
389 case Left:
390 case Right:
391 area.height -= w->sw.geometry.height;
392 area.y += w->sw.geometry.height;
393 break;
394 default:
395 break;
397 break;
398 case Bottom:
399 switch(wibox->position)
401 case Bottom:
402 area.y -= w->sw.geometry.height;
403 break;
404 case Left:
405 case Right:
406 area.height -= w->sw.geometry.height;
407 break;
408 default:
409 break;
411 break;
415 /* The "length" of a wibox is always chosen to be the optimal size (non-floating).
416 * The "width" of a wibox is kept if it exists.
418 switch(wibox->position)
420 case Right:
421 wingeom.height = area.height - 2 * wibox->sw.border.width;
422 wingeom.width = wibox->sw.geometry.width > 0 ? wibox->sw.geometry.width : 1.5 * globalconf.font->height;
423 wingeom.x = area.x + area.width - wingeom.width;
424 switch(wibox->align)
426 default:
427 wingeom.y = area.y;
428 break;
429 case AlignRight:
430 wingeom.y = area.y + area.height - wingeom.height;
431 break;
432 case AlignCenter:
433 wingeom.y = (area.y + area.height - wingeom.height) / 2;
434 break;
436 break;
437 case Left:
438 wingeom.height = area.height - 2 * wibox->sw.border.width;
439 wingeom.width = wibox->sw.geometry.width > 0 ? wibox->sw.geometry.width : 1.5 * globalconf.font->height;
440 wingeom.x = area.x;
441 switch(wibox->align)
443 default:
444 wingeom.y = (area.y + area.height) - wingeom.height;
445 break;
446 case AlignRight:
447 wingeom.y = area.y;
448 break;
449 case AlignCenter:
450 wingeom.y = (area.y + area.height - wingeom.height) / 2;
452 break;
453 case Bottom:
454 wingeom.height = wibox->sw.geometry.height > 0 ? wibox->sw.geometry.height : 1.5 * globalconf.font->height;
455 wingeom.width = area.width - 2 * wibox->sw.border.width;
456 wingeom.y = (area.y + area.height) - wingeom.height;
457 wingeom.x = area.x;
458 switch(wibox->align)
460 default:
461 break;
462 case AlignRight:
463 wingeom.x += area.width - wingeom.width;
464 break;
465 case AlignCenter:
466 wingeom.x += (area.width - wingeom.width) / 2;
467 break;
469 break;
470 case Top:
471 wingeom.height = wibox->sw.geometry.height > 0 ? wibox->sw.geometry.height : 1.5 * globalconf.font->height;
472 wingeom.width = area.width - 2 * wibox->sw.border.width;
473 wingeom.x = area.x;
474 wingeom.y = area.y;
475 switch(wibox->align)
477 default:
478 break;
479 case AlignRight:
480 wingeom.x += area.width - wingeom.width;
481 break;
482 case AlignCenter:
483 wingeom.x += (area.width - wingeom.width) / 2;
484 break;
486 break;
487 case Floating:
488 /* Floating wiboxes are not handled here, but in
489 * wibox_position_update_floating(), but the compiler insists...
491 break;
494 /* same window size and position ? */
495 if(wingeom.width != wibox->sw.geometry.width
496 || wingeom.height != wibox->sw.geometry.height)
497 wibox_resize(wibox, wingeom.width, wingeom.height);
499 if(wingeom.x != wibox->sw.geometry.x
500 || wingeom.y != wibox->sw.geometry.y)
501 wibox_move(wibox, wingeom.x, wingeom.y);
504 /** Update the wibox position. It deletes every wibox resources and
505 * create them back.
506 * \param wibox The wibox.
508 void
509 wibox_position_update(wibox_t *wibox)
511 if(wibox->position == Floating)
512 wibox_position_update_floating(wibox);
513 else
514 wibox_position_update_non_floating(wibox);
517 /** Get a wibox by its window.
518 * \param w The window id.
519 * \return A wibox if found, NULL otherwise.
521 wibox_t *
522 wibox_getbywin(xcb_window_t win)
524 foreach(screen, globalconf.screens)
525 foreach(w, screen->wiboxes)
526 if((*w)->sw.window == win)
527 return *w;
529 foreach(_c, globalconf.clients)
531 client_t *c = *_c;
532 if(c->titlebar && c->titlebar->sw.window == win)
533 return c->titlebar;
536 return NULL;
539 /** Draw a wibox.
540 * \param wibox The wibox to draw.
542 static void
543 wibox_draw(wibox_t *wibox)
545 if(wibox->isvisible)
547 widget_render(wibox);
548 simplewindow_refresh_pixmap(&wibox->sw);
550 wibox->need_update = false;
553 wibox_systray_refresh(wibox);
556 /** Refresh all wiboxes.
558 void
559 wibox_refresh(void)
561 foreach(screen, globalconf.screens)
562 foreach(w, screen->wiboxes)
563 if((*w)->need_update)
564 wibox_draw(*w);
566 foreach(_c, globalconf.clients)
568 client_t *c = *_c;
569 if(c->titlebar && c->titlebar->need_update)
570 wibox_draw(c->titlebar);
574 /** Reposition all wiboxes.
576 void
577 wibox_update_positions(void)
579 foreach(screen, globalconf.screens)
580 foreach(w, screen->wiboxes)
581 wibox_position_update(*w);
584 /** Set a wibox visible or not.
585 * \param wibox The wibox.
586 * \param v The visible value.
588 static void
589 wibox_setvisible(wibox_t *wibox, bool v)
591 if(v != wibox->isvisible)
593 wibox->isvisible = v;
594 wibox->mouse_over = NULL;
596 if(wibox->screen != NULL)
598 if(wibox->isvisible)
599 wibox_map(wibox);
600 else
601 xcb_unmap_window(globalconf.connection, wibox->sw.window);
603 /* kick out systray if needed */
604 wibox_systray_refresh(wibox);
606 /* All the other wibox and ourselves need to be repositioned */
607 foreach(w, wibox->screen->wiboxes)
608 wibox_position_update(*w);
613 /** Remove a wibox from a screen.
614 * \param wibox Wibox to detach from screen.
616 void
617 wibox_detach(wibox_t *wibox)
619 if(wibox->screen != NULL)
621 bool v;
623 /* save visible state */
624 v = wibox->isvisible;
625 wibox->isvisible = false;
626 wibox_systray_refresh(wibox);
627 wibox_position_update(wibox);
628 /* restore position */
629 wibox->isvisible = v;
631 wibox->mouse_over = NULL;
633 simplewindow_wipe(&wibox->sw);
635 wibox->screen->need_arrange = true;
637 foreach(item, wibox->screen->wiboxes)
638 if(*item == wibox)
640 wibox_array_remove(&wibox->screen->wiboxes, item);
641 break;
644 wibox->screen = NULL;
645 wibox_unref(globalconf.L, wibox);
649 /** Attach a wibox that is on top of the stack.
650 * \param s The screen to attach the wibox to.
652 static void
653 wibox_attach(screen_t *s)
655 int phys_screen = screen_virttophys(screen_array_indexof(&globalconf.screens, s));
657 wibox_t *wibox = wibox_ref(globalconf.L);
659 wibox_detach(wibox);
661 /* Set the wibox screen */
662 wibox->screen = s;
664 /* Check that the wibox coordinates matches the screen. */
665 screen_t *cscreen =
666 screen_getbycoord(wibox->screen, wibox->sw.geometry.x, wibox->sw.geometry.y);
668 /* If it does not match, move it to the screen coordinates */
669 if(cscreen != wibox->screen)
670 wibox_move(wibox, s->geometry.x, s->geometry.y);
672 wibox_array_append(&s->wiboxes, wibox);
674 /* compute x/y/width/height if not set */
675 wibox_position_update(wibox);
677 simplewindow_init(&wibox->sw, phys_screen,
678 wibox->sw.geometry,
679 wibox->sw.border.width,
680 wibox->sw.orientation,
681 &wibox->sw.ctx.fg, &wibox->sw.ctx.bg);
683 simplewindow_border_color_set(&wibox->sw, &wibox->sw.border.color);
685 simplewindow_cursor_set(&wibox->sw,
686 xcursor_new(globalconf.connection, xcursor_font_fromstr(wibox->cursor)));
688 /* All the other wibox and ourselves need to be repositioned */
689 foreach(w, s->wiboxes)
690 wibox_position_update(*w);
692 ewmh_update_workarea(phys_screen);
694 if(wibox->isvisible)
695 wibox_map(wibox);
696 else
697 wibox_need_update(wibox);
700 /** Create a new wibox.
701 * \param L The Lua VM state.
703 * \luastack
704 * \lparam A table with optionaly defined values:
705 * position, align, fg, bg, border_width, border_color, ontop, width and height.
706 * \lreturn A brand new wibox.
708 static int
709 luaA_wibox_new(lua_State *L)
711 wibox_t *w;
712 const char *buf;
713 size_t len;
714 xcolor_init_request_t reqs[3];
715 int i, reqs_nbr = -1;
717 luaA_checktable(L, 2);
719 w = wibox_new(L);
720 w->widgets_table = LUA_REFNIL;
722 w->sw.ctx.fg = globalconf.colors.fg;
723 if((buf = luaA_getopt_lstring(L, 2, "fg", NULL, &len)))
724 reqs[++reqs_nbr] = xcolor_init_unchecked(&w->sw.ctx.fg, buf, len);
726 w->sw.ctx.bg = globalconf.colors.bg;
727 if((buf = luaA_getopt_lstring(L, 2, "bg", NULL, &len)))
728 reqs[++reqs_nbr] = xcolor_init_unchecked(&w->sw.ctx.bg, buf, len);
730 w->sw.border.color = globalconf.colors.bg;
731 if((buf = luaA_getopt_lstring(L, 2, "border_color", NULL, &len)))
732 reqs[++reqs_nbr] = xcolor_init_unchecked(&w->sw.border.color, buf, len);
734 w->ontop = luaA_getopt_boolean(L, 2, "ontop", false);
736 buf = luaA_getopt_lstring(L, 2, "align", "left", &len);
737 w->align = draw_align_fromstr(buf, len);
739 w->sw.border.width = luaA_getopt_number(L, 2, "border_width", 0);
741 buf = luaA_getopt_lstring(L, 2, "position", "top", &len);
743 switch((w->position = position_fromstr(buf, len)))
745 case Bottom:
746 case Top:
747 case Floating:
748 w->sw.orientation = East;
749 break;
750 case Left:
751 w->sw.orientation = North;
752 break;
753 case Right:
754 w->sw.orientation = South;
755 break;
758 w->sw.geometry.x = luaA_getopt_number(L, 2, "x", 0);
759 w->sw.geometry.y = luaA_getopt_number(L, 2, "y", 0);
760 w->sw.geometry.width = luaA_getopt_number(L, 2, "width", 0);
761 w->sw.geometry.height = luaA_getopt_number(L, 2, "height", 0);
763 w->isvisible = true;
764 w->cursor = a_strdup("left_ptr");
766 w->mouse_enter = w->mouse_leave = LUA_REFNIL;
768 for(i = 0; i <= reqs_nbr; i++)
769 xcolor_init_reply(reqs[i]);
771 return 1;
774 /** Rebuild wibox widgets list.
775 * \param L The Lua VM state.
776 * \param wibox The wibox.
778 static void
779 wibox_widgets_table_build(lua_State *L, wibox_t *wibox)
781 widget_node_array_wipe(&wibox->widgets);
782 widget_node_array_init(&wibox->widgets);
783 luaA_table2widgets(L, &wibox->widgets);
784 wibox_need_update(wibox);
787 /** Check if a wibox widget table has an item.
788 * \param L The Lua VM state.
789 * \param wibox The wibox.
790 * \param item The item to look for.
792 static bool
793 luaA_wibox_hasitem(lua_State *L, wibox_t *wibox, const void *item)
795 if(wibox->widgets_table != LUA_REFNIL)
797 lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, wibox->widgets_table);
798 if(lua_topointer(L, -1) == item || luaA_hasitem(L, item))
799 return true;
801 return false;
804 /** Invalidate a wibox by a Lua object (table, etc).
805 * \param L The Lua VM state.
806 * \param item The object identifier.
808 void
809 luaA_wibox_invalidate_byitem(lua_State *L, const void *item)
811 foreach(screen, globalconf.screens)
812 foreach(w, screen->wiboxes)
814 wibox_t *wibox = *w;
815 if(luaA_wibox_hasitem(L, wibox, item))
817 /* recompute widget node list */
818 wibox_widgets_table_build(L, wibox);
819 lua_pop(L, 1); /* remove widgets table */
824 foreach(_c, globalconf.clients)
826 client_t *c = *_c;
827 if(c->titlebar && luaA_wibox_hasitem(L, c->titlebar, item))
829 /* recompute widget node list */
830 wibox_widgets_table_build(L, c->titlebar);
831 lua_pop(L, 1); /* remove widgets table */
836 /** Wibox object.
837 * \param L The Lua VM state.
838 * \return The number of elements pushed on stack.
839 * \luastack
840 * \lfield screen Screen number.
841 * \lfield client The client attached to (titlebar).
842 * \lfield border_width Border width.
843 * \lfield border_color Border color.
844 * \lfield align The alignment.
845 * \lfield fg Foreground color.
846 * \lfield bg Background color.
847 * \lfield bg_image Background image.
848 * \lfield position The position.
849 * \lfield ontop On top of other windows.
850 * \lfield cursor The mouse cursor.
851 * \lfield visible Visibility.
852 * \lfield orientation The drawing orientation: east, north or south.
853 * \lfield widgets An array with all widgets drawn on this wibox.
854 * \lfield opacity The opacity of the wibox, between 0 and 1.
855 * \lfield mouse_enter A function to execute when the mouse enter the widget.
856 * \lfield mouse_leave A function to execute when the mouse leave the widget.
858 static int
859 luaA_wibox_index(lua_State *L)
861 size_t len;
862 wibox_t *wibox = luaL_checkudata(L, 1, "wibox");
863 const char *attr = luaL_checklstring(L, 2, &len);
865 if(luaA_usemetatable(L, 1, 2))
866 return 1;
868 switch(a_tokenize(attr, len))
870 case A_TK_VISIBLE:
871 lua_pushboolean(L, wibox->isvisible);
872 break;
873 case A_TK_CLIENT:
874 return client_push(L, client_getbytitlebar(wibox));
875 case A_TK_SCREEN:
876 if(!wibox->screen)
877 return 0;
878 lua_pushnumber(L, screen_array_indexof(&globalconf.screens, wibox->screen) + 1);
879 break;
880 case A_TK_BORDER_WIDTH:
881 lua_pushnumber(L, wibox->sw.border.width);
882 break;
883 case A_TK_BORDER_COLOR:
884 luaA_pushxcolor(L, &wibox->sw.border.color);
885 break;
886 case A_TK_ALIGN:
887 lua_pushstring(L, draw_align_tostr(wibox->align));
888 break;
889 case A_TK_FG:
890 luaA_pushxcolor(L, &wibox->sw.ctx.fg);
891 break;
892 case A_TK_BG:
893 luaA_pushxcolor(L, &wibox->sw.ctx.bg);
894 break;
895 case A_TK_BG_IMAGE:
896 image_push(L, wibox->bg_image);
897 break;
898 case A_TK_POSITION:
899 lua_pushstring(L, position_tostr(wibox->position));
900 break;
901 case A_TK_ONTOP:
902 lua_pushboolean(L, wibox->ontop);
903 break;
904 case A_TK_ORIENTATION:
905 lua_pushstring(L, orientation_tostr(wibox->sw.orientation));
906 break;
907 case A_TK_WIDGETS:
908 if(wibox->widgets_table != LUA_REFNIL)
909 lua_rawgeti(L, LUA_REGISTRYINDEX, wibox->widgets_table);
910 else
911 lua_pushnil(L);
912 break;
913 case A_TK_CURSOR:
914 lua_pushstring(L, wibox->cursor);
915 break;
916 case A_TK_OPACITY:
918 double d;
919 if ((d = window_opacity_get(wibox->sw.window)) >= 0)
920 lua_pushnumber(L, d);
921 else
922 return 0;
924 break;
925 case A_TK_MOUSE_ENTER:
926 if(wibox->mouse_enter != LUA_REFNIL)
927 lua_rawgeti(L, LUA_REGISTRYINDEX, wibox->mouse_enter);
928 else
929 return 0;
930 return 1;
931 case A_TK_MOUSE_LEAVE:
932 if(wibox->mouse_leave != LUA_REFNIL)
933 lua_rawgeti(L, LUA_REGISTRYINDEX, wibox->mouse_leave);
934 else
935 return 0;
936 return 1;
937 default:
938 return 0;
941 return 1;
944 /* Set or get the wibox geometry.
945 * \param L The Lua VM state.
946 * \return The number of elements pushed on stack.
947 * \luastack
948 * \lparam An optional table with wibox geometry.
949 * \lreturn The wibox geometry.
951 static int
952 luaA_wibox_geometry(lua_State *L)
954 wibox_t *wibox = luaL_checkudata(L, 1, "wibox");
956 if(lua_gettop(L) == 2)
958 area_t wingeom;
960 luaA_checktable(L, 2);
961 wingeom.x = luaA_getopt_number(L, 2, "x", wibox->sw.geometry.x);
962 wingeom.y = luaA_getopt_number(L, 2, "y", wibox->sw.geometry.y);
963 wingeom.width = luaA_getopt_number(L, 2, "width", wibox->sw.geometry.width);
964 wingeom.height = luaA_getopt_number(L, 2, "height", wibox->sw.geometry.height);
966 switch(wibox->type)
968 case WIBOX_TYPE_TITLEBAR:
969 wibox_resize(wibox, wingeom.width, wingeom.height);
970 break;
971 case WIBOX_TYPE_NORMAL:
972 if(wibox->position == Floating)
973 wibox_moveresize(wibox, wingeom);
974 else if(wingeom.width != wibox->sw.geometry.width
975 || wingeom.height != wibox->sw.geometry.height)
977 wibox_resize(wibox, wingeom.width, wingeom.height);
978 wibox->screen->need_arrange = true;
980 break;
984 return luaA_pusharea(L, wibox->sw.geometry);
987 /** Wibox newindex.
988 * \param L The Lua VM state.
989 * \return The number of elements pushed on stack.
991 static int
992 luaA_wibox_newindex(lua_State *L)
994 size_t len;
995 wibox_t *wibox = luaL_checkudata(L, 1, "wibox");
996 const char *buf, *attr = luaL_checklstring(L, 2, &len);
997 awesome_token_t tok;
999 switch((tok = a_tokenize(attr, len)))
1001 bool b;
1003 case A_TK_FG:
1004 if((buf = luaL_checklstring(L, 3, &len)))
1005 if(xcolor_init_reply(xcolor_init_unchecked(&wibox->sw.ctx.fg, buf, len)))
1006 wibox->need_update = true;
1007 break;
1008 case A_TK_BG:
1009 if((buf = luaL_checklstring(L, 3, &len)))
1010 if(xcolor_init_reply(xcolor_init_unchecked(&wibox->sw.ctx.bg, buf, len)))
1011 wibox->need_update = true;
1012 break;
1013 case A_TK_BG_IMAGE:
1014 image_unref(L, wibox->bg_image);
1015 wibox->bg_image = image_ref(L);
1016 wibox->need_update = true;
1017 break;
1018 case A_TK_ALIGN:
1019 buf = luaL_checklstring(L, 3, &len);
1020 wibox->align = draw_align_fromstr(buf, len);
1021 switch(wibox->type)
1023 case WIBOX_TYPE_NORMAL:
1024 wibox_position_update(wibox);
1025 break;
1026 case WIBOX_TYPE_TITLEBAR:
1027 titlebar_update_geometry(client_getbytitlebar(wibox));
1028 break;
1030 break;
1031 case A_TK_POSITION:
1032 switch(wibox->type)
1034 case WIBOX_TYPE_TITLEBAR:
1035 return luaA_titlebar_newindex(L, wibox, tok);
1036 case WIBOX_TYPE_NORMAL:
1037 if((buf = luaL_checklstring(L, 3, &len)))
1038 wibox_setposition(wibox, position_fromstr(buf, len));
1039 break;
1041 break;
1042 case A_TK_CLIENT:
1043 /* first detach */
1044 if(lua_isnil(L, 3))
1045 titlebar_client_detach(client_getbytitlebar(wibox));
1046 else
1048 client_t *c = luaA_client_checkudata(L, -1);
1049 lua_pushvalue(L, 1);
1050 titlebar_client_attach(c);
1052 break;
1053 case A_TK_CURSOR:
1054 if((buf = luaL_checkstring(L, 3)))
1056 uint16_t cursor_font = xcursor_font_fromstr(buf);
1057 if(cursor_font)
1059 xcb_cursor_t cursor = xcursor_new(globalconf.connection, cursor_font);
1060 p_delete(&wibox->cursor);
1061 wibox->cursor = a_strdup(buf);
1062 simplewindow_cursor_set(&wibox->sw, cursor);
1065 break;
1066 case A_TK_SCREEN:
1067 if(lua_isnil(L, 3))
1069 wibox_detach(wibox);
1070 titlebar_client_detach(client_getbytitlebar(wibox));
1072 else
1074 int screen = luaL_checknumber(L, 3) - 1;
1075 luaA_checkscreen(screen);
1076 if(!wibox->screen || screen != screen_array_indexof(&globalconf.screens, wibox->screen))
1078 titlebar_client_detach(client_getbytitlebar(wibox));
1079 lua_pushvalue(L, 1);
1080 wibox_attach(&globalconf.screens.tab[screen]);
1083 break;
1084 case A_TK_ONTOP:
1085 b = luaA_checkboolean(L, 3);
1086 if(b != wibox->ontop)
1088 wibox->ontop = b;
1089 client_stack();
1091 break;
1092 case A_TK_ORIENTATION:
1093 if((buf = luaL_checklstring(L, 3, &len)))
1095 simplewindow_orientation_set(&wibox->sw, orientation_fromstr(buf, len));
1096 wibox_need_update(wibox);
1098 break;
1099 case A_TK_BORDER_COLOR:
1100 if((buf = luaL_checklstring(L, 3, &len)))
1101 if(xcolor_init_reply(xcolor_init_unchecked(&wibox->sw.border.color, buf, len)))
1102 if(wibox->sw.window)
1103 simplewindow_border_color_set(&wibox->sw, &wibox->sw.border.color);
1104 break;
1105 case A_TK_VISIBLE:
1106 b = luaA_checkboolean(L, 3);
1107 if(b != wibox->isvisible)
1108 switch(wibox->type)
1110 case WIBOX_TYPE_NORMAL:
1111 wibox_setvisible(wibox, b);
1112 break;
1113 case WIBOX_TYPE_TITLEBAR:
1114 titlebar_set_visible(wibox, b);
1115 break;
1117 break;
1118 case A_TK_WIDGETS:
1119 if(luaA_isloop(L, 3))
1121 luaA_warn(L, "table is looping, cannot use this as widget table");
1122 return 0;
1124 /* register object */
1125 luaA_register(L, 3, &wibox->widgets_table);
1126 /* duplicate table because next function will eat it */
1127 lua_pushvalue(L, -1);
1128 /* recompute widget node list */
1129 wibox_widgets_table_build(L, wibox);
1130 luaA_table2wtable(L);
1131 break;
1132 case A_TK_OPACITY:
1133 if(lua_isnil(L, 3))
1134 window_opacity_set(wibox->sw.window, -1);
1135 else
1137 double d = luaL_checknumber(L, 3);
1138 if(d >= 0 && d <= 1)
1139 window_opacity_set(wibox->sw.window, d);
1141 break;
1142 case A_TK_MOUSE_ENTER:
1143 luaA_registerfct(L, 3, &wibox->mouse_enter);
1144 return 0;
1145 case A_TK_MOUSE_LEAVE:
1146 luaA_registerfct(L, 3, &wibox->mouse_leave);
1147 return 0;
1148 default:
1149 switch(wibox->type)
1151 case WIBOX_TYPE_TITLEBAR:
1152 return luaA_titlebar_newindex(L, wibox, tok);
1153 case WIBOX_TYPE_NORMAL:
1154 break;
1158 return 0;
1161 /** Get or set mouse buttons bindings to a wibox.
1162 * \param L The Lua VM state.
1163 * \luastack
1164 * \lvalue A wibox.
1165 * \lparam An array of mouse button bindings objects, or nothing.
1166 * \return The array of mouse button bindings objects of this wibox.
1168 static int
1169 luaA_wibox_buttons(lua_State *L)
1171 wibox_t *wibox = luaL_checkudata(L, 1, "wibox");
1172 button_array_t *buttons = &wibox->buttons;
1174 if(lua_gettop(L) == 2)
1176 luaA_button_array_set(L, 2, buttons);
1177 return 1;
1180 return luaA_button_array_get(L, buttons);
1183 const struct luaL_reg awesome_wibox_methods[] =
1185 { "__call", luaA_wibox_new },
1186 { NULL, NULL }
1188 const struct luaL_reg awesome_wibox_meta[] =
1190 { "buttons", luaA_wibox_buttons },
1191 { "geometry", luaA_wibox_geometry },
1192 { "__index", luaA_wibox_index },
1193 { "__newindex", luaA_wibox_newindex },
1194 { "__gc", luaA_wibox_gc },
1195 { "__tostring", luaA_wibox_tostring },
1196 { NULL, NULL },
1199 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80