2 * statusbar.c - statusbar functions
4 * Copyright © 2007-2008 Julien Danjou <julien@danjou.info>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 #include "statusbar.h"
30 extern awesome_t globalconf
;
32 DO_LUA_NEW(extern, statusbar_t
, statusbar
, "statusbar", statusbar_ref
)
33 DO_LUA_GC(statusbar_t
, statusbar
, "statusbar", statusbar_unref
)
34 DO_LUA_EQ(statusbar_t
, statusbar
, "statusbar")
36 /** Kick out systray windows.
37 * \param phys_screen Physical screen number.
40 statusbar_systray_kickout(int phys_screen
)
43 uint32_t config_win_vals_off
[2] = { -512, -512 };
45 for(em
= globalconf
.embedded
; em
; em
= em
->next
)
46 if(em
->phys_screen
== phys_screen
)
47 xcb_configure_window(globalconf
.connection
, em
->win
,
49 | XCB_CONFIG_WINDOW_Y
,
54 statusbar_systray_refresh(statusbar_t
*statusbar
)
56 widget_node_t
*systray
;
58 if(statusbar
->screen
== SCREEN_UNDEF
)
61 for(systray
= statusbar
->widgets
; systray
; systray
= systray
->next
)
62 if(systray
->widget
->type
== systray_new
)
64 uint32_t config_win_vals
[4];
65 uint32_t config_win_vals_off
[2] = { -512, -512 };
69 if(statusbar
->position
70 && systray
->widget
->isvisible
)
72 pos
= statusbar
->position
;
74 config_win_vals
[2] = systray
->area
.height
;
76 config_win_vals
[3] = systray
->area
.height
;
85 config_win_vals
[0] = statusbar
->sw
->geometry
.x
+ systray
->area
.y
;
86 config_win_vals
[1] = statusbar
->sw
->geometry
.y
+ statusbar
->sw
->geometry
.height
87 - systray
->area
.x
- config_win_vals
[3];
88 for(em
= globalconf
.embedded
; em
; em
= em
->next
)
89 if(em
->phys_screen
== statusbar
->phys_screen
)
91 if(config_win_vals
[1] - config_win_vals
[2] >= (uint32_t) statusbar
->sw
->geometry
.y
)
93 xcb_map_window(globalconf
.connection
, em
->win
);
94 xcb_configure_window(globalconf
.connection
, em
->win
,
97 | XCB_CONFIG_WINDOW_WIDTH
98 | XCB_CONFIG_WINDOW_HEIGHT
,
100 config_win_vals
[1] -= config_win_vals
[3];
103 xcb_configure_window(globalconf
.connection
, em
->win
,
105 | XCB_CONFIG_WINDOW_Y
,
106 config_win_vals_off
);
111 config_win_vals
[0] = statusbar
->sw
->geometry
.x
- systray
->area
.y
;
112 config_win_vals
[1] = statusbar
->sw
->geometry
.y
+ systray
->area
.x
;
113 for(em
= globalconf
.embedded
; em
; em
= em
->next
)
114 if(em
->phys_screen
== statusbar
->phys_screen
)
116 if(config_win_vals
[1] + config_win_vals
[3] <= (uint32_t) statusbar
->sw
->geometry
.y
+ statusbar
->ctx
->width
)
118 xcb_map_window(globalconf
.connection
, em
->win
);
119 xcb_configure_window(globalconf
.connection
, em
->win
,
121 | XCB_CONFIG_WINDOW_Y
122 | XCB_CONFIG_WINDOW_WIDTH
123 | XCB_CONFIG_WINDOW_HEIGHT
,
125 config_win_vals
[1] += config_win_vals
[3];
128 xcb_configure_window(globalconf
.connection
, em
->win
,
130 | XCB_CONFIG_WINDOW_Y
,
131 config_win_vals_off
);
137 config_win_vals
[0] = statusbar
->sw
->geometry
.x
+ systray
->area
.x
;
138 config_win_vals
[1] = statusbar
->sw
->geometry
.y
+ systray
->area
.y
;
139 for(em
= globalconf
.embedded
; em
; em
= em
->next
)
140 if(em
->phys_screen
== statusbar
->phys_screen
)
142 /* if(x + width < systray.x + systray.width) */
143 if(config_win_vals
[0] + config_win_vals
[2] <= (uint32_t) AREA_RIGHT(systray
->area
) + statusbar
->sw
->geometry
.x
)
145 xcb_map_window(globalconf
.connection
, em
->win
);
146 xcb_configure_window(globalconf
.connection
, em
->win
,
148 | XCB_CONFIG_WINDOW_Y
149 | XCB_CONFIG_WINDOW_WIDTH
150 | XCB_CONFIG_WINDOW_HEIGHT
,
152 config_win_vals
[0] += config_win_vals
[2];
155 xcb_configure_window(globalconf
.connection
, em
->win
,
157 | XCB_CONFIG_WINDOW_Y
,
158 config_win_vals_off
);
163 statusbar_systray_kickout(statusbar
->phys_screen
);
170 /** Draw a statusbar.
171 * \param statusbar The statusbar to draw.
174 statusbar_draw(statusbar_t
*statusbar
)
176 statusbar
->need_update
= false;
178 if(statusbar
->position
)
180 widget_render(statusbar
->widgets
, statusbar
->ctx
, statusbar
->sw
->gc
,
181 statusbar
->sw
->pixmap
,
182 statusbar
->screen
, statusbar
->position
,
183 statusbar
->sw
->geometry
.x
, statusbar
->sw
->geometry
.y
,
184 statusbar
, AWESOME_TYPE_STATUSBAR
);
185 simplewindow_refresh_pixmap(statusbar
->sw
);
188 statusbar_systray_refresh(statusbar
);
191 /** Statusbar refresh function.
194 statusbar_refresh(void)
197 statusbar_t
*statusbar
;
199 for(screen
= 0; screen
< globalconf
.screens_info
->nscreen
; screen
++)
200 for(statusbar
= globalconf
.screens
[screen
].statusbar
; statusbar
; statusbar
= statusbar
->next
)
201 if(statusbar
->need_update
)
202 statusbar_draw(statusbar
);
205 /** Update the statusbar position. It deletes every statusbar resources and
207 * \param statusbar The statusbar.
210 statusbar_position_update(statusbar_t
*statusbar
)
215 xcb_screen_t
*s
= NULL
;
218 globalconf
.screens
[statusbar
->screen
].need_arrange
= true;
220 simplewindow_delete(&statusbar
->sw
);
221 draw_context_delete(&statusbar
->ctx
);
223 if(statusbar
->position
== Off
)
226 area
= screen_area_get(statusbar
->screen
,
228 &globalconf
.screens
[statusbar
->screen
].padding
);
230 /* Top and Bottom statusbar_t have prio */
231 for(sb
= globalconf
.screens
[statusbar
->screen
].statusbar
; sb
; sb
= sb
->next
)
233 /* Ignore every statusbar after me that is in the same position */
239 else if(ignore
&& statusbar
->position
== sb
->position
)
244 switch(statusbar
->position
)
247 area
.x
+= statusbar
->height
;
254 switch(statusbar
->position
)
257 area
.x
-= statusbar
->height
;
264 switch(statusbar
->position
)
267 area
.y
+= sb
->height
;
271 area
.height
-= sb
->height
;
272 area
.y
+= sb
->height
;
279 switch(statusbar
->position
)
282 area
.y
-= sb
->height
;
286 area
.height
-= sb
->height
;
297 switch(statusbar
->position
)
301 if(!statusbar
->width_user
)
302 statusbar
->width
= area
.height
;
304 simplewindow_new(globalconf
.connection
, statusbar
->phys_screen
, 0, 0,
305 statusbar
->height
, statusbar
->width
, 0);
306 s
= xutil_screen_get(globalconf
.connection
, statusbar
->phys_screen
);
307 /* we need a new pixmap this way [ ] to render */
308 dw
= xcb_generate_id(globalconf
.connection
);
309 xcb_create_pixmap(globalconf
.connection
,
310 s
->root_depth
, dw
, s
->root
,
311 statusbar
->width
, statusbar
->height
);
312 statusbar
->ctx
= draw_context_new(globalconf
.connection
,
313 statusbar
->phys_screen
,
317 &statusbar
->colors
.fg
,
318 &statusbar
->colors
.bg
);
321 if(!statusbar
->width_user
)
322 statusbar
->width
= area
.width
;
324 simplewindow_new(globalconf
.connection
, statusbar
->phys_screen
, 0, 0,
325 statusbar
->width
, statusbar
->height
, 0);
326 statusbar
->ctx
= draw_context_new(globalconf
.connection
,
327 statusbar
->phys_screen
,
330 statusbar
->sw
->pixmap
,
331 &statusbar
->colors
.fg
,
332 &statusbar
->colors
.bg
);
336 switch(statusbar
->position
)
339 switch(statusbar
->align
)
342 simplewindow_move(statusbar
->sw
, area
.x
, area
.y
);
345 simplewindow_move(statusbar
->sw
,
346 area
.x
+ area
.width
- statusbar
->width
, area
.y
);
349 simplewindow_move(statusbar
->sw
,
350 area
.x
+ (area
.width
- statusbar
->width
) / 2, area
.y
);
355 switch(statusbar
->align
)
358 simplewindow_move(statusbar
->sw
,
359 area
.x
, (area
.y
+ area
.height
) - statusbar
->height
);
362 simplewindow_move(statusbar
->sw
,
363 area
.x
+ area
.width
- statusbar
->width
,
364 (area
.y
+ area
.height
) - statusbar
->height
);
367 simplewindow_move(statusbar
->sw
,
368 area
.x
+ (area
.width
- statusbar
->width
) / 2,
369 (area
.y
+ area
.height
) - statusbar
->height
);
374 switch(statusbar
->align
)
377 simplewindow_move(statusbar
->sw
, area
.x
,
378 (area
.y
+ area
.height
) - statusbar
->sw
->geometry
.height
);
381 simplewindow_move(statusbar
->sw
, area
.x
, area
.y
);
384 simplewindow_move(statusbar
->sw
, area
.x
, (area
.y
+ area
.height
- statusbar
->width
) / 2);
388 switch(statusbar
->align
)
391 simplewindow_move(statusbar
->sw
, area
.x
+ area
.width
- statusbar
->height
, area
.y
);
394 simplewindow_move(statusbar
->sw
, area
.x
+ area
.width
- statusbar
->height
,
395 area
.y
+ area
.height
- statusbar
->width
);
398 simplewindow_move(statusbar
->sw
, area
.x
+ area
.width
- statusbar
->height
,
399 (area
.y
+ area
.height
- statusbar
->width
) / 2);
405 xcb_map_window(globalconf
.connection
, statusbar
->sw
->window
);
407 /* Set need update */
408 statusbar
->need_update
= true;
411 /** Convert a statusbar to a printable string.
412 * \param L The Lua VM state.
415 * \lvalue A statusbar.
418 luaA_statusbar_tostring(lua_State
*L
)
420 statusbar_t
**p
= luaA_checkudata(L
, 1, "statusbar");
421 lua_pushfstring(L
, "[statusbar udata(%p) name(%s)]", *p
, (*p
)->name
);
425 /** Create a new statusbar.
426 * \param L The Lua VM state.
429 * \lparam A table with at least a name attribute. Optionaly defined values are:
430 * position, align, fg, bg, width and height.
431 * \lreturn A brand new statusbar.
434 luaA_statusbar_new(lua_State
*L
)
440 luaA_checktable(L
, 2);
442 if(!(buf
= luaA_getopt_string(L
, 2, "name", NULL
)))
443 luaL_error(L
, "object statusbar must have a name");
445 sb
= p_new(statusbar_t
, 1);
447 sb
->name
= a_strdup(buf
);
449 sb
->colors
.fg
= globalconf
.colors
.fg
;
450 if((buf
= luaA_getopt_lstring(L
, 2, "fg", NULL
, &len
)))
451 xcolor_init(&sb
->colors
.fg
, globalconf
.connection
,
452 globalconf
.default_screen
, buf
, len
);
454 sb
->colors
.bg
= globalconf
.colors
.bg
;
455 if((buf
= luaA_getopt_lstring(L
, 2, "bg", NULL
, &len
)))
456 xcolor_init(&sb
->colors
.bg
, globalconf
.connection
,
457 globalconf
.default_screen
, buf
, len
);
459 buf
= luaA_getopt_lstring(L
, 2, "align", "left", &len
);
460 sb
->align
= draw_align_fromstr(buf
, len
);
462 sb
->width
= luaA_getopt_number(L
, 2, "width", 0);
464 sb
->width_user
= true;
465 sb
->height
= luaA_getopt_number(L
, 2, "height", 0);
467 /* 1.5 as default factor, it fits nice but no one knows why */
468 sb
->height
= 1.5 * globalconf
.font
->height
;
470 buf
= luaA_getopt_lstring(L
, 2, "position", "top", &len
);
471 sb
->position
= position_fromstr(buf
, len
);
473 sb
->screen
= SCREEN_UNDEF
;
475 return luaA_statusbar_userdata_new(L
, sb
);
478 /** Statusbar object.
479 * \param L The Lua VM state.
480 * \return The number of elements pushed on stack.
482 * \lfield screen Screen number.
483 * \lfield align The alignment.
484 * \lfield fg Foreground color.
485 * \lfield bg Background color.
486 * \lfield position The position.
487 * \lfield widget The statusbar widgets.
490 luaA_statusbar_index(lua_State
*L
)
494 widget_node_t
*witer
;
495 statusbar_t
**statusbar
= luaA_checkudata(L
, 1, "statusbar");
496 const char *attr
= luaL_checklstring(L
, 2, &len
);
498 if(luaA_usemetatable(L
, 1, 2))
501 switch(a_tokenize(attr
, len
))
504 if((*statusbar
)->screen
== SCREEN_UNDEF
)
506 lua_pushnumber(L
, (*statusbar
)->screen
+ 1);
509 lua_pushstring(L
, draw_align_tostr((*statusbar
)->align
));
512 luaA_pushcolor(L
, &(*statusbar
)->colors
.fg
);
515 luaA_pushcolor(L
, &(*statusbar
)->colors
.bg
);
518 lua_pushstring(L
, position_tostr((*statusbar
)->position
));
522 for(witer
= (*statusbar
)->widgets
; witer
; witer
= witer
->next
)
524 luaA_widget_userdata_new(L
, witer
->widget
);
525 lua_rawseti(L
, -2, ++i
);
535 /** Remove a statubar from a screen.
536 * \param statusbar Statusbar to detach from screen.
539 statusbar_remove(statusbar_t
*statusbar
)
541 if(statusbar
->screen
!= SCREEN_UNDEF
)
545 statusbar_systray_kickout(statusbar
->phys_screen
);
548 p
= statusbar
->position
;
549 statusbar
->position
= Off
;
550 statusbar_position_update(statusbar
);
551 /* restore position */
552 statusbar
->position
= p
;
554 statusbar_list_detach(&globalconf
.screens
[statusbar
->screen
].statusbar
, statusbar
);
555 globalconf
.screens
[statusbar
->screen
].need_arrange
= true;
556 statusbar
->screen
= SCREEN_UNDEF
;
557 statusbar_unref(&statusbar
);
561 /** Statusbar newindex.
562 * \param L The Lua VM state.
563 * \return The number of elements pushed on stack.
566 luaA_statusbar_newindex(lua_State
*L
)
569 statusbar_t
*s
, **statusbar
= luaA_checkudata(L
, 1, "statusbar");
570 const char *buf
, *attr
= luaL_checklstring(L
, 2, &len
);
573 widget_node_t
*witer
;
575 switch(a_tokenize(attr
, len
))
579 statusbar_remove(*statusbar
);
582 screen
= luaL_checknumber(L
, 3) - 1;
584 luaA_checkscreen(screen
);
586 if((*statusbar
)->screen
== screen
)
587 luaL_error(L
, "this statusbar is already on screen %d",
588 (*statusbar
)->screen
+ 1);
590 /* Check for uniq name and id. */
591 for(s
= globalconf
.screens
[screen
].statusbar
; s
; s
= s
->next
)
592 if(!a_strcmp(s
->name
, (*statusbar
)->name
))
593 luaL_error(L
, "a statusbar with that name is already on screen %d\n",
596 statusbar_remove(*statusbar
);
598 (*statusbar
)->screen
= screen
;
599 (*statusbar
)->phys_screen
= screen_virttophys(screen
);
601 statusbar_list_append(&globalconf
.screens
[screen
].statusbar
, *statusbar
);
602 statusbar_ref(statusbar
);
604 /* All the other statusbar and ourselves need to be repositioned */
605 for(s
= globalconf
.screens
[screen
].statusbar
; s
; s
= s
->next
)
606 statusbar_position_update(s
);
608 ewmh_update_workarea((*statusbar
)->phys_screen
);
612 buf
= luaL_checklstring(L
, 3, &len
);
613 (*statusbar
)->align
= draw_align_fromstr(buf
, len
);
614 statusbar_position_update(*statusbar
);
617 if((buf
= luaL_checklstring(L
, 3, &len
)))
618 if(xcolor_init(&(*statusbar
)->colors
.fg
, globalconf
.connection
,
619 globalconf
.default_screen
, buf
, len
))
621 if((*statusbar
)->ctx
)
622 (*statusbar
)->ctx
->fg
= (*statusbar
)->colors
.fg
;
623 (*statusbar
)->need_update
= true;
627 if((buf
= luaL_checklstring(L
, 3, &len
)))
628 if(xcolor_init(&(*statusbar
)->colors
.bg
, globalconf
.connection
,
629 globalconf
.default_screen
, buf
, len
))
631 if((*statusbar
)->ctx
)
632 (*statusbar
)->ctx
->bg
= (*statusbar
)->colors
.bg
;
634 (*statusbar
)->need_update
= true;
638 buf
= luaL_checklstring(L
, 3, &len
);
639 p
= position_fromstr(buf
, len
);
640 if(p
!= (*statusbar
)->position
)
642 (*statusbar
)->position
= p
;
643 for(s
= globalconf
.screens
[(*statusbar
)->screen
].statusbar
; s
; s
= s
->next
)
644 statusbar_position_update(s
);
645 ewmh_update_workarea((*statusbar
)->phys_screen
);
649 luaA_checktable(L
, 3);
651 /* remove all widgets */
652 for(witer
= (*statusbar
)->widgets
; witer
; witer
= (*statusbar
)->widgets
)
654 if(witer
->widget
->detach
)
655 witer
->widget
->detach(witer
->widget
, *statusbar
);
656 widget_unref(&witer
->widget
);
657 widget_node_list_detach(&(*statusbar
)->widgets
, witer
);
661 (*statusbar
)->need_update
= true;
663 /* now read all widgets and add them */
665 while(lua_next(L
, 3))
667 widget_t
**widget
= luaA_checkudata(L
, -1, "widget");
668 widget_node_t
*w
= p_new(widget_node_t
, 1);
670 widget_node_list_append(&(*statusbar
)->widgets
, w
);
682 const struct luaL_reg awesome_statusbar_methods
[] =
684 { "__call", luaA_statusbar_new
},
687 const struct luaL_reg awesome_statusbar_meta
[] =
689 { "__index", luaA_statusbar_index
},
690 { "__newindex", luaA_statusbar_newindex
},
691 { "__gc", luaA_statusbar_gc
},
692 { "__eq", luaA_statusbar_eq
},
693 { "__tostring", luaA_statusbar_tostring
},
697 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80