luaa: refresh all wiboxes on font change
[awesome.git] / wibox.c
blobf787f2c2311a93c01e09e4c7c8c0e5c68cf5557a
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 p_delete(&wibox->cursor);
43 simplewindow_wipe(&wibox->sw);
44 button_array_wipe(&wibox->buttons);
45 image_unref(L, wibox->bg_image);
46 luaL_unref(L, LUA_REGISTRYINDEX, wibox->widgets_table);
47 luaL_unref(L, LUA_REGISTRYINDEX, wibox->mouse_enter);
48 luaL_unref(L, LUA_REGISTRYINDEX, wibox->mouse_leave);
49 widget_node_array_wipe(&wibox->widgets);
50 return 0;
53 void
54 wibox_unref_simplified(wibox_t **item)
56 wibox_unref(globalconf.L, *item);
59 static void
60 wibox_need_update(wibox_t *wibox)
62 wibox->need_update = true;
63 wibox->mouse_over = NULL;
66 static void
67 wibox_map(wibox_t *wibox)
69 xcb_map_window(globalconf.connection, wibox->sw.window);
70 /* We must make sure the wibox does not display garbage */
71 wibox_need_update(wibox);
72 /* Stack this wibox correctly */
73 client_stack();
76 static void
77 wibox_move(wibox_t *wibox, int16_t x, int16_t y)
79 if(wibox->sw.window)
81 simplewindow_move(&wibox->sw, x, y);
82 wibox->screen = screen_getbycoord(wibox->screen, x, y);
84 else
86 wibox->sw.geometry.x = x;
87 wibox->sw.geometry.y = y;
91 static void
92 wibox_resize(wibox_t *wibox, uint16_t width, uint16_t height)
94 if(wibox->sw.window)
95 simplewindow_resize(&wibox->sw, width, height);
96 else
98 wibox->sw.geometry.width = width;
99 wibox->sw.geometry.height = height;
101 wibox_need_update(wibox);
104 static void
105 wibox_setposition(wibox_t *wibox, position_t p)
107 if(p != wibox->position)
109 switch((wibox->position = p))
111 case Bottom:
112 case Top:
113 case Floating:
114 simplewindow_orientation_set(&wibox->sw, East);
115 break;
116 case Left:
117 simplewindow_orientation_set(&wibox->sw, North);
118 break;
119 case Right:
120 simplewindow_orientation_set(&wibox->sw, South);
121 break;
123 /* reset width/height to 0 */
124 if(wibox->position != Floating)
125 wibox->sw.geometry.width = wibox->sw.geometry.height = 0;
127 /* recompute position */
128 wibox_position_update(wibox);
130 /* reset all wibox position */
131 foreach(w, wibox->screen->wiboxes)
132 wibox_position_update(*w);
134 ewmh_update_workarea(screen_virttophys(screen_array_indexof(&globalconf.screens, wibox->screen)));
136 wibox_need_update(wibox);
140 /** Kick out systray windows.
141 * \param phys_screen Physical screen number.
143 static void
144 wibox_systray_kickout(int phys_screen)
146 xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
148 if(globalconf.screens.tab[phys_screen].systray.parent != s->root)
150 /* Who! Check that we're not deleting a wibox with a systray, because it
151 * may be its parent. If so, we reparent to root before, otherwise it will
152 * hurt very much. */
153 xcb_reparent_window(globalconf.connection,
154 globalconf.screens.tab[phys_screen].systray.window,
155 s->root, -512, -512);
157 globalconf.screens.tab[phys_screen].systray.parent = s->root;
161 static void
162 wibox_systray_refresh(wibox_t *wibox)
164 if(!wibox->screen)
165 return;
167 for(int i = 0; i < wibox->widgets.len; i++)
169 widget_node_t *systray = &wibox->widgets.tab[i];
170 if(systray->widget->type == widget_systray)
172 uint32_t config_back[] = { wibox->sw.ctx.bg.pixel };
173 uint32_t config_win_vals[4];
174 uint32_t config_win_vals_off[2] = { -512, -512 };
175 xembed_window_t *em;
176 int phys_screen = wibox->sw.ctx.phys_screen;
178 if(wibox->isvisible
179 && systray->widget->isvisible
180 && systray->geometry.width)
182 /* Set background of the systray window. */
183 xcb_change_window_attributes(globalconf.connection,
184 globalconf.screens.tab[phys_screen].systray.window,
185 XCB_CW_BACK_PIXEL, config_back);
186 /* Map it. */
187 xcb_map_window(globalconf.connection, globalconf.screens.tab[phys_screen].systray.window);
188 /* Move it. */
189 switch(wibox->sw.orientation)
191 case North:
192 config_win_vals[0] = systray->geometry.y;
193 config_win_vals[1] = wibox->sw.geometry.height - systray->geometry.x - systray->geometry.width;
194 config_win_vals[2] = systray->geometry.height;
195 config_win_vals[3] = systray->geometry.width;
196 break;
197 case South:
198 config_win_vals[0] = systray->geometry.y;
199 config_win_vals[1] = systray->geometry.x;
200 config_win_vals[2] = systray->geometry.height;
201 config_win_vals[3] = systray->geometry.width;
202 break;
203 case East:
204 config_win_vals[0] = systray->geometry.x;
205 config_win_vals[1] = systray->geometry.y;
206 config_win_vals[2] = systray->geometry.width;
207 config_win_vals[3] = systray->geometry.height;
208 break;
210 /* reparent */
211 if(globalconf.screens.tab[phys_screen].systray.parent != wibox->sw.window)
213 xcb_reparent_window(globalconf.connection,
214 globalconf.screens.tab[phys_screen].systray.window,
215 wibox->sw.window,
216 config_win_vals[0], config_win_vals[1]);
217 globalconf.screens.tab[phys_screen].systray.parent = wibox->sw.window;
219 xcb_configure_window(globalconf.connection,
220 globalconf.screens.tab[phys_screen].systray.window,
221 XCB_CONFIG_WINDOW_X
222 | XCB_CONFIG_WINDOW_Y
223 | XCB_CONFIG_WINDOW_WIDTH
224 | XCB_CONFIG_WINDOW_HEIGHT,
225 config_win_vals);
226 /* width = height = systray height */
227 config_win_vals[2] = config_win_vals[3] = systray->geometry.height;
228 config_win_vals[0] = 0;
230 else
231 return wibox_systray_kickout(phys_screen);
233 switch(wibox->sw.orientation)
235 case North:
236 config_win_vals[1] = systray->geometry.width - config_win_vals[3];
237 for(int j = 0; j < globalconf.embedded.len; j++)
239 em = &globalconf.embedded.tab[j];
240 if(em->phys_screen == phys_screen)
242 if(config_win_vals[1] - config_win_vals[2] >= (uint32_t) wibox->sw.geometry.y)
244 xcb_map_window(globalconf.connection, em->win);
245 xcb_configure_window(globalconf.connection, em->win,
246 XCB_CONFIG_WINDOW_X
247 | XCB_CONFIG_WINDOW_Y
248 | XCB_CONFIG_WINDOW_WIDTH
249 | XCB_CONFIG_WINDOW_HEIGHT,
250 config_win_vals);
251 config_win_vals[1] -= config_win_vals[3];
253 else
254 xcb_configure_window(globalconf.connection, em->win,
255 XCB_CONFIG_WINDOW_X
256 | XCB_CONFIG_WINDOW_Y,
257 config_win_vals_off);
260 break;
261 case South:
262 config_win_vals[1] = 0;
263 for(int j = 0; j < globalconf.embedded.len; j++)
265 em = &globalconf.embedded.tab[j];
266 if(em->phys_screen == phys_screen)
268 /* if(y + width <= wibox.y + systray.right) */
269 if(config_win_vals[1] + config_win_vals[3] <= (uint32_t) wibox->sw.geometry.y + AREA_RIGHT(systray->geometry))
271 xcb_map_window(globalconf.connection, em->win);
272 xcb_configure_window(globalconf.connection, em->win,
273 XCB_CONFIG_WINDOW_X
274 | XCB_CONFIG_WINDOW_Y
275 | XCB_CONFIG_WINDOW_WIDTH
276 | XCB_CONFIG_WINDOW_HEIGHT,
277 config_win_vals);
278 config_win_vals[1] += config_win_vals[3];
280 else
281 xcb_configure_window(globalconf.connection, em->win,
282 XCB_CONFIG_WINDOW_X
283 | XCB_CONFIG_WINDOW_Y,
284 config_win_vals_off);
287 break;
288 case East:
289 config_win_vals[1] = 0;
290 for(int j = 0; j < globalconf.embedded.len; j++)
292 em = &globalconf.embedded.tab[j];
293 if(em->phys_screen == phys_screen)
295 /* if(x + width < systray.x + systray.width) */
296 if(config_win_vals[0] + config_win_vals[2] <= (uint32_t) AREA_RIGHT(systray->geometry) + wibox->sw.geometry.x)
298 xcb_map_window(globalconf.connection, em->win);
299 xcb_configure_window(globalconf.connection, em->win,
300 XCB_CONFIG_WINDOW_X
301 | XCB_CONFIG_WINDOW_Y
302 | XCB_CONFIG_WINDOW_WIDTH
303 | XCB_CONFIG_WINDOW_HEIGHT,
304 config_win_vals);
305 config_win_vals[0] += config_win_vals[2];
307 else
308 xcb_configure_window(globalconf.connection, em->win,
309 XCB_CONFIG_WINDOW_X
310 | XCB_CONFIG_WINDOW_Y,
311 config_win_vals_off);
314 break;
316 break;
321 /* Only called by wibox_position_update() */
322 static void
323 wibox_position_update_floating(wibox_t *wibox)
325 area_t wingeom = wibox->sw.geometry;
327 /* We only make sure the wibox is at least 1x1 pixel big. */
328 wingeom.width = MAX(1, wibox->sw.geometry.width);
329 wingeom.height = MAX(1, wibox->sw.geometry.height);
331 if(wingeom.width != wibox->sw.geometry.width
332 || wingeom.height != wibox->sw.geometry.height)
333 wibox_resize(wibox, wingeom.width, wingeom.height);
336 /* Only called by wibox_position_update() */
337 static void
338 wibox_position_update_non_floating(wibox_t *wibox)
340 area_t area, wingeom = wibox->sw.geometry;
341 bool ignore = false;
343 /* Everything we do below needs the wibox' screen.
344 * No screen, nothing to do.
346 if (!wibox->screen)
347 return;
349 /* This wibox limits the space available to clients and thus clients
350 * need to be repositioned.
352 wibox->screen->need_arrange = true;
354 /* Place wibox'es at the edge of the screen, struts come later. */
355 area = screen_area_get(wibox->screen, NULL,
356 &wibox->screen->padding, false);
358 /* Top and Bottom wibox_t have prio */
359 foreach(_w, wibox->screen->wiboxes)
361 wibox_t *w = *_w;
362 /* Ignore every wibox after me that is in the same position */
363 if(wibox == w)
365 ignore = true;
366 continue;
368 else if((ignore && wibox->position == w->position) || !w->isvisible)
369 continue;
370 switch(w->position)
372 case Floating:
373 break;
374 case Left:
375 if(wibox->position == Left)
376 area.x += wibox->sw.geometry.height;
377 break;
378 case Right:
379 if(wibox->position == Right)
380 area.x -= wibox->sw.geometry.height;
381 break;
382 case Top:
383 switch(wibox->position)
385 case Top:
386 area.y += w->sw.geometry.height;
387 break;
388 case Left:
389 case Right:
390 area.height -= w->sw.geometry.height;
391 area.y += w->sw.geometry.height;
392 break;
393 default:
394 break;
396 break;
397 case Bottom:
398 switch(wibox->position)
400 case Bottom:
401 area.y -= w->sw.geometry.height;
402 break;
403 case Left:
404 case Right:
405 area.height -= w->sw.geometry.height;
406 break;
407 default:
408 break;
410 break;
414 /* The "length" of a wibox is always chosen to be the optimal size (non-floating).
415 * The "width" of a wibox is kept if it exists.
417 switch(wibox->position)
419 case Right:
420 wingeom.height = area.height - 2 * wibox->sw.border.width;
421 wingeom.width = wibox->sw.geometry.width > 0 ? wibox->sw.geometry.width : 1.5 * globalconf.font->height;
422 wingeom.x = area.x + area.width - wingeom.width;
423 switch(wibox->align)
425 default:
426 wingeom.y = area.y;
427 break;
428 case AlignRight:
429 wingeom.y = area.y + area.height - wingeom.height;
430 break;
431 case AlignCenter:
432 wingeom.y = (area.y + area.height - wingeom.height) / 2;
433 break;
435 break;
436 case Left:
437 wingeom.height = area.height - 2 * wibox->sw.border.width;
438 wingeom.width = wibox->sw.geometry.width > 0 ? wibox->sw.geometry.width : 1.5 * globalconf.font->height;
439 wingeom.x = area.x;
440 switch(wibox->align)
442 default:
443 wingeom.y = (area.y + area.height) - wingeom.height;
444 break;
445 case AlignRight:
446 wingeom.y = area.y;
447 break;
448 case AlignCenter:
449 wingeom.y = (area.y + area.height - wingeom.height) / 2;
451 break;
452 case Bottom:
453 wingeom.height = wibox->sw.geometry.height > 0 ? wibox->sw.geometry.height : 1.5 * globalconf.font->height;
454 wingeom.width = area.width - 2 * wibox->sw.border.width;
455 wingeom.y = (area.y + area.height) - wingeom.height;
456 wingeom.x = area.x;
457 switch(wibox->align)
459 default:
460 break;
461 case AlignRight:
462 wingeom.x += area.width - wingeom.width;
463 break;
464 case AlignCenter:
465 wingeom.x += (area.width - wingeom.width) / 2;
466 break;
468 break;
469 case Top:
470 wingeom.height = wibox->sw.geometry.height > 0 ? wibox->sw.geometry.height : 1.5 * globalconf.font->height;
471 wingeom.width = area.width - 2 * wibox->sw.border.width;
472 wingeom.x = area.x;
473 wingeom.y = area.y;
474 switch(wibox->align)
476 default:
477 break;
478 case AlignRight:
479 wingeom.x += area.width - wingeom.width;
480 break;
481 case AlignCenter:
482 wingeom.x += (area.width - wingeom.width) / 2;
483 break;
485 break;
486 case Floating:
487 /* Floating wiboxes are not handled here, but in
488 * wibox_position_update_floating(), but the compiler insists...
490 break;
493 /* same window size and position ? */
494 if(wingeom.width != wibox->sw.geometry.width
495 || wingeom.height != wibox->sw.geometry.height)
496 wibox_resize(wibox, wingeom.width, wingeom.height);
498 if(wingeom.x != wibox->sw.geometry.x
499 || wingeom.y != wibox->sw.geometry.y)
500 wibox_move(wibox, wingeom.x, wingeom.y);
503 /** Update the wibox position. It deletes every wibox resources and
504 * create them back.
505 * \param wibox The wibox.
507 void
508 wibox_position_update(wibox_t *wibox)
510 if(wibox->position == Floating)
511 wibox_position_update_floating(wibox);
512 else
513 wibox_position_update_non_floating(wibox);
516 /** Get a wibox by its window.
517 * \param w The window id.
518 * \return A wibox if found, NULL otherwise.
520 wibox_t *
521 wibox_getbywin(xcb_window_t win)
523 foreach(screen, globalconf.screens)
524 foreach(w, screen->wiboxes)
525 if((*w)->sw.window == win)
526 return *w;
528 foreach(_c, globalconf.clients)
530 client_t *c = *_c;
531 if(c->titlebar && c->titlebar->sw.window == win)
532 return c->titlebar;
535 return NULL;
538 /** Draw a wibox.
539 * \param wibox The wibox to draw.
541 static void
542 wibox_draw(wibox_t *wibox)
544 if(wibox->isvisible)
546 widget_render(wibox);
547 simplewindow_refresh_pixmap(&wibox->sw);
549 wibox->need_update = false;
552 wibox_systray_refresh(wibox);
555 /** Refresh all wiboxes.
557 void
558 wibox_refresh(void)
560 foreach(screen, globalconf.screens)
561 foreach(w, screen->wiboxes)
562 if((*w)->need_update)
563 wibox_draw(*w);
565 foreach(_c, globalconf.clients)
567 client_t *c = *_c;
568 if(c->titlebar && c->titlebar->need_update)
569 wibox_draw(c->titlebar);
573 /** Reposition all wiboxes.
575 void
576 wibox_update_positions(void)
578 foreach(screen, globalconf.screens)
579 foreach(w, screen->wiboxes)
580 wibox_position_update(*w);
583 /** Set a wibox visible or not.
584 * \param wibox The wibox.
585 * \param v The visible value.
587 static void
588 wibox_setvisible(wibox_t *wibox, bool v)
590 if(v != wibox->isvisible)
592 wibox->isvisible = v;
593 wibox->mouse_over = NULL;
595 if(wibox->screen != NULL)
597 if(wibox->isvisible)
598 wibox_map(wibox);
599 else
600 xcb_unmap_window(globalconf.connection, wibox->sw.window);
602 /* kick out systray if needed */
603 wibox_systray_refresh(wibox);
605 /* All the other wibox and ourselves need to be repositioned */
606 foreach(w, wibox->screen->wiboxes)
607 wibox_position_update(*w);
612 /** Remove a wibox from a screen.
613 * \param wibox Wibox to detach from screen.
615 void
616 wibox_detach(wibox_t *wibox)
618 if(wibox->screen != NULL)
620 bool v;
622 /* save visible state */
623 v = wibox->isvisible;
624 wibox->isvisible = false;
625 wibox_systray_refresh(wibox);
626 wibox_position_update(wibox);
627 /* restore position */
628 wibox->isvisible = v;
630 wibox->mouse_over = NULL;
632 simplewindow_wipe(&wibox->sw);
634 wibox->screen->need_arrange = true;
636 foreach(item, wibox->screen->wiboxes)
637 if(*item == wibox)
639 wibox_array_remove(&wibox->screen->wiboxes, item);
640 break;
643 wibox->screen = NULL;
644 wibox_unref(globalconf.L, wibox);
648 /** Attach a wibox that is on top of the stack.
649 * \param s The screen to attach the wibox to.
651 static void
652 wibox_attach(screen_t *s)
654 int phys_screen = screen_virttophys(screen_array_indexof(&globalconf.screens, s));
656 wibox_t *wibox = wibox_ref(globalconf.L);
658 wibox_detach(wibox);
660 /* Set the wibox screen */
661 wibox->screen = s;
663 /* Check that the wibox coordinates matches the screen. */
664 screen_t *cscreen =
665 screen_getbycoord(wibox->screen, wibox->sw.geometry.x, wibox->sw.geometry.y);
667 /* If it does not match, move it to the screen coordinates */
668 if(cscreen != wibox->screen)
669 wibox_move(wibox, s->geometry.x, s->geometry.y);
671 wibox_array_append(&s->wiboxes, wibox);
673 /* compute x/y/width/height if not set */
674 wibox_position_update(wibox);
676 simplewindow_init(&wibox->sw, phys_screen,
677 wibox->sw.geometry,
678 wibox->sw.border.width,
679 wibox->sw.orientation,
680 &wibox->sw.ctx.fg, &wibox->sw.ctx.bg);
682 simplewindow_border_color_set(&wibox->sw, &wibox->sw.border.color);
684 simplewindow_cursor_set(&wibox->sw,
685 xcursor_new(globalconf.connection, xcursor_font_fromstr(wibox->cursor)));
687 /* All the other wibox and ourselves need to be repositioned */
688 foreach(w, s->wiboxes)
689 wibox_position_update(*w);
691 ewmh_update_workarea(phys_screen);
693 if(wibox->isvisible)
694 wibox_map(wibox);
695 else
696 wibox_need_update(wibox);
699 /** Create a new wibox.
700 * \param L The Lua VM state.
702 * \luastack
703 * \lparam A table with optionaly defined values:
704 * position, align, fg, bg, border_width, border_color, ontop, width and height.
705 * \lreturn A brand new wibox.
707 static int
708 luaA_wibox_new(lua_State *L)
710 wibox_t *w;
711 const char *buf;
712 size_t len;
713 xcolor_init_request_t reqs[3];
714 int i, reqs_nbr = -1;
716 luaA_checktable(L, 2);
718 w = wibox_new(L);
719 w->widgets_table = LUA_REFNIL;
721 w->sw.ctx.fg = globalconf.colors.fg;
722 if((buf = luaA_getopt_lstring(L, 2, "fg", NULL, &len)))
723 reqs[++reqs_nbr] = xcolor_init_unchecked(&w->sw.ctx.fg, buf, len);
725 w->sw.ctx.bg = globalconf.colors.bg;
726 if((buf = luaA_getopt_lstring(L, 2, "bg", NULL, &len)))
727 reqs[++reqs_nbr] = xcolor_init_unchecked(&w->sw.ctx.bg, buf, len);
729 w->sw.border.color = globalconf.colors.bg;
730 if((buf = luaA_getopt_lstring(L, 2, "border_color", NULL, &len)))
731 reqs[++reqs_nbr] = xcolor_init_unchecked(&w->sw.border.color, buf, len);
733 w->ontop = luaA_getopt_boolean(L, 2, "ontop", false);
735 buf = luaA_getopt_lstring(L, 2, "align", "left", &len);
736 w->align = draw_align_fromstr(buf, len);
738 w->sw.border.width = luaA_getopt_number(L, 2, "border_width", 0);
740 buf = luaA_getopt_lstring(L, 2, "position", "top", &len);
742 switch((w->position = position_fromstr(buf, len)))
744 case Bottom:
745 case Top:
746 case Floating:
747 w->sw.orientation = East;
748 break;
749 case Left:
750 w->sw.orientation = North;
751 break;
752 case Right:
753 w->sw.orientation = South;
754 break;
757 w->sw.geometry.x = luaA_getopt_number(L, 2, "x", 0);
758 w->sw.geometry.y = luaA_getopt_number(L, 2, "y", 0);
759 w->sw.geometry.width = luaA_getopt_number(L, 2, "width", 0);
760 w->sw.geometry.height = luaA_getopt_number(L, 2, "height", 0);
762 w->isvisible = true;
763 w->cursor = a_strdup("left_ptr");
765 w->mouse_enter = w->mouse_leave = LUA_REFNIL;
767 for(i = 0; i <= reqs_nbr; i++)
768 xcolor_init_reply(reqs[i]);
770 return 1;
773 /** Rebuild wibox widgets list.
774 * \param L The Lua VM state.
775 * \param wibox The wibox.
777 static void
778 wibox_widgets_table_build(lua_State *L, wibox_t *wibox)
780 widget_node_array_wipe(&wibox->widgets);
781 widget_node_array_init(&wibox->widgets);
782 luaA_table2widgets(L, &wibox->widgets);
783 wibox_need_update(wibox);
786 /** Check if a wibox widget table has an item.
787 * \param L The Lua VM state.
788 * \param wibox The wibox.
789 * \param item The item to look for.
791 static bool
792 luaA_wibox_hasitem(lua_State *L, wibox_t *wibox, const void *item)
794 if(wibox->widgets_table != LUA_REFNIL)
796 lua_rawgeti(globalconf.L, LUA_REGISTRYINDEX, wibox->widgets_table);
797 if(lua_topointer(L, -1) == item || luaA_hasitem(L, item))
798 return true;
800 return false;
803 /** Invalidate a wibox by a Lua object (table, etc).
804 * \param L The Lua VM state.
805 * \param item The object identifier.
807 void
808 luaA_wibox_invalidate_byitem(lua_State *L, const void *item)
810 foreach(screen, globalconf.screens)
811 foreach(w, screen->wiboxes)
813 wibox_t *wibox = *w;
814 if(luaA_wibox_hasitem(L, wibox, item))
816 /* recompute widget node list */
817 wibox_widgets_table_build(L, wibox);
818 lua_pop(L, 1); /* remove widgets table */
823 foreach(_c, globalconf.clients)
825 client_t *c = *_c;
826 if(c->titlebar && luaA_wibox_hasitem(L, c->titlebar, item))
828 /* recompute widget node list */
829 wibox_widgets_table_build(L, c->titlebar);
830 lua_pop(L, 1); /* remove widgets table */
835 /** Wibox object.
836 * \param L The Lua VM state.
837 * \return The number of elements pushed on stack.
838 * \luastack
839 * \lfield screen Screen number.
840 * \lfield client The client attached to this titlebar.
841 * \lfield border_width Border width.
842 * \lfield border_color Border color.
843 * \lfield align The alignment.
844 * \lfield fg Foreground color.
845 * \lfield bg Background color.
846 * \lfield position The position.
847 * \lfield ontop On top of other windows.
848 * \lfield cursor The mouse cursor.
849 * \lfield mouse_enter A function to execute when the mouse enter the widget.
850 * \lfield mouse_leave A function to execute when the mouse leave the widget.
852 static int
853 luaA_wibox_index(lua_State *L)
855 size_t len;
856 wibox_t *wibox = luaL_checkudata(L, 1, "wibox");
857 const char *attr = luaL_checklstring(L, 2, &len);
859 if(luaA_usemetatable(L, 1, 2))
860 return 1;
862 switch(a_tokenize(attr, len))
864 case A_TK_VISIBLE:
865 lua_pushboolean(L, wibox->isvisible);
866 break;
867 case A_TK_CLIENT:
868 return client_push(L, client_getbytitlebar(wibox));
869 case A_TK_SCREEN:
870 if(!wibox->screen)
871 return 0;
872 lua_pushnumber(L, screen_array_indexof(&globalconf.screens, wibox->screen) + 1);
873 break;
874 case A_TK_BORDER_WIDTH:
875 lua_pushnumber(L, wibox->sw.border.width);
876 break;
877 case A_TK_BORDER_COLOR:
878 luaA_pushxcolor(L, &wibox->sw.border.color);
879 break;
880 case A_TK_ALIGN:
881 lua_pushstring(L, draw_align_tostr(wibox->align));
882 break;
883 case A_TK_FG:
884 luaA_pushxcolor(L, &wibox->sw.ctx.fg);
885 break;
886 case A_TK_BG:
887 luaA_pushxcolor(L, &wibox->sw.ctx.bg);
888 break;
889 case A_TK_BG_IMAGE:
890 image_push(L, wibox->bg_image);
891 break;
892 case A_TK_POSITION:
893 lua_pushstring(L, position_tostr(wibox->position));
894 break;
895 case A_TK_ONTOP:
896 lua_pushboolean(L, wibox->ontop);
897 break;
898 case A_TK_ORIENTATION:
899 lua_pushstring(L, orientation_tostr(wibox->sw.orientation));
900 break;
901 case A_TK_WIDGETS:
902 if(wibox->widgets_table != LUA_REFNIL)
903 lua_rawgeti(L, LUA_REGISTRYINDEX, wibox->widgets_table);
904 else
905 lua_pushnil(L);
906 break;
907 case A_TK_CURSOR:
908 lua_pushstring(L, wibox->cursor);
909 break;
910 case A_TK_OPACITY:
912 double d;
913 if ((d = window_opacity_get(wibox->sw.window)) >= 0)
914 lua_pushnumber(L, d);
915 else
916 return 0;
918 break;
919 case A_TK_MOUSE_ENTER:
920 if(wibox->mouse_enter != LUA_REFNIL)
921 lua_rawgeti(L, LUA_REGISTRYINDEX, wibox->mouse_enter);
922 else
923 return 0;
924 return 1;
925 case A_TK_MOUSE_LEAVE:
926 if(wibox->mouse_leave != LUA_REFNIL)
927 lua_rawgeti(L, LUA_REGISTRYINDEX, wibox->mouse_leave);
928 else
929 return 0;
930 return 1;
931 default:
932 return 0;
935 return 1;
938 /* Set or get the wibox geometry.
939 * \param L The Lua VM state.
940 * \return The number of elements pushed on stack.
941 * \luastack
942 * \lparam An optional table with wibox geometry.
943 * \lreturn The wibox geometry.
945 static int
946 luaA_wibox_geometry(lua_State *L)
948 wibox_t *wibox = luaL_checkudata(L, 1, "wibox");
950 if(lua_gettop(L) == 2)
952 area_t wingeom;
954 luaA_checktable(L, 2);
955 wingeom.x = luaA_getopt_number(L, 2, "x", wibox->sw.geometry.x);
956 wingeom.y = luaA_getopt_number(L, 2, "y", wibox->sw.geometry.y);
957 wingeom.width = luaA_getopt_number(L, 2, "width", wibox->sw.geometry.width);
958 wingeom.height = luaA_getopt_number(L, 2, "height", wibox->sw.geometry.height);
960 switch(wibox->type)
962 case WIBOX_TYPE_TITLEBAR:
963 wibox_resize(wibox, wingeom.width, wingeom.height);
964 break;
965 case WIBOX_TYPE_NORMAL:
966 if(wibox->position == Floating)
967 wibox_moveresize(wibox, wingeom);
968 else if(wingeom.width != wibox->sw.geometry.width
969 || wingeom.height != wibox->sw.geometry.height)
971 wibox_resize(wibox, wingeom.width, wingeom.height);
972 wibox->screen->need_arrange = true;
974 break;
978 return luaA_pusharea(L, wibox->sw.geometry);
981 /** Wibox newindex.
982 * \param L The Lua VM state.
983 * \return The number of elements pushed on stack.
985 static int
986 luaA_wibox_newindex(lua_State *L)
988 size_t len;
989 wibox_t *wibox = luaL_checkudata(L, 1, "wibox");
990 const char *buf, *attr = luaL_checklstring(L, 2, &len);
991 awesome_token_t tok;
993 switch((tok = a_tokenize(attr, len)))
995 bool b;
997 case A_TK_FG:
998 if((buf = luaL_checklstring(L, 3, &len)))
999 if(xcolor_init_reply(xcolor_init_unchecked(&wibox->sw.ctx.fg, buf, len)))
1000 wibox->need_update = true;
1001 break;
1002 case A_TK_BG:
1003 if((buf = luaL_checklstring(L, 3, &len)))
1004 if(xcolor_init_reply(xcolor_init_unchecked(&wibox->sw.ctx.bg, buf, len)))
1005 wibox->need_update = true;
1006 break;
1007 case A_TK_BG_IMAGE:
1008 image_unref(L, wibox->bg_image);
1009 wibox->bg_image = image_ref(L);
1010 wibox->need_update = true;
1011 break;
1012 case A_TK_ALIGN:
1013 buf = luaL_checklstring(L, 3, &len);
1014 wibox->align = draw_align_fromstr(buf, len);
1015 switch(wibox->type)
1017 case WIBOX_TYPE_NORMAL:
1018 wibox_position_update(wibox);
1019 break;
1020 case WIBOX_TYPE_TITLEBAR:
1021 titlebar_update_geometry(client_getbytitlebar(wibox));
1022 break;
1024 break;
1025 case A_TK_POSITION:
1026 switch(wibox->type)
1028 case WIBOX_TYPE_TITLEBAR:
1029 return luaA_titlebar_newindex(L, wibox, tok);
1030 case WIBOX_TYPE_NORMAL:
1031 if((buf = luaL_checklstring(L, 3, &len)))
1032 wibox_setposition(wibox, position_fromstr(buf, len));
1033 break;
1035 break;
1036 case A_TK_CLIENT:
1037 /* first detach */
1038 if(lua_isnil(L, 3))
1039 titlebar_client_detach(client_getbytitlebar(wibox));
1040 else
1042 client_t *c = luaA_client_checkudata(L, -1);
1043 lua_pushvalue(L, 1);
1044 titlebar_client_attach(c);
1046 break;
1047 case A_TK_CURSOR:
1048 if((buf = luaL_checkstring(L, 3)))
1050 uint16_t cursor_font = xcursor_font_fromstr(buf);
1051 if(cursor_font)
1053 xcb_cursor_t cursor = xcursor_new(globalconf.connection, cursor_font);
1054 p_delete(&wibox->cursor);
1055 wibox->cursor = a_strdup(buf);
1056 simplewindow_cursor_set(&wibox->sw, cursor);
1059 break;
1060 case A_TK_SCREEN:
1061 if(lua_isnil(L, 3))
1063 wibox_detach(wibox);
1064 titlebar_client_detach(client_getbytitlebar(wibox));
1066 else
1068 int screen = luaL_checknumber(L, 3) - 1;
1069 luaA_checkscreen(screen);
1070 if(!wibox->screen || screen != screen_array_indexof(&globalconf.screens, wibox->screen))
1072 titlebar_client_detach(client_getbytitlebar(wibox));
1073 lua_pushvalue(L, 1);
1074 wibox_attach(&globalconf.screens.tab[screen]);
1077 break;
1078 case A_TK_ONTOP:
1079 b = luaA_checkboolean(L, 3);
1080 if(b != wibox->ontop)
1082 wibox->ontop = b;
1083 client_stack();
1085 break;
1086 case A_TK_ORIENTATION:
1087 if((buf = luaL_checklstring(L, 3, &len)))
1089 simplewindow_orientation_set(&wibox->sw, orientation_fromstr(buf, len));
1090 wibox_need_update(wibox);
1092 break;
1093 case A_TK_BORDER_COLOR:
1094 if((buf = luaL_checklstring(L, 3, &len)))
1095 if(xcolor_init_reply(xcolor_init_unchecked(&wibox->sw.border.color, buf, len)))
1096 if(wibox->sw.window)
1097 simplewindow_border_color_set(&wibox->sw, &wibox->sw.border.color);
1098 break;
1099 case A_TK_VISIBLE:
1100 b = luaA_checkboolean(L, 3);
1101 if(b != wibox->isvisible)
1102 switch(wibox->type)
1104 case WIBOX_TYPE_NORMAL:
1105 wibox_setvisible(wibox, b);
1106 break;
1107 case WIBOX_TYPE_TITLEBAR:
1108 titlebar_set_visible(wibox, b);
1109 break;
1111 break;
1112 case A_TK_WIDGETS:
1113 if(luaA_isloop(L, 3))
1115 luaA_warn(L, "table is looping, cannot use this as widget table");
1116 return 0;
1118 /* register object */
1119 luaA_register(L, 3, &wibox->widgets_table);
1120 /* duplicate table because next function will eat it */
1121 lua_pushvalue(L, -1);
1122 /* recompute widget node list */
1123 wibox_widgets_table_build(L, wibox);
1124 luaA_table2wtable(L);
1125 break;
1126 case A_TK_OPACITY:
1127 if(lua_isnil(L, 3))
1128 window_opacity_set(wibox->sw.window, -1);
1129 else
1131 double d = luaL_checknumber(L, 3);
1132 if(d >= 0 && d <= 1)
1133 window_opacity_set(wibox->sw.window, d);
1135 break;
1136 case A_TK_MOUSE_ENTER:
1137 luaA_registerfct(L, 3, &wibox->mouse_enter);
1138 return 0;
1139 case A_TK_MOUSE_LEAVE:
1140 luaA_registerfct(L, 3, &wibox->mouse_leave);
1141 return 0;
1142 default:
1143 switch(wibox->type)
1145 case WIBOX_TYPE_TITLEBAR:
1146 return luaA_titlebar_newindex(L, wibox, tok);
1147 case WIBOX_TYPE_NORMAL:
1148 break;
1152 return 0;
1155 /** Get or set mouse buttons bindings to a wibox.
1156 * \param L The Lua VM state.
1157 * \luastack
1158 * \lvalue A wibox.
1159 * \lparam An array of mouse button bindings objects, or nothing.
1160 * \return The array of mouse button bindings objects of this wibox.
1162 static int
1163 luaA_wibox_buttons(lua_State *L)
1165 wibox_t *wibox = luaL_checkudata(L, 1, "wibox");
1166 button_array_t *buttons = &wibox->buttons;
1168 if(lua_gettop(L) == 2)
1170 luaA_button_array_set(L, 2, buttons);
1171 return 1;
1174 return luaA_button_array_get(L, buttons);
1177 const struct luaL_reg awesome_wibox_methods[] =
1179 { "__call", luaA_wibox_new },
1180 { NULL, NULL }
1182 const struct luaL_reg awesome_wibox_meta[] =
1184 { "buttons", luaA_wibox_buttons },
1185 { "geometry", luaA_wibox_geometry },
1186 { "__index", luaA_wibox_index },
1187 { "__newindex", luaA_wibox_newindex },
1188 { "__gc", luaA_wibox_gc },
1189 { "__tostring", luaA_wibox_tostring },
1190 { NULL, NULL },
1193 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80