build: do not use common as include dir
[awesome.git] / wibox.c
blobd420eefb3c2e0e7619dffd646271a3fd020a807f
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 = luaL_checkudata(L, 1, "wibox");
41 p_delete(&wibox->cursor);
42 wibox_wipe(wibox);
43 widget_node_array_wipe(&wibox->widgets);
44 return luaA_object_gc(L);
47 void
48 wibox_unref_simplified(wibox_t **item)
50 wibox_unref(globalconf.L, *item);
53 static void
54 wibox_need_update(wibox_t *wibox)
56 wibox->need_update = true;
57 wibox->mouse_over = NULL;
60 static int
61 have_shape(void)
63 const xcb_query_extension_reply_t *reply;
65 reply = xcb_get_extension_data(globalconf.connection, &xcb_shape_id);
66 if (!reply || !reply->present)
67 return 0;
69 /* We don't need a specific version of SHAPE, no version check required */
70 return 1;
73 static void
74 shape_update(xcb_window_t win, xcb_shape_kind_t kind, image_t *image, int offset)
76 xcb_pixmap_t shape;
78 if(image)
79 shape = image_to_1bit_pixmap(image, win);
80 else
81 /* Reset the shape */
82 shape = XCB_NONE;
84 xcb_shape_mask(globalconf.connection, XCB_SHAPE_SO_SET, kind,
85 win, offset, offset, shape);
87 if (shape != XCB_NONE)
88 xcb_free_pixmap(globalconf.connection, shape);
91 /** Update the window's shape.
92 * \param wibox The simplw window whose shape should be updated.
94 static void
95 wibox_shape_update(wibox_t *wibox)
97 if(wibox->window == XCB_NONE)
98 return;
100 if(!have_shape())
102 static bool warned = false;
103 if(!warned)
104 warn("The X server doesn't have the SHAPE extension; "
105 "can't change window's shape");
106 warned = true;
107 return;
110 shape_update(wibox->window, XCB_SHAPE_SK_CLIP, wibox->shape.clip, 0);
111 shape_update(wibox->window, XCB_SHAPE_SK_BOUNDING, wibox->shape.bounding, - wibox->border.width);
113 wibox->need_shape_update = false;
116 static void
117 wibox_draw_context_update(wibox_t *w, xcb_screen_t *s)
119 xcolor_t fg = w->ctx.fg, bg = w->ctx.bg;
120 int phys_screen = w->ctx.phys_screen;
122 draw_context_wipe(&w->ctx);
124 /* update draw context */
125 switch(w->orientation)
127 case South:
128 case North:
129 /* we need a new pixmap this way [ ] to render */
130 w->ctx.pixmap = xcb_generate_id(globalconf.connection);
131 xcb_create_pixmap(globalconf.connection,
132 s->root_depth,
133 w->ctx.pixmap, s->root,
134 w->geometry.height,
135 w->geometry.width);
136 draw_context_init(&w->ctx, phys_screen,
137 w->geometry.height,
138 w->geometry.width,
139 w->ctx.pixmap, &fg, &bg);
140 break;
141 case East:
142 draw_context_init(&w->ctx, phys_screen,
143 w->geometry.width,
144 w->geometry.height,
145 w->pixmap, &fg, &bg);
146 break;
150 /** Initialize a wibox.
151 * \param w The wibox to initialize.
152 * \param phys_screen Physical screen number.
154 void
155 wibox_init(wibox_t *w, int phys_screen)
157 xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
159 w->window = xcb_generate_id(globalconf.connection);
160 xcb_create_window(globalconf.connection, s->root_depth, w->window, s->root,
161 w->geometry.x, w->geometry.y,
162 w->geometry.width, w->geometry.height,
163 w->border.width, XCB_COPY_FROM_PARENT, s->root_visual,
164 XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL
165 | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK,
166 (const uint32_t [])
168 XCB_BACK_PIXMAP_PARENT_RELATIVE,
169 w->border.color.pixel,
171 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT
172 | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_ENTER_WINDOW
173 | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_STRUCTURE_NOTIFY
174 | XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE
175 | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_EXPOSURE
176 | XCB_EVENT_MASK_PROPERTY_CHANGE
179 /* Create a pixmap. */
180 w->pixmap = xcb_generate_id(globalconf.connection);
181 xcb_create_pixmap(globalconf.connection, s->root_depth, w->pixmap, s->root,
182 w->geometry.width, w->geometry.height);
184 /* Update draw context physical screen, important for Zaphod. */
185 w->ctx.phys_screen = phys_screen;
186 wibox_draw_context_update(w, s);
188 /* The default GC is just a newly created associated to the root window */
189 w->gc = xcb_generate_id(globalconf.connection);
190 xcb_create_gc(globalconf.connection, w->gc, s->root, XCB_GC_FOREGROUND | XCB_GC_BACKGROUND,
191 (const uint32_t[]) { s->black_pixel, s->white_pixel });
193 wibox_shape_update(w);
196 /** Refresh the window content by copying its pixmap data to its window.
197 * \param w The wibox to refresh.
199 static inline void
200 wibox_refresh_pixmap(wibox_t *w)
202 wibox_refresh_pixmap_partial(w, 0, 0, w->geometry.width, w->geometry.height);
205 /** Set a wibox opacity.
206 * \param w The wibox the adjust the opacity of.
207 * \param opacity A value between 0 and 1 which describes the opacity.
209 static inline void
210 wibox_opacity_set(wibox_t *w, double opacity)
212 w->opacity = opacity;
213 if(w->window != XCB_NONE)
214 window_opacity_set(w->window, opacity);
217 void
218 wibox_moveresize(wibox_t *w, area_t geometry)
220 if(w->window)
222 int number_of_vals = 0;
223 uint32_t moveresize_win_vals[4], mask_vals = 0;
225 if(w->geometry.x != geometry.x)
227 w->geometry.x = moveresize_win_vals[number_of_vals++] = geometry.x;
228 mask_vals |= XCB_CONFIG_WINDOW_X;
231 if(w->geometry.y != geometry.y)
233 w->geometry.y = moveresize_win_vals[number_of_vals++] = geometry.y;
234 mask_vals |= XCB_CONFIG_WINDOW_Y;
237 if(geometry.width > 0 && w->geometry.width != geometry.width)
239 w->geometry.width = moveresize_win_vals[number_of_vals++] = geometry.width;
240 mask_vals |= XCB_CONFIG_WINDOW_WIDTH;
243 if(geometry.height > 0 && w->geometry.height != geometry.height)
245 w->geometry.height = moveresize_win_vals[number_of_vals++] = geometry.height;
246 mask_vals |= XCB_CONFIG_WINDOW_HEIGHT;
249 if(mask_vals & (XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT))
251 xcb_free_pixmap(globalconf.connection, w->pixmap);
252 /* orientation != East */
253 if(w->pixmap != w->ctx.pixmap)
254 xcb_free_pixmap(globalconf.connection, w->ctx.pixmap);
255 w->pixmap = xcb_generate_id(globalconf.connection);
256 xcb_screen_t *s = xutil_screen_get(globalconf.connection, w->ctx.phys_screen);
257 xcb_create_pixmap(globalconf.connection, s->root_depth, w->pixmap, s->root,
258 w->geometry.width, w->geometry.height);
259 wibox_draw_context_update(w, s);
262 if(mask_vals)
263 xcb_configure_window(globalconf.connection, w->window, mask_vals, moveresize_win_vals);
265 else
266 w->geometry = geometry;
268 wibox_need_update(w);
271 /** Refresh the window content by copying its pixmap data to its window.
272 * \param wibox The wibox to refresh.
273 * \param x The copy starting point x component.
274 * \param y The copy starting point y component.
275 * \param w The copy width from the x component.
276 * \param h The copy height from the y component.
278 void
279 wibox_refresh_pixmap_partial(wibox_t *wibox,
280 int16_t x, int16_t y,
281 uint16_t w, uint16_t h)
283 xcb_copy_area(globalconf.connection, wibox->pixmap,
284 wibox->window, wibox->gc, x, y, x, y,
285 w, h);
288 /** Set a wibox border width.
289 * \param w The wibox to change border width.
290 * \param border_width The border width in pixel.
292 void
293 wibox_border_width_set(wibox_t *w, uint32_t border_width)
295 xcb_configure_window(globalconf.connection, w->window, XCB_CONFIG_WINDOW_BORDER_WIDTH,
296 &border_width);
297 w->border.width = border_width;
300 /** Set a wibox border color.
301 * \param w The wibox to change border width.
302 * \param color The border color.
304 void
305 wibox_border_color_set(wibox_t *w, const xcolor_t *color)
307 xcb_change_window_attributes(globalconf.connection, w->window,
308 XCB_CW_BORDER_PIXEL, &color->pixel);
309 w->border.color = *color;
312 /** Set wibox orientation.
313 * \param w The wibox.
314 * \param o The new orientation.
316 void
317 wibox_orientation_set(wibox_t *w, orientation_t o)
319 if(o != w->orientation)
321 xcb_screen_t *s = xutil_screen_get(globalconf.connection, w->ctx.phys_screen);
322 w->orientation = o;
323 /* orientation != East */
324 if(w->pixmap != w->ctx.pixmap)
325 xcb_free_pixmap(globalconf.connection, w->ctx.pixmap);
326 wibox_draw_context_update(w, s);
330 /** Set wibox cursor.
331 * \param w The wibox.
332 * \param c The cursor.
334 static void
335 wibox_cursor_set(wibox_t *w, xcb_cursor_t c)
337 if(w->window)
338 xcb_change_window_attributes(globalconf.connection, w->window, XCB_CW_CURSOR,
339 (const uint32_t[]) { c });
342 static void
343 wibox_map(wibox_t *wibox)
345 xcb_map_window(globalconf.connection, wibox->window);
346 /* We must make sure the wibox does not display garbage */
347 wibox_need_update(wibox);
348 /* Stack this wibox correctly */
349 client_stack();
352 static void
353 wibox_move(wibox_t *wibox, int16_t x, int16_t y)
355 if(wibox->window
356 && (x != wibox->geometry.x || y != wibox->geometry.y))
358 xcb_configure_window(globalconf.connection, wibox->window,
359 XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y,
360 (const uint32_t[]) { x, y });
362 wibox->screen = screen_getbycoord(wibox->screen, x, y);
365 wibox->geometry.x = x;
366 wibox->geometry.y = y;
369 static void
370 wibox_resize(wibox_t *w, uint16_t width, uint16_t height)
372 if(width <= 0 || height <= 0 || (w->geometry.width == width && w->geometry.height == height))
373 return;
375 w->geometry.width = width;
376 w->geometry.height = height;
378 if(w->window)
380 xcb_screen_t *s = xutil_screen_get(globalconf.connection, w->ctx.phys_screen);
382 xcb_free_pixmap(globalconf.connection, w->pixmap);
383 /* orientation != East */
384 if(w->pixmap != w->ctx.pixmap)
385 xcb_free_pixmap(globalconf.connection, w->ctx.pixmap);
386 w->pixmap = xcb_generate_id(globalconf.connection);
387 xcb_create_pixmap(globalconf.connection, s->root_depth, w->pixmap, s->root,
388 w->geometry.width, w->geometry.height);
389 xcb_configure_window(globalconf.connection, w->window,
390 XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT,
391 (const uint32_t[]) { w->geometry.width, w->geometry.height });
392 wibox_draw_context_update(w, s);
395 wibox_need_update(w);
398 /** Kick out systray windows.
399 * \param phys_screen Physical screen number.
401 static void
402 wibox_systray_kickout(int phys_screen)
404 xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
406 if(globalconf.screens.tab[phys_screen].systray.parent != s->root)
408 /* Who! Check that we're not deleting a wibox with a systray, because it
409 * may be its parent. If so, we reparent to root before, otherwise it will
410 * hurt very much. */
411 xcb_reparent_window(globalconf.connection,
412 globalconf.screens.tab[phys_screen].systray.window,
413 s->root, -512, -512);
415 globalconf.screens.tab[phys_screen].systray.parent = s->root;
419 static void
420 wibox_systray_refresh(wibox_t *wibox)
422 if(!wibox->screen)
423 return;
425 for(int i = 0; i < wibox->widgets.len; i++)
427 widget_node_t *systray = &wibox->widgets.tab[i];
428 if(systray->widget->type == widget_systray)
430 uint32_t config_back[] = { wibox->ctx.bg.pixel };
431 uint32_t config_win_vals[4];
432 uint32_t config_win_vals_off[2] = { -512, -512 };
433 xembed_window_t *em;
434 int phys_screen = wibox->ctx.phys_screen;
436 if(wibox->isvisible
437 && systray->widget->isvisible
438 && systray->geometry.width)
440 /* Set background of the systray window. */
441 xcb_change_window_attributes(globalconf.connection,
442 globalconf.screens.tab[phys_screen].systray.window,
443 XCB_CW_BACK_PIXEL, config_back);
444 /* Map it. */
445 xcb_map_window(globalconf.connection, globalconf.screens.tab[phys_screen].systray.window);
446 /* Move it. */
447 switch(wibox->orientation)
449 case North:
450 config_win_vals[0] = systray->geometry.y;
451 config_win_vals[1] = wibox->geometry.height - systray->geometry.x - systray->geometry.width;
452 config_win_vals[2] = systray->geometry.height;
453 config_win_vals[3] = systray->geometry.width;
454 break;
455 case South:
456 config_win_vals[0] = systray->geometry.y;
457 config_win_vals[1] = systray->geometry.x;
458 config_win_vals[2] = systray->geometry.height;
459 config_win_vals[3] = systray->geometry.width;
460 break;
461 case East:
462 config_win_vals[0] = systray->geometry.x;
463 config_win_vals[1] = systray->geometry.y;
464 config_win_vals[2] = systray->geometry.width;
465 config_win_vals[3] = systray->geometry.height;
466 break;
468 /* reparent */
469 if(globalconf.screens.tab[phys_screen].systray.parent != wibox->window)
471 xcb_reparent_window(globalconf.connection,
472 globalconf.screens.tab[phys_screen].systray.window,
473 wibox->window,
474 config_win_vals[0], config_win_vals[1]);
475 globalconf.screens.tab[phys_screen].systray.parent = wibox->window;
477 xcb_configure_window(globalconf.connection,
478 globalconf.screens.tab[phys_screen].systray.window,
479 XCB_CONFIG_WINDOW_X
480 | XCB_CONFIG_WINDOW_Y
481 | XCB_CONFIG_WINDOW_WIDTH
482 | XCB_CONFIG_WINDOW_HEIGHT,
483 config_win_vals);
484 /* width = height = systray height */
485 config_win_vals[2] = config_win_vals[3] = systray->geometry.height;
486 config_win_vals[0] = 0;
488 else
489 return wibox_systray_kickout(phys_screen);
491 switch(wibox->orientation)
493 case North:
494 config_win_vals[1] = systray->geometry.width - config_win_vals[3];
495 for(int j = 0; j < globalconf.embedded.len; j++)
497 em = &globalconf.embedded.tab[j];
498 if(em->phys_screen == phys_screen)
500 if(config_win_vals[1] - config_win_vals[2] >= (uint32_t) wibox->geometry.y)
502 xcb_map_window(globalconf.connection, em->win);
503 xcb_configure_window(globalconf.connection, em->win,
504 XCB_CONFIG_WINDOW_X
505 | XCB_CONFIG_WINDOW_Y
506 | XCB_CONFIG_WINDOW_WIDTH
507 | XCB_CONFIG_WINDOW_HEIGHT,
508 config_win_vals);
509 config_win_vals[1] -= config_win_vals[3];
511 else
512 xcb_configure_window(globalconf.connection, em->win,
513 XCB_CONFIG_WINDOW_X
514 | XCB_CONFIG_WINDOW_Y,
515 config_win_vals_off);
518 break;
519 case South:
520 config_win_vals[1] = 0;
521 for(int j = 0; j < globalconf.embedded.len; j++)
523 em = &globalconf.embedded.tab[j];
524 if(em->phys_screen == phys_screen)
526 /* if(y + width <= wibox.y + systray.right) */
527 if(config_win_vals[1] + config_win_vals[3] <= (uint32_t) wibox->geometry.y + AREA_RIGHT(systray->geometry))
529 xcb_map_window(globalconf.connection, em->win);
530 xcb_configure_window(globalconf.connection, em->win,
531 XCB_CONFIG_WINDOW_X
532 | XCB_CONFIG_WINDOW_Y
533 | XCB_CONFIG_WINDOW_WIDTH
534 | XCB_CONFIG_WINDOW_HEIGHT,
535 config_win_vals);
536 config_win_vals[1] += config_win_vals[3];
538 else
539 xcb_configure_window(globalconf.connection, em->win,
540 XCB_CONFIG_WINDOW_X
541 | XCB_CONFIG_WINDOW_Y,
542 config_win_vals_off);
545 break;
546 case East:
547 config_win_vals[1] = 0;
548 for(int j = 0; j < globalconf.embedded.len; j++)
550 em = &globalconf.embedded.tab[j];
551 if(em->phys_screen == phys_screen)
553 /* if(x + width < systray.x + systray.width) */
554 if(config_win_vals[0] + config_win_vals[2] <= (uint32_t) AREA_RIGHT(systray->geometry) + wibox->geometry.x)
556 xcb_map_window(globalconf.connection, em->win);
557 xcb_configure_window(globalconf.connection, em->win,
558 XCB_CONFIG_WINDOW_X
559 | XCB_CONFIG_WINDOW_Y
560 | XCB_CONFIG_WINDOW_WIDTH
561 | XCB_CONFIG_WINDOW_HEIGHT,
562 config_win_vals);
563 config_win_vals[0] += config_win_vals[2];
565 else
566 xcb_configure_window(globalconf.connection, em->win,
567 XCB_CONFIG_WINDOW_X
568 | XCB_CONFIG_WINDOW_Y,
569 config_win_vals_off);
572 break;
574 break;
579 /** Get a wibox by its window.
580 * \param win The window id.
581 * \return A wibox if found, NULL otherwise.
583 wibox_t *
584 wibox_getbywin(xcb_window_t win)
586 foreach(w, globalconf.wiboxes)
587 if((*w)->window == win)
588 return *w;
590 foreach(_c, globalconf.clients)
592 client_t *c = *_c;
593 if(c->titlebar && c->titlebar->window == win)
594 return c->titlebar;
597 return NULL;
600 /** Draw a wibox.
601 * \param wibox The wibox to draw.
603 static void
604 wibox_draw(wibox_t *wibox)
606 if(wibox->isvisible)
608 widget_render(wibox);
609 wibox_refresh_pixmap(wibox);
611 wibox->need_update = false;
614 wibox_systray_refresh(wibox);
617 /** Refresh all wiboxes.
619 void
620 wibox_refresh(void)
622 foreach(w, globalconf.wiboxes)
624 if((*w)->need_shape_update)
625 wibox_shape_update(*w);
626 if((*w)->need_update)
627 wibox_draw(*w);
630 foreach(_c, globalconf.clients)
632 client_t *c = *_c;
633 if(c->titlebar && c->titlebar->need_update)
634 wibox_draw(c->titlebar);
638 /** Set a wibox visible or not.
639 * \param wibox The wibox.
640 * \param v The visible value.
642 static void
643 wibox_setvisible(wibox_t *wibox, bool v)
645 if(v != wibox->isvisible)
647 wibox->isvisible = v;
648 wibox->mouse_over = NULL;
650 if(wibox->screen)
652 if(wibox->isvisible)
653 wibox_map(wibox);
654 else
655 xcb_unmap_window(globalconf.connection, wibox->window);
657 /* kick out systray if needed */
658 wibox_systray_refresh(wibox);
661 hook_property(wibox, wibox, "visible");
665 /** Destroy all X resources of a wibox.
666 * \param w The wibox to wipe.
668 void
669 wibox_wipe(wibox_t *w)
671 if(w->window)
673 xcb_destroy_window(globalconf.connection, w->window);
674 w->window = XCB_NONE;
676 if(w->pixmap)
678 xcb_free_pixmap(globalconf.connection, w->pixmap);
679 w->pixmap = XCB_NONE;
681 if(w->gc)
683 xcb_free_gc(globalconf.connection, w->gc);
684 w->gc = XCB_NONE;
686 draw_context_wipe(&w->ctx);
689 /** Remove a wibox from a screen.
690 * \param wibox Wibox to detach from screen.
692 static void
693 wibox_detach(wibox_t *wibox)
695 if(wibox->screen)
697 bool v;
699 /* save visible state */
700 v = wibox->isvisible;
701 wibox->isvisible = false;
702 wibox_systray_refresh(wibox);
703 /* restore visibility */
704 wibox->isvisible = v;
706 wibox->mouse_over = NULL;
708 wibox_wipe(wibox);
710 foreach(item, globalconf.wiboxes)
711 if(*item == wibox)
713 wibox_array_remove(&globalconf.wiboxes, item);
714 break;
717 hook_property(wibox, wibox, "screen");
719 wibox->screen = NULL;
721 wibox_unref(globalconf.L, wibox);
725 /** Attach a wibox that is on top of the stack.
726 * \param s The screen to attach the wibox to.
728 static void
729 wibox_attach(screen_t *s)
731 int phys_screen = screen_virttophys(screen_array_indexof(&globalconf.screens, s));
733 wibox_t *wibox = wibox_ref(globalconf.L, -1);
735 wibox_detach(wibox);
737 /* Set the wibox screen */
738 wibox->screen = s;
740 /* Check that the wibox coordinates matches the screen. */
741 screen_t *cscreen =
742 screen_getbycoord(wibox->screen, wibox->geometry.x, wibox->geometry.y);
744 /* If it does not match, move it to the screen coordinates */
745 if(cscreen != wibox->screen)
746 wibox_move(wibox, s->geometry.x, s->geometry.y);
748 wibox_array_append(&globalconf.wiboxes, wibox);
750 wibox_init(wibox, phys_screen);
752 wibox_cursor_set(wibox,
753 xcursor_new(globalconf.connection, xcursor_font_fromstr(wibox->cursor)));
755 wibox_opacity_set(wibox, wibox->opacity);
757 if(wibox->isvisible)
758 wibox_map(wibox);
759 else
760 wibox_need_update(wibox);
762 hook_property(wibox, wibox, "screen");
765 /** Create a new wibox.
766 * \param L The Lua VM state.
768 * \luastack
769 * \lparam A table with optionaly defined values:
770 * fg, bg, border_width, border_color, ontop, width and height.
771 * \lreturn A brand new wibox.
773 static int
774 luaA_wibox_new(lua_State *L)
776 wibox_t *w;
777 const char *buf;
778 size_t len;
779 xcolor_init_request_t reqs[3];
780 int i, reqs_nbr = -1;
782 luaA_checktable(L, 2);
784 w = wibox_new(L);
786 w->ctx.fg = globalconf.colors.fg;
787 if((buf = luaA_getopt_lstring(L, 2, "fg", NULL, &len)))
788 reqs[++reqs_nbr] = xcolor_init_unchecked(&w->ctx.fg, buf, len);
790 w->ctx.bg = globalconf.colors.bg;
791 if((buf = luaA_getopt_lstring(L, 2, "bg", NULL, &len)))
792 reqs[++reqs_nbr] = xcolor_init_unchecked(&w->ctx.bg, buf, len);
794 w->border.color = globalconf.colors.bg;
795 if((buf = luaA_getopt_lstring(L, 2, "border_color", NULL, &len)))
796 reqs[++reqs_nbr] = xcolor_init_unchecked(&w->border.color, buf, len);
798 w->ontop = luaA_getopt_boolean(L, 2, "ontop", false);
800 w->opacity = -1;
801 w->border.width = luaA_getopt_number(L, 2, "border_width", 0);
802 w->geometry.x = luaA_getopt_number(L, 2, "x", 0);
803 w->geometry.y = luaA_getopt_number(L, 2, "y", 0);
804 w->geometry.width = luaA_getopt_number(L, 2, "width", 100);
805 w->geometry.height = luaA_getopt_number(L, 2, "height", globalconf.font->height * 1.5);
807 w->isvisible = true;
808 w->cursor = a_strdup("left_ptr");
810 for(i = 0; i <= reqs_nbr; i++)
811 xcolor_init_reply(reqs[i]);
813 return 1;
816 /** Check if a wibox widget table has an item.
817 * \param L The Lua VM state.
818 * \param wibox The wibox.
819 * \param item The item to look for.
821 static bool
822 luaA_wibox_hasitem(lua_State *L, wibox_t *wibox, const void *item)
824 if(wibox->widgets_table)
826 wibox_push(L, wibox);
827 luaA_object_push_item(L, -1, wibox->widgets_table);
828 lua_remove(L, -2);
829 if(lua_topointer(L, -1) == item || luaA_hasitem(L, item))
830 return true;
832 return false;
835 /** Invalidate a wibox by a Lua object (table, etc).
836 * \param L The Lua VM state.
837 * \param item The object identifier.
839 void
840 luaA_wibox_invalidate_byitem(lua_State *L, const void *item)
842 foreach(w, globalconf.wiboxes)
844 wibox_t *wibox = *w;
845 if(luaA_wibox_hasitem(L, wibox, item))
847 /* update wibox */
848 wibox_need_update(wibox);
849 lua_pop(L, 1); /* remove widgets table */
854 foreach(_c, globalconf.clients)
856 client_t *c = *_c;
857 if(c->titlebar && luaA_wibox_hasitem(L, c->titlebar, item))
859 /* update wibox */
860 wibox_need_update(c->titlebar);
861 lua_pop(L, 1); /* remove widgets table */
866 /** Wibox object.
867 * \param L The Lua VM state.
868 * \return The number of elements pushed on stack.
869 * \luastack
870 * \lfield screen Screen number.
871 * \lfield client The client attached to (titlebar).
872 * \lfield border_width Border width.
873 * \lfield border_color Border color.
874 * \lfield align The alignment (titlebar).
875 * \lfield fg Foreground color.
876 * \lfield bg Background color.
877 * \lfield bg_image Background image.
878 * \lfield position The position (titlebar).
879 * \lfield ontop On top of other windows.
880 * \lfield cursor The mouse cursor.
881 * \lfield visible Visibility.
882 * \lfield orientation The drawing orientation: east, north or south.
883 * \lfield widgets An array with all widgets drawn on this wibox.
884 * \lfield opacity The opacity of the wibox, between 0 and 1.
885 * \lfield mouse_enter A function to execute when the mouse enter the widget.
886 * \lfield mouse_leave A function to execute when the mouse leave the widget.
887 * \lfield shape_clip Image describing the window's content shape.
888 * \lfield shape_bounding Image describing the window's border shape.
890 static int
891 luaA_wibox_index(lua_State *L)
893 size_t len;
894 wibox_t *wibox = luaL_checkudata(L, 1, "wibox");
895 const char *attr = luaL_checklstring(L, 2, &len);
897 if(luaA_usemetatable(L, 1, 2))
898 return 1;
900 switch(a_tokenize(attr, len))
902 case A_TK_VISIBLE:
903 lua_pushboolean(L, wibox->isvisible);
904 break;
905 case A_TK_CLIENT:
906 return client_push(L, client_getbytitlebar(wibox));
907 case A_TK_SCREEN:
908 if(!wibox->screen)
909 return 0;
910 lua_pushnumber(L, screen_array_indexof(&globalconf.screens, wibox->screen) + 1);
911 break;
912 case A_TK_BORDER_WIDTH:
913 lua_pushnumber(L, wibox->border.width);
914 break;
915 case A_TK_BORDER_COLOR:
916 luaA_pushxcolor(L, &wibox->border.color);
917 break;
918 case A_TK_ALIGN:
919 if(wibox->type == WIBOX_TYPE_NORMAL)
920 luaA_deprecate(L, "awful.wibox.align");
921 lua_pushstring(L, draw_align_tostr(wibox->align));
922 break;
923 case A_TK_FG:
924 luaA_pushxcolor(L, &wibox->ctx.fg);
925 break;
926 case A_TK_BG:
927 luaA_pushxcolor(L, &wibox->ctx.bg);
928 break;
929 case A_TK_BG_IMAGE:
930 luaA_object_push_item(L, 1, wibox->bg_image);
931 break;
932 case A_TK_POSITION:
933 if(wibox->type == WIBOX_TYPE_NORMAL)
934 luaA_deprecate(L, "awful.wibox.attach");
935 lua_pushstring(L, position_tostr(wibox->position));
936 break;
937 case A_TK_ONTOP:
938 lua_pushboolean(L, wibox->ontop);
939 break;
940 case A_TK_ORIENTATION:
941 lua_pushstring(L, orientation_tostr(wibox->orientation));
942 break;
943 case A_TK_WIDGETS:
944 return luaA_object_push_item(L, 1, wibox->widgets_table);
945 case A_TK_CURSOR:
946 lua_pushstring(L, wibox->cursor);
947 break;
948 case A_TK_OPACITY:
949 if (wibox->opacity >= 0)
950 lua_pushnumber(L, wibox->opacity);
951 else
952 return 0;
953 break;
954 case A_TK_MOUSE_ENTER:
955 return luaA_object_push_item(L, 1, wibox->mouse_enter);
956 case A_TK_MOUSE_LEAVE:
957 return luaA_object_push_item(L, 1, wibox->mouse_leave);
958 case A_TK_SHAPE_BOUNDING:
959 return luaA_object_push_item(L, 1, wibox->shape.bounding);
960 case A_TK_SHAPE_CLIP:
961 return luaA_object_push_item(L, 1, wibox->shape.clip);
962 case A_TK_BUTTONS:
963 return luaA_object_push_item(L, 1, wibox->buttons);
964 default:
965 return 0;
968 return 1;
971 /* Set or get the wibox geometry.
972 * \param L The Lua VM state.
973 * \return The number of elements pushed on stack.
974 * \luastack
975 * \lparam An optional table with wibox geometry.
976 * \lreturn The wibox geometry.
978 static int
979 luaA_wibox_geometry(lua_State *L)
981 wibox_t *wibox = luaL_checkudata(L, 1, "wibox");
983 if(lua_gettop(L) == 2)
985 area_t wingeom;
987 luaA_checktable(L, 2);
988 wingeom.x = luaA_getopt_number(L, 2, "x", wibox->geometry.x);
989 wingeom.y = luaA_getopt_number(L, 2, "y", wibox->geometry.y);
990 wingeom.width = luaA_getopt_number(L, 2, "width", wibox->geometry.width);
991 wingeom.height = luaA_getopt_number(L, 2, "height", wibox->geometry.height);
993 switch(wibox->type)
995 case WIBOX_TYPE_TITLEBAR:
996 wibox_resize(wibox, wingeom.width, wingeom.height);
997 break;
998 case WIBOX_TYPE_NORMAL:
999 wibox_moveresize(wibox, wingeom);
1000 break;
1004 return luaA_pusharea(L, wibox->geometry);
1007 /** Wibox newindex.
1008 * \param L The Lua VM state.
1009 * \return The number of elements pushed on stack.
1011 static int
1012 luaA_wibox_newindex(lua_State *L)
1014 size_t len;
1015 wibox_t *wibox = luaL_checkudata(L, 1, "wibox");
1016 const char *buf, *attr = luaL_checklstring(L, 2, &len);
1017 awesome_token_t tok;
1019 switch((tok = a_tokenize(attr, len)))
1021 bool b;
1023 case A_TK_FG:
1024 if((buf = luaL_checklstring(L, 3, &len)))
1025 if(xcolor_init_reply(xcolor_init_unchecked(&wibox->ctx.fg, buf, len)))
1026 wibox->need_update = true;
1027 break;
1028 case A_TK_BG:
1029 if((buf = luaL_checklstring(L, 3, &len)))
1030 if(xcolor_init_reply(xcolor_init_unchecked(&wibox->ctx.bg, buf, len)))
1031 wibox->need_update = true;
1032 break;
1033 case A_TK_BG_IMAGE:
1034 luaA_object_unref_item(L, 1, wibox->bg_image);
1035 wibox->bg_image = luaA_object_ref_item(L, 1, 3);
1036 wibox->need_update = true;
1037 break;
1038 case A_TK_ALIGN:
1039 buf = luaL_checklstring(L, 3, &len);
1040 wibox->align = draw_align_fromstr(buf, len);
1041 switch(wibox->type)
1043 case WIBOX_TYPE_NORMAL:
1044 luaA_deprecate(L, "awful.wibox.align");
1045 break;
1046 case WIBOX_TYPE_TITLEBAR:
1047 titlebar_update_geometry(client_getbytitlebar(wibox));
1048 break;
1050 break;
1051 case A_TK_POSITION:
1052 switch(wibox->type)
1054 case WIBOX_TYPE_NORMAL:
1055 if((buf = luaL_checklstring(L, 3, &len)))
1057 luaA_deprecate(L, "awful.wibox.attach");
1058 wibox->position = position_fromstr(buf, len);
1060 break;
1061 case WIBOX_TYPE_TITLEBAR:
1062 return luaA_titlebar_newindex(L, wibox, tok);
1064 break;
1065 case A_TK_CLIENT:
1066 /* first detach */
1067 if(lua_isnil(L, 3))
1068 titlebar_client_detach(client_getbytitlebar(wibox));
1069 else
1071 client_t *c = luaA_client_checkudata(L, -1);
1072 lua_pushvalue(L, 1);
1073 titlebar_client_attach(c);
1075 break;
1076 case A_TK_CURSOR:
1077 if((buf = luaL_checkstring(L, 3)))
1079 uint16_t cursor_font = xcursor_font_fromstr(buf);
1080 if(cursor_font)
1082 xcb_cursor_t cursor = xcursor_new(globalconf.connection, cursor_font);
1083 p_delete(&wibox->cursor);
1084 wibox->cursor = a_strdup(buf);
1085 wibox_cursor_set(wibox, cursor);
1088 break;
1089 case A_TK_SCREEN:
1090 if(lua_isnil(L, 3))
1092 wibox_detach(wibox);
1093 titlebar_client_detach(client_getbytitlebar(wibox));
1095 else
1097 int screen = luaL_checknumber(L, 3) - 1;
1098 luaA_checkscreen(screen);
1099 if(!wibox->screen || screen != screen_array_indexof(&globalconf.screens, wibox->screen))
1101 titlebar_client_detach(client_getbytitlebar(wibox));
1102 lua_pushvalue(L, 1);
1103 wibox_attach(&globalconf.screens.tab[screen]);
1106 break;
1107 case A_TK_ONTOP:
1108 b = luaA_checkboolean(L, 3);
1109 if(b != wibox->ontop)
1111 wibox->ontop = b;
1112 client_stack();
1114 break;
1115 case A_TK_ORIENTATION:
1116 if((buf = luaL_checklstring(L, 3, &len)))
1118 wibox_orientation_set(wibox, orientation_fromstr(buf, len));
1119 wibox_need_update(wibox);
1121 break;
1122 case A_TK_BORDER_COLOR:
1123 if((buf = luaL_checklstring(L, 3, &len)))
1124 if(xcolor_init_reply(xcolor_init_unchecked(&wibox->border.color, buf, len)))
1125 if(wibox->window)
1126 wibox_border_color_set(wibox, &wibox->border.color);
1127 break;
1128 case A_TK_VISIBLE:
1129 b = luaA_checkboolean(L, 3);
1130 if(b != wibox->isvisible)
1131 switch(wibox->type)
1133 case WIBOX_TYPE_NORMAL:
1134 wibox_setvisible(wibox, b);
1135 break;
1136 case WIBOX_TYPE_TITLEBAR:
1137 titlebar_set_visible(wibox, b);
1138 break;
1140 break;
1141 case A_TK_WIDGETS:
1142 if(luaA_isloop(L, 3))
1144 luaA_warn(L, "table is looping, cannot use this as widget table");
1145 return 0;
1147 /* duplicate table because next function will eat it */
1148 lua_pushvalue(L, 3);
1149 /* register object */
1150 wibox->widgets_table = luaA_object_ref_item(L, 1, -1);
1151 wibox_need_update(wibox);
1152 luaA_table2wtable(L);
1153 break;
1154 case A_TK_OPACITY:
1155 if(lua_isnil(L, 3))
1156 wibox_opacity_set(wibox, -1);
1157 else
1159 double d = luaL_checknumber(L, 3);
1160 if(d >= 0 && d <= 1)
1161 wibox_opacity_set(wibox, d);
1163 break;
1164 case A_TK_MOUSE_ENTER:
1165 luaA_checkfunction(L, 3);
1166 luaA_object_unref_item(L, 1, wibox->mouse_enter);
1167 wibox->mouse_enter = luaA_object_ref_item(L, 1, 3);
1168 return 0;
1169 case A_TK_MOUSE_LEAVE:
1170 luaA_checkfunction(L, 3);
1171 luaA_object_unref_item(L, 1, wibox->mouse_leave);
1172 wibox->mouse_leave = luaA_object_ref_item(L, 1, 3);
1173 return 0;
1174 case A_TK_SHAPE_BOUNDING:
1175 luaA_object_unref_item(L, 1, wibox->shape.bounding);
1176 wibox->shape.bounding = luaA_object_ref_item(L, 1, 3);
1177 wibox->need_shape_update = true;
1178 break;
1179 case A_TK_SHAPE_CLIP:
1180 luaA_object_unref_item(L, 1, wibox->shape.clip);
1181 wibox->shape.clip = luaA_object_ref_item(L, 1, 3);
1182 wibox->need_shape_update = true;
1183 case A_TK_BUTTONS:
1184 luaA_object_unref_item(L, 1, wibox->buttons);
1185 wibox->buttons = luaA_object_ref_item(L, 1, 3);
1186 break;
1187 default:
1188 switch(wibox->type)
1190 case WIBOX_TYPE_TITLEBAR:
1191 return luaA_titlebar_newindex(L, wibox, tok);
1192 case WIBOX_TYPE_NORMAL:
1193 break;
1197 return 0;
1200 const struct luaL_reg awesome_wibox_methods[] =
1202 LUA_CLASS_METHODS(wibox)
1203 { "__call", luaA_wibox_new },
1204 { NULL, NULL }
1206 const struct luaL_reg awesome_wibox_meta[] =
1208 LUA_OBJECT_META(wibox)
1209 { "geometry", luaA_wibox_geometry },
1210 { "__index", luaA_wibox_index },
1211 { "__newindex", luaA_wibox_newindex },
1212 { "__gc", luaA_wibox_gc },
1213 { NULL, NULL },
1216 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80