luaobject: add export property macro
[awesome.git] / wibox.c
blob905cbd8494b47983b0535696643943976190cdf9
1 /*
2 * wibox.c - wibox functions
4 * Copyright © 2008-2009 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 <xcb/shape.h>
24 #include "screen.h"
25 #include "wibox.h"
26 #include "titlebar.h"
27 #include "client.h"
28 #include "screen.h"
29 #include "window.h"
30 #include "common/xcursor.h"
31 #include "common/xutil.h"
33 /** Take care of garbage collecting a wibox.
34 * \param L The Lua VM state.
35 * \return The number of elements pushed on stack, 0!
37 static int
38 luaA_wibox_gc(lua_State *L)
40 wibox_t *wibox = luaA_checkudata(L, 1, &wibox_class);
41 p_delete(&wibox->cursor);
42 wibox_wipe(wibox);
43 button_array_wipe(&wibox->buttons);
44 widget_node_array_wipe(&wibox->widgets);
45 return luaA_object_gc(L);
48 void
49 wibox_unref_simplified(wibox_t **item)
51 luaA_object_unref(globalconf.L, *item);
54 static void
55 wibox_need_update(wibox_t *wibox)
57 wibox->need_update = true;
58 wibox->mouse_over = NULL;
61 static int
62 have_shape(void)
64 const xcb_query_extension_reply_t *reply;
66 reply = xcb_get_extension_data(globalconf.connection, &xcb_shape_id);
67 if (!reply || !reply->present)
68 return 0;
70 /* We don't need a specific version of SHAPE, no version check required */
71 return 1;
74 static void
75 shape_update(xcb_window_t win, xcb_shape_kind_t kind, image_t *image, int offset)
77 xcb_pixmap_t shape;
79 if(image)
80 shape = image_to_1bit_pixmap(image, win);
81 else
82 /* Reset the shape */
83 shape = XCB_NONE;
85 xcb_shape_mask(globalconf.connection, XCB_SHAPE_SO_SET, kind,
86 win, offset, offset, shape);
88 if (shape != XCB_NONE)
89 xcb_free_pixmap(globalconf.connection, shape);
92 /** Update the window's shape.
93 * \param wibox The simplw window whose shape should be updated.
95 static void
96 wibox_shape_update(wibox_t *wibox)
98 if(wibox->window == XCB_NONE)
99 return;
101 if(!have_shape())
103 static bool warned = false;
104 if(!warned)
105 warn("The X server doesn't have the SHAPE extension; "
106 "can't change window's shape");
107 warned = true;
108 return;
111 shape_update(wibox->window, XCB_SHAPE_SK_CLIP, wibox->shape.clip, 0);
112 shape_update(wibox->window, XCB_SHAPE_SK_BOUNDING, wibox->shape.bounding, - wibox->border.width);
114 wibox->need_shape_update = false;
117 static void
118 wibox_draw_context_update(wibox_t *w, xcb_screen_t *s)
120 xcolor_t fg = w->ctx.fg, bg = w->ctx.bg;
121 int phys_screen = w->ctx.phys_screen;
123 draw_context_wipe(&w->ctx);
125 /* update draw context */
126 switch(w->orientation)
128 case South:
129 case North:
130 /* we need a new pixmap this way [ ] to render */
131 w->ctx.pixmap = xcb_generate_id(globalconf.connection);
132 xcb_create_pixmap(globalconf.connection,
133 s->root_depth,
134 w->ctx.pixmap, s->root,
135 w->geometry.height,
136 w->geometry.width);
137 draw_context_init(&w->ctx, phys_screen,
138 w->geometry.height,
139 w->geometry.width,
140 w->ctx.pixmap, &fg, &bg);
141 break;
142 case East:
143 draw_context_init(&w->ctx, phys_screen,
144 w->geometry.width,
145 w->geometry.height,
146 w->pixmap, &fg, &bg);
147 break;
151 /** Initialize a wibox.
152 * \param w The wibox to initialize.
153 * \param phys_screen Physical screen number.
155 void
156 wibox_init(wibox_t *w, int phys_screen)
158 xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
160 w->window = xcb_generate_id(globalconf.connection);
161 xcb_create_window(globalconf.connection, s->root_depth, w->window, s->root,
162 w->geometry.x, w->geometry.y,
163 w->geometry.width, w->geometry.height,
164 w->border.width, XCB_COPY_FROM_PARENT, s->root_visual,
165 XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL
166 | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK,
167 (const uint32_t [])
169 XCB_BACK_PIXMAP_PARENT_RELATIVE,
170 w->border.color.pixel,
172 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
173 | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_ENTER_WINDOW
174 | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_STRUCTURE_NOTIFY
175 | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE
176 | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE
177 | XCB_EVENT_MASK_PROPERTY_CHANGE
180 /* Create a pixmap. */
181 w->pixmap = xcb_generate_id(globalconf.connection);
182 xcb_create_pixmap(globalconf.connection, s->root_depth, w->pixmap, s->root,
183 w->geometry.width, w->geometry.height);
185 /* Update draw context physical screen, important for Zaphod. */
186 w->ctx.phys_screen = phys_screen;
187 wibox_draw_context_update(w, s);
189 /* The default GC is just a newly created associated to the root window */
190 w->gc = xcb_generate_id(globalconf.connection);
191 xcb_create_gc(globalconf.connection, w->gc, s->root, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND,
192 (const uint32_t[]) { s->black_pixel, s->white_pixel });
194 wibox_shape_update(w);
197 /** Refresh the window content by copying its pixmap data to its window.
198 * \param w The wibox to refresh.
200 static inline void
201 wibox_refresh_pixmap(wibox_t *w)
203 wibox_refresh_pixmap_partial(w, 0, 0, w->geometry.width, w->geometry.height);
206 /** Set a wibox opacity.
207 * \param w The wibox the adjust the opacity of.
208 * \param opacity A value between 0 and 1 which describes the opacity.
210 static inline void
211 wibox_opacity_set(wibox_t *w, double opacity)
213 w->opacity = opacity;
214 if(w->window != XCB_NONE)
215 window_opacity_set(w->window, opacity);
218 void
219 wibox_moveresize(wibox_t *w, area_t geometry)
221 if(w->window)
223 int number_of_vals = 0;
224 uint32_t moveresize_win_vals[4], mask_vals = 0;
226 if(w->geometry.x != geometry.x)
228 w->geometry.x = moveresize_win_vals[number_of_vals++] = geometry.x;
229 mask_vals |= XCB_CONFIG_WINDOW_X;
232 if(w->geometry.y != geometry.y)
234 w->geometry.y = moveresize_win_vals[number_of_vals++] = geometry.y;
235 mask_vals |= XCB_CONFIG_WINDOW_Y;
238 if(geometry.width > 0 && w->geometry.width != geometry.width)
240 w->geometry.width = moveresize_win_vals[number_of_vals++] = geometry.width;
241 mask_vals |= XCB_CONFIG_WINDOW_WIDTH;
244 if(geometry.height > 0 && w->geometry.height != geometry.height)
246 w->geometry.height = moveresize_win_vals[number_of_vals++] = geometry.height;
247 mask_vals |= XCB_CONFIG_WINDOW_HEIGHT;
250 if(mask_vals & (XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT))
252 xcb_free_pixmap(globalconf.connection, w->pixmap);
253 /* orientation != East */
254 if(w->pixmap != w->ctx.pixmap)
255 xcb_free_pixmap(globalconf.connection, w->ctx.pixmap);
256 w->pixmap = xcb_generate_id(globalconf.connection);
257 xcb_screen_t *s = xutil_screen_get(globalconf.connection, w->ctx.phys_screen);
258 xcb_create_pixmap(globalconf.connection, s->root_depth, w->pixmap, s->root,
259 w->geometry.width, w->geometry.height);
260 wibox_draw_context_update(w, s);
263 if(mask_vals)
264 xcb_configure_window(globalconf.connection, w->window, mask_vals, moveresize_win_vals);
266 w->screen = screen_getbycoord(w->screen, w->geometry.x, w->geometry.y);
268 else
269 w->geometry = geometry;
271 wibox_need_update(w);
274 /** Refresh the window content by copying its pixmap data to its window.
275 * \param wibox The wibox to refresh.
276 * \param x The copy starting point x component.
277 * \param y The copy starting point y component.
278 * \param w The copy width from the x component.
279 * \param h The copy height from the y component.
281 void
282 wibox_refresh_pixmap_partial(wibox_t *wibox,
283 int16_t x, int16_t y,
284 uint16_t w, uint16_t h)
286 xcb_copy_area(globalconf.connection, wibox->pixmap,
287 wibox->window, wibox->gc, x, y, x, y,
288 w, h);
291 /** Set a wibox border width.
292 * \param w The wibox to change border width.
293 * \param border_width The border width in pixel.
295 void
296 wibox_border_width_set(wibox_t *w, uint32_t border_width)
298 xcb_configure_window(globalconf.connection, w->window, XCB_CONFIG_WINDOW_BORDER_WIDTH,
299 &border_width);
300 w->border.width = border_width;
303 /** Set a wibox border color.
304 * \param w The wibox to change border width.
305 * \param color The border color.
307 void
308 wibox_border_color_set(wibox_t *w, const xcolor_t *color)
310 xcb_change_window_attributes(globalconf.connection, w->window,
311 XCB_CW_BORDER_PIXEL, &color->pixel);
312 w->border.color = *color;
315 /** Set wibox orientation.
316 * \param w The wibox.
317 * \param o The new orientation.
319 void
320 wibox_orientation_set(wibox_t *w, orientation_t o)
322 if(o != w->orientation)
324 xcb_screen_t *s = xutil_screen_get(globalconf.connection, w->ctx.phys_screen);
325 w->orientation = o;
326 /* orientation != East */
327 if(w->pixmap != w->ctx.pixmap)
328 xcb_free_pixmap(globalconf.connection, w->ctx.pixmap);
329 wibox_draw_context_update(w, s);
333 static void
334 wibox_map(wibox_t *wibox)
336 xcb_map_window(globalconf.connection, wibox->window);
337 /* We must make sure the wibox does not display garbage */
338 wibox_need_update(wibox);
339 /* Stack this wibox correctly */
340 client_stack();
343 /** Kick out systray windows.
344 * \param phys_screen Physical screen number.
346 static void
347 wibox_systray_kickout(int phys_screen)
349 xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
351 if(globalconf.screens.tab[phys_screen].systray.parent != s->root)
353 /* Who! Check that we're not deleting a wibox with a systray, because it
354 * may be its parent. If so, we reparent to root before, otherwise it will
355 * hurt very much. */
356 xcb_reparent_window(globalconf.connection,
357 globalconf.screens.tab[phys_screen].systray.window,
358 s->root, -512, -512);
360 globalconf.screens.tab[phys_screen].systray.parent = s->root;
364 static void
365 wibox_systray_refresh(wibox_t *wibox)
367 if(!wibox->screen)
368 return;
370 for(int i = 0; i < wibox->widgets.len; i++)
372 widget_node_t *systray = &wibox->widgets.tab[i];
373 if(systray->widget->type == widget_systray)
375 uint32_t config_back[] = { wibox->ctx.bg.pixel };
376 uint32_t config_win_vals[4];
377 uint32_t config_win_vals_off[2] = { -512, -512 };
378 xembed_window_t *em;
379 int phys_screen = wibox->ctx.phys_screen;
381 if(wibox->isvisible
382 && systray->widget->isvisible
383 && systray->geometry.width)
385 /* Set background of the systray window. */
386 xcb_change_window_attributes(globalconf.connection,
387 globalconf.screens.tab[phys_screen].systray.window,
388 XCB_CW_BACK_PIXEL, config_back);
389 /* Map it. */
390 xcb_map_window(globalconf.connection, globalconf.screens.tab[phys_screen].systray.window);
391 /* Move it. */
392 switch(wibox->orientation)
394 case North:
395 config_win_vals[0] = systray->geometry.y;
396 config_win_vals[1] = wibox->geometry.height - systray->geometry.x - systray->geometry.width;
397 config_win_vals[2] = systray->geometry.height;
398 config_win_vals[3] = systray->geometry.width;
399 break;
400 case South:
401 config_win_vals[0] = systray->geometry.y;
402 config_win_vals[1] = systray->geometry.x;
403 config_win_vals[2] = systray->geometry.height;
404 config_win_vals[3] = systray->geometry.width;
405 break;
406 case East:
407 config_win_vals[0] = systray->geometry.x;
408 config_win_vals[1] = systray->geometry.y;
409 config_win_vals[2] = systray->geometry.width;
410 config_win_vals[3] = systray->geometry.height;
411 break;
413 /* reparent */
414 if(globalconf.screens.tab[phys_screen].systray.parent != wibox->window)
416 xcb_reparent_window(globalconf.connection,
417 globalconf.screens.tab[phys_screen].systray.window,
418 wibox->window,
419 config_win_vals[0], config_win_vals[1]);
420 globalconf.screens.tab[phys_screen].systray.parent = wibox->window;
422 xcb_configure_window(globalconf.connection,
423 globalconf.screens.tab[phys_screen].systray.window,
424 XCB_CONFIG_WINDOW_X
425 | XCB_CONFIG_WINDOW_Y
426 | XCB_CONFIG_WINDOW_WIDTH
427 | XCB_CONFIG_WINDOW_HEIGHT,
428 config_win_vals);
429 /* width = height = systray height */
430 config_win_vals[2] = config_win_vals[3] = systray->geometry.height;
431 config_win_vals[0] = 0;
433 else
434 return wibox_systray_kickout(phys_screen);
436 switch(wibox->orientation)
438 case North:
439 config_win_vals[1] = systray->geometry.width - config_win_vals[3];
440 for(int j = 0; j < globalconf.embedded.len; j++)
442 em = &globalconf.embedded.tab[j];
443 if(em->phys_screen == phys_screen)
445 if(config_win_vals[1] - config_win_vals[2] >= (uint32_t) wibox->geometry.y)
447 xcb_map_window(globalconf.connection, em->win);
448 xcb_configure_window(globalconf.connection, em->win,
449 XCB_CONFIG_WINDOW_X
450 | XCB_CONFIG_WINDOW_Y
451 | XCB_CONFIG_WINDOW_WIDTH
452 | XCB_CONFIG_WINDOW_HEIGHT,
453 config_win_vals);
454 config_win_vals[1] -= config_win_vals[3];
456 else
457 xcb_configure_window(globalconf.connection, em->win,
458 XCB_CONFIG_WINDOW_X
459 | XCB_CONFIG_WINDOW_Y,
460 config_win_vals_off);
463 break;
464 case South:
465 config_win_vals[1] = 0;
466 for(int j = 0; j < globalconf.embedded.len; j++)
468 em = &globalconf.embedded.tab[j];
469 if(em->phys_screen == phys_screen)
471 /* if(y + width <= wibox.y + systray.right) */
472 if(config_win_vals[1] + config_win_vals[3] <= (uint32_t) wibox->geometry.y + AREA_RIGHT(systray->geometry))
474 xcb_map_window(globalconf.connection, em->win);
475 xcb_configure_window(globalconf.connection, em->win,
476 XCB_CONFIG_WINDOW_X
477 | XCB_CONFIG_WINDOW_Y
478 | XCB_CONFIG_WINDOW_WIDTH
479 | XCB_CONFIG_WINDOW_HEIGHT,
480 config_win_vals);
481 config_win_vals[1] += config_win_vals[3];
483 else
484 xcb_configure_window(globalconf.connection, em->win,
485 XCB_CONFIG_WINDOW_X
486 | XCB_CONFIG_WINDOW_Y,
487 config_win_vals_off);
490 break;
491 case East:
492 config_win_vals[1] = 0;
493 for(int j = 0; j < globalconf.embedded.len; j++)
495 em = &globalconf.embedded.tab[j];
496 if(em->phys_screen == phys_screen)
498 /* if(x + width < systray.x + systray.width) */
499 if(config_win_vals[0] + config_win_vals[2] <= (uint32_t) AREA_RIGHT(systray->geometry) + wibox->geometry.x)
501 xcb_map_window(globalconf.connection, em->win);
502 xcb_configure_window(globalconf.connection, em->win,
503 XCB_CONFIG_WINDOW_X
504 | XCB_CONFIG_WINDOW_Y
505 | XCB_CONFIG_WINDOW_WIDTH
506 | XCB_CONFIG_WINDOW_HEIGHT,
507 config_win_vals);
508 config_win_vals[0] += config_win_vals[2];
510 else
511 xcb_configure_window(globalconf.connection, em->win,
512 XCB_CONFIG_WINDOW_X
513 | XCB_CONFIG_WINDOW_Y,
514 config_win_vals_off);
517 break;
519 break;
524 /** Get a wibox by its window.
525 * \param win The window id.
526 * \return A wibox if found, NULL otherwise.
528 wibox_t *
529 wibox_getbywin(xcb_window_t win)
531 foreach(w, globalconf.wiboxes)
532 if((*w)->window == win)
533 return *w;
535 foreach(_c, globalconf.clients)
537 client_t *c = *_c;
538 if(c->titlebar && c->titlebar->window == win)
539 return c->titlebar;
542 return NULL;
545 /** Draw a wibox.
546 * \param wibox The wibox to draw.
548 static void
549 wibox_draw(wibox_t *wibox)
551 if(wibox->isvisible)
553 widget_render(wibox);
554 wibox_refresh_pixmap(wibox);
556 wibox->need_update = false;
559 wibox_systray_refresh(wibox);
562 /** Refresh all wiboxes.
564 void
565 wibox_refresh(void)
567 foreach(w, globalconf.wiboxes)
569 if((*w)->need_shape_update)
570 wibox_shape_update(*w);
571 if((*w)->need_update)
572 wibox_draw(*w);
575 foreach(_c, globalconf.clients)
577 client_t *c = *_c;
578 if(c->titlebar && c->titlebar->need_update)
579 wibox_draw(c->titlebar);
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)
597 if(wibox->isvisible)
598 wibox_map(wibox);
599 else
600 xcb_unmap_window(globalconf.connection, wibox->window);
602 /* kick out systray if needed */
603 wibox_systray_refresh(wibox);
606 hook_property(wibox, "visible");
610 /** Destroy all X resources of a wibox.
611 * \param w The wibox to wipe.
613 void
614 wibox_wipe(wibox_t *w)
616 if(w->window)
618 xcb_destroy_window(globalconf.connection, w->window);
619 w->window = XCB_NONE;
621 if(w->pixmap)
623 xcb_free_pixmap(globalconf.connection, w->pixmap);
624 w->pixmap = XCB_NONE;
626 if(w->gc)
628 xcb_free_gc(globalconf.connection, w->gc);
629 w->gc = XCB_NONE;
631 draw_context_wipe(&w->ctx);
634 /** Remove a wibox from a screen.
635 * \param wibox Wibox to detach from screen.
637 static void
638 wibox_detach(wibox_t *wibox)
640 if(wibox->screen)
642 bool v;
644 /* save visible state */
645 v = wibox->isvisible;
646 wibox->isvisible = false;
647 wibox_systray_refresh(wibox);
648 /* restore visibility */
649 wibox->isvisible = v;
651 wibox->mouse_over = NULL;
653 wibox_wipe(wibox);
655 foreach(item, globalconf.wiboxes)
656 if(*item == wibox)
658 wibox_array_remove(&globalconf.wiboxes, item);
659 break;
662 hook_property(wibox, "screen");
664 wibox->screen = NULL;
666 luaA_object_unref(globalconf.L, wibox);
670 /** Attach a wibox that is on top of the stack.
671 * \param s The screen to attach the wibox to.
673 static void
674 wibox_attach(screen_t *s)
676 int phys_screen = screen_virttophys(screen_array_indexof(&globalconf.screens, s));
678 wibox_t *wibox = luaA_object_ref(globalconf.L, -1);
680 wibox_detach(wibox);
682 /* Set the wibox screen */
683 wibox->screen = s;
685 /* Check that the wibox coordinates matches the screen. */
686 screen_t *cscreen =
687 screen_getbycoord(wibox->screen, wibox->geometry.x, wibox->geometry.y);
689 /* If it does not match, move it to the screen coordinates */
690 if(cscreen != wibox->screen)
691 wibox_moveresize(wibox, (area_t) { .x = s->geometry.x,
692 .y = s->geometry.y,
693 .width = wibox->geometry.width,
694 .height = wibox->geometry.height });
696 wibox_array_append(&globalconf.wiboxes, wibox);
698 wibox_init(wibox, phys_screen);
700 window_set_cursor(wibox->window,
701 xcursor_new(globalconf.connection, xcursor_font_fromstr(wibox->cursor)));
703 wibox_opacity_set(wibox, wibox->opacity);
705 if(wibox->isvisible)
706 wibox_map(wibox);
707 else
708 wibox_need_update(wibox);
710 hook_property(wibox, "screen");
713 /** Create a new wibox.
714 * \param L The Lua VM state.
716 * \luastack
717 * \lparam A table with optionaly defined values:
718 * fg, bg, border_width, border_color, ontop, width and height.
719 * \lreturn A brand new wibox.
721 static int
722 luaA_wibox_new(lua_State *L)
724 wibox_t *w;
725 const char *buf;
726 size_t len;
727 xcolor_init_request_t reqs[3];
728 int i, reqs_nbr = -1;
730 luaA_checktable(L, 2);
732 w = wibox_new(L);
734 w->ctx.fg = globalconf.colors.fg;
735 if((buf = luaA_getopt_lstring(L, 2, "fg", NULL, &len)))
736 reqs[++reqs_nbr] = xcolor_init_unchecked(&w->ctx.fg, buf, len);
738 w->ctx.bg = globalconf.colors.bg;
739 if((buf = luaA_getopt_lstring(L, 2, "bg", NULL, &len)))
740 reqs[++reqs_nbr] = xcolor_init_unchecked(&w->ctx.bg, buf, len);
742 w->border.color = globalconf.colors.bg;
743 if((buf = luaA_getopt_lstring(L, 2, "border_color", NULL, &len)))
744 reqs[++reqs_nbr] = xcolor_init_unchecked(&w->border.color, buf, len);
746 w->ontop = luaA_getopt_boolean(L, 2, "ontop", false);
748 w->opacity = -1;
749 w->border.width = luaA_getopt_number(L, 2, "border_width", 0);
750 w->geometry.x = luaA_getopt_number(L, 2, "x", 0);
751 w->geometry.y = luaA_getopt_number(L, 2, "y", 0);
752 w->geometry.width = luaA_getopt_number(L, 2, "width", 100);
753 w->geometry.height = luaA_getopt_number(L, 2, "height", globalconf.font->height * 1.5);
755 w->isvisible = true;
756 w->cursor = a_strdup("left_ptr");
758 for(i = 0; i <= reqs_nbr; i++)
759 xcolor_init_reply(reqs[i]);
761 return 1;
764 /** Check if a wibox widget table has an item.
765 * \param L The Lua VM state.
766 * \param wibox The wibox.
767 * \param item The item to look for.
769 static bool
770 luaA_wibox_hasitem(lua_State *L, wibox_t *wibox, const void *item)
772 if(wibox->widgets_table)
774 luaA_object_push(L, wibox);
775 luaA_object_push_item(L, -1, wibox->widgets_table);
776 lua_remove(L, -2);
777 if(lua_topointer(L, -1) == item || luaA_hasitem(L, item))
778 return true;
780 return false;
783 /** Invalidate a wibox by a Lua object (table, etc).
784 * \param L The Lua VM state.
785 * \param item The object identifier.
787 void
788 luaA_wibox_invalidate_byitem(lua_State *L, const void *item)
790 foreach(w, globalconf.wiboxes)
792 wibox_t *wibox = *w;
793 if(luaA_wibox_hasitem(L, wibox, item))
795 /* update wibox */
796 wibox_need_update(wibox);
797 lua_pop(L, 1); /* remove widgets table */
802 foreach(_c, globalconf.clients)
804 client_t *c = *_c;
805 if(c->titlebar && luaA_wibox_hasitem(L, c->titlebar, item))
807 /* update wibox */
808 wibox_need_update(c->titlebar);
809 lua_pop(L, 1); /* remove widgets table */
814 /** Wibox object.
815 * \param L The Lua VM state.
816 * \return The number of elements pushed on stack.
817 * \luastack
818 * \lfield screen Screen number.
819 * \lfield client The client attached to (titlebar).
820 * \lfield border_width Border width.
821 * \lfield border_color Border color.
822 * \lfield align The alignment (titlebar).
823 * \lfield fg Foreground color.
824 * \lfield bg Background color.
825 * \lfield bg_image Background image.
826 * \lfield position The position (titlebar).
827 * \lfield ontop On top of other windows.
828 * \lfield cursor The mouse cursor.
829 * \lfield visible Visibility.
830 * \lfield orientation The drawing orientation: east, north or south.
831 * \lfield widgets An array with all widgets drawn on this wibox.
832 * \lfield opacity The opacity of the wibox, between 0 and 1.
833 * \lfield mouse_enter A function to execute when the mouse enter the widget.
834 * \lfield mouse_leave A function to execute when the mouse leave the widget.
835 * \lfield shape_clip Image describing the window's content shape.
836 * \lfield shape_bounding Image describing the window's border shape.
838 static int
839 luaA_wibox_index(lua_State *L)
841 size_t len;
842 wibox_t *wibox = luaA_checkudata(L, 1, &wibox_class);
843 const char *attr = luaL_checklstring(L, 2, &len);
845 if(luaA_usemetatable(L, 1, 2))
846 return 1;
848 switch(a_tokenize(attr, len))
850 case A_TK_VISIBLE:
851 lua_pushboolean(L, wibox->isvisible);
852 break;
853 case A_TK_CLIENT:
854 return luaA_object_push(L, client_getbytitlebar(wibox));
855 case A_TK_SCREEN:
856 if(!wibox->screen)
857 return 0;
858 lua_pushnumber(L, screen_array_indexof(&globalconf.screens, wibox->screen) + 1);
859 break;
860 case A_TK_BORDER_WIDTH:
861 lua_pushnumber(L, wibox->border.width);
862 break;
863 case A_TK_BORDER_COLOR:
864 luaA_pushxcolor(L, wibox->border.color);
865 break;
866 case A_TK_ALIGN:
867 if(wibox->type == WIBOX_TYPE_NORMAL)
868 luaA_deprecate(L, "awful.wibox.align");
869 lua_pushstring(L, draw_align_tostr(wibox->align));
870 break;
871 case A_TK_FG:
872 luaA_pushxcolor(L, wibox->ctx.fg);
873 break;
874 case A_TK_BG:
875 luaA_pushxcolor(L, wibox->ctx.bg);
876 break;
877 case A_TK_BG_IMAGE:
878 luaA_object_push_item(L, 1, wibox->bg_image);
879 break;
880 case A_TK_POSITION:
881 if(wibox->type == WIBOX_TYPE_NORMAL)
882 luaA_deprecate(L, "awful.wibox.attach");
883 lua_pushstring(L, position_tostr(wibox->position));
884 break;
885 case A_TK_ONTOP:
886 lua_pushboolean(L, wibox->ontop);
887 break;
888 case A_TK_ORIENTATION:
889 lua_pushstring(L, orientation_tostr(wibox->orientation));
890 break;
891 case A_TK_WIDGETS:
892 return luaA_object_push_item(L, 1, wibox->widgets_table);
893 case A_TK_CURSOR:
894 lua_pushstring(L, wibox->cursor);
895 break;
896 case A_TK_OPACITY:
897 if (wibox->opacity >= 0)
898 lua_pushnumber(L, wibox->opacity);
899 else
900 return 0;
901 break;
902 case A_TK_MOUSE_ENTER:
903 return luaA_object_push_item(L, 1, wibox->mouse_enter);
904 case A_TK_MOUSE_LEAVE:
905 return luaA_object_push_item(L, 1, wibox->mouse_leave);
906 case A_TK_SHAPE_BOUNDING:
907 return luaA_object_push_item(L, 1, wibox->shape.bounding);
908 case A_TK_SHAPE_CLIP:
909 return luaA_object_push_item(L, 1, wibox->shape.clip);
910 default:
911 return 0;
914 return 1;
917 /* Set or get the wibox geometry.
918 * \param L The Lua VM state.
919 * \return The number of elements pushed on stack.
920 * \luastack
921 * \lparam An optional table with wibox geometry.
922 * \lreturn The wibox geometry.
924 static int
925 luaA_wibox_geometry(lua_State *L)
927 wibox_t *wibox = luaA_checkudata(L, 1, &wibox_class);
929 if(lua_gettop(L) == 2)
931 area_t wingeom;
933 luaA_checktable(L, 2);
934 wingeom.x = luaA_getopt_number(L, 2, "x", wibox->geometry.x);
935 wingeom.y = luaA_getopt_number(L, 2, "y", wibox->geometry.y);
936 wingeom.width = luaA_getopt_number(L, 2, "width", wibox->geometry.width);
937 wingeom.height = luaA_getopt_number(L, 2, "height", wibox->geometry.height);
939 switch(wibox->type)
941 case WIBOX_TYPE_TITLEBAR:
942 wibox_moveresize(wibox, (area_t) { .x = wibox->geometry.x,
943 .y = wibox->geometry.y,
944 .width = wingeom.width,
945 .height = wingeom.height });
946 break;
947 case WIBOX_TYPE_NORMAL:
948 wibox_moveresize(wibox, wingeom);
949 break;
953 return luaA_pusharea(L, wibox->geometry);
956 /** Wibox newindex.
957 * \param L The Lua VM state.
958 * \return The number of elements pushed on stack.
960 static int
961 luaA_wibox_newindex(lua_State *L)
963 size_t len;
964 wibox_t *wibox = luaA_checkudata(L, 1, &wibox_class);
965 const char *buf, *attr = luaL_checklstring(L, 2, &len);
966 awesome_token_t tok;
968 switch((tok = a_tokenize(attr, len)))
970 bool b;
972 case A_TK_FG:
973 if((buf = luaL_checklstring(L, 3, &len)))
974 if(xcolor_init_reply(xcolor_init_unchecked(&wibox->ctx.fg, buf, len)))
975 wibox->need_update = true;
976 break;
977 case A_TK_BG:
978 if((buf = luaL_checklstring(L, 3, &len)))
979 if(xcolor_init_reply(xcolor_init_unchecked(&wibox->ctx.bg, buf, len)))
980 wibox->need_update = true;
981 break;
982 case A_TK_BG_IMAGE:
983 luaA_object_unref_item(L, 1, wibox->bg_image);
984 wibox->bg_image = luaA_object_ref_item(L, 1, 3);
985 wibox->need_update = true;
986 break;
987 case A_TK_ALIGN:
988 buf = luaL_checklstring(L, 3, &len);
989 wibox->align = draw_align_fromstr(buf, len);
990 switch(wibox->type)
992 case WIBOX_TYPE_NORMAL:
993 luaA_deprecate(L, "awful.wibox.align");
994 break;
995 case WIBOX_TYPE_TITLEBAR:
996 titlebar_update_geometry(client_getbytitlebar(wibox));
997 break;
999 break;
1000 case A_TK_POSITION:
1001 switch(wibox->type)
1003 case WIBOX_TYPE_NORMAL:
1004 if((buf = luaL_checklstring(L, 3, &len)))
1006 luaA_deprecate(L, "awful.wibox.attach");
1007 wibox->position = position_fromstr(buf, len);
1009 break;
1010 case WIBOX_TYPE_TITLEBAR:
1011 return luaA_titlebar_newindex(L, wibox, tok);
1013 break;
1014 case A_TK_CLIENT:
1015 /* first detach */
1016 if(lua_isnil(L, 3))
1017 titlebar_client_detach(client_getbytitlebar(wibox));
1018 else
1020 client_t *c = luaA_client_checkudata(L, -1);
1021 lua_pushvalue(L, 1);
1022 titlebar_client_attach(c);
1024 break;
1025 case A_TK_CURSOR:
1026 if((buf = luaL_checkstring(L, 3)))
1028 uint16_t cursor_font = xcursor_font_fromstr(buf);
1029 if(cursor_font)
1031 xcb_cursor_t cursor = xcursor_new(globalconf.connection, cursor_font);
1032 p_delete(&wibox->cursor);
1033 wibox->cursor = a_strdup(buf);
1034 window_set_cursor(wibox->window, cursor);
1037 break;
1038 case A_TK_SCREEN:
1039 if(lua_isnil(L, 3))
1041 wibox_detach(wibox);
1042 titlebar_client_detach(client_getbytitlebar(wibox));
1044 else
1046 int screen = luaL_checknumber(L, 3) - 1;
1047 luaA_checkscreen(screen);
1048 if(!wibox->screen || screen != screen_array_indexof(&globalconf.screens, wibox->screen))
1050 titlebar_client_detach(client_getbytitlebar(wibox));
1051 lua_pushvalue(L, 1);
1052 wibox_attach(&globalconf.screens.tab[screen]);
1055 break;
1056 case A_TK_ONTOP:
1057 b = luaA_checkboolean(L, 3);
1058 if(b != wibox->ontop)
1060 wibox->ontop = b;
1061 client_stack();
1063 break;
1064 case A_TK_ORIENTATION:
1065 if((buf = luaL_checklstring(L, 3, &len)))
1067 wibox_orientation_set(wibox, orientation_fromstr(buf, len));
1068 wibox_need_update(wibox);
1070 break;
1071 case A_TK_BORDER_COLOR:
1072 if((buf = luaL_checklstring(L, 3, &len)))
1073 if(xcolor_init_reply(xcolor_init_unchecked(&wibox->border.color, buf, len)))
1074 if(wibox->window)
1075 wibox_border_color_set(wibox, &wibox->border.color);
1076 break;
1077 case A_TK_VISIBLE:
1078 b = luaA_checkboolean(L, 3);
1079 if(b != wibox->isvisible)
1080 switch(wibox->type)
1082 case WIBOX_TYPE_NORMAL:
1083 wibox_setvisible(wibox, b);
1084 break;
1085 case WIBOX_TYPE_TITLEBAR:
1086 titlebar_set_visible(wibox, b);
1087 break;
1089 break;
1090 case A_TK_WIDGETS:
1091 if(luaA_isloop(L, 3))
1093 luaA_warn(L, "table is looping, cannot use this as widget table");
1094 return 0;
1096 /* duplicate table because next function will eat it */
1097 lua_pushvalue(L, 3);
1098 /* register object */
1099 wibox->widgets_table = luaA_object_ref_item(L, 1, -1);
1100 wibox_need_update(wibox);
1101 luaA_table2wtable(L);
1102 break;
1103 case A_TK_OPACITY:
1104 if(lua_isnil(L, 3))
1105 wibox_opacity_set(wibox, -1);
1106 else
1108 double d = luaL_checknumber(L, 3);
1109 if(d >= 0 && d <= 1)
1110 wibox_opacity_set(wibox, d);
1112 break;
1113 case A_TK_MOUSE_ENTER:
1114 luaA_checkfunction(L, 3);
1115 luaA_object_unref_item(L, 1, wibox->mouse_enter);
1116 wibox->mouse_enter = luaA_object_ref_item(L, 1, 3);
1117 return 0;
1118 case A_TK_MOUSE_LEAVE:
1119 luaA_checkfunction(L, 3);
1120 luaA_object_unref_item(L, 1, wibox->mouse_leave);
1121 wibox->mouse_leave = luaA_object_ref_item(L, 1, 3);
1122 return 0;
1123 case A_TK_SHAPE_BOUNDING:
1124 luaA_object_unref_item(L, 1, wibox->shape.bounding);
1125 wibox->shape.bounding = luaA_object_ref_item(L, 1, 3);
1126 wibox->need_shape_update = true;
1127 break;
1128 case A_TK_SHAPE_CLIP:
1129 luaA_object_unref_item(L, 1, wibox->shape.clip);
1130 wibox->shape.clip = luaA_object_ref_item(L, 1, 3);
1131 wibox->need_shape_update = true;
1132 break;
1133 default:
1134 switch(wibox->type)
1136 case WIBOX_TYPE_TITLEBAR:
1137 return luaA_titlebar_newindex(L, wibox, tok);
1138 case WIBOX_TYPE_NORMAL:
1139 break;
1143 return 0;
1146 /** Get or set mouse buttons bindings to a wibox.
1147 * \param L The Lua VM state.
1148 * \luastack
1149 * \lvalue A wibox.
1150 * \lparam An array of mouse button bindings objects, or nothing.
1151 * \return The array of mouse button bindings objects of this wibox.
1153 static int
1154 luaA_wibox_buttons(lua_State *L)
1156 wibox_t *wibox = luaA_checkudata(L, 1, &wibox_class);
1158 if(lua_gettop(L) == 2)
1160 luaA_button_array_set(L, 1, 2, &wibox->buttons);
1161 return 1;
1164 return luaA_button_array_get(L, 1, &wibox->buttons);
1167 const struct luaL_reg awesome_wibox_methods[] =
1169 LUA_CLASS_METHODS(wibox)
1170 { "__call", luaA_wibox_new },
1171 { NULL, NULL }
1173 const struct luaL_reg awesome_wibox_meta[] =
1175 LUA_OBJECT_META(wibox)
1176 { "buttons", luaA_wibox_buttons },
1177 { "geometry", luaA_wibox_geometry },
1178 { "__index", luaA_wibox_index },
1179 { "__newindex", luaA_wibox_newindex },
1180 { "__gc", luaA_wibox_gc },
1181 { NULL, NULL },
1184 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80