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(&globalconf
.screens
[statusbar
->screen
].geometry
,
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
)
439 xcolor_init_request_t reqs
[2];
440 int8_t i
, reqs_nbr
= -1;
442 luaA_checktable(L
, 2);
444 if(!(buf
= luaA_getopt_string(L
, 2, "name", NULL
)))
445 luaL_error(L
, "object statusbar must have a name");
447 sb
= p_new(statusbar_t
, 1);
449 sb
->name
= a_strdup(buf
);
451 sb
->colors
.fg
= globalconf
.colors
.fg
;
452 if((buf
= luaA_getopt_lstring(L
, 2, "fg", NULL
, &len
)))
453 reqs
[++reqs_nbr
] = xcolor_init_unchecked(globalconf
.connection
,
455 globalconf
.default_screen
,
458 sb
->colors
.bg
= globalconf
.colors
.bg
;
459 if((buf
= luaA_getopt_lstring(L
, 2, "bg", NULL
, &len
)))
460 reqs
[++reqs_nbr
] = xcolor_init_unchecked(globalconf
.connection
,
462 globalconf
.default_screen
,
465 buf
= luaA_getopt_lstring(L
, 2, "align", "left", &len
);
466 sb
->align
= draw_align_fromstr(buf
, len
);
468 sb
->width
= luaA_getopt_number(L
, 2, "width", 0);
470 sb
->width_user
= true;
471 sb
->height
= luaA_getopt_number(L
, 2, "height", 0);
473 /* 1.5 as default factor, it fits nice but no one knows why */
474 sb
->height
= 1.5 * globalconf
.font
->height
;
476 buf
= luaA_getopt_lstring(L
, 2, "position", "top", &len
);
477 sb
->position
= position_fromstr(buf
, len
);
479 sb
->screen
= SCREEN_UNDEF
;
481 for(i
= 0; i
<= reqs_nbr
; i
++)
482 xcolor_init_reply(globalconf
.connection
, reqs
[i
]);
484 return luaA_statusbar_userdata_new(L
, sb
);
487 /** Statusbar object.
488 * \param L The Lua VM state.
489 * \return The number of elements pushed on stack.
491 * \lfield screen Screen number.
492 * \lfield align The alignment.
493 * \lfield fg Foreground color.
494 * \lfield bg Background color.
495 * \lfield position The position.
496 * \lfield widget The statusbar widgets.
499 luaA_statusbar_index(lua_State
*L
)
503 widget_node_t
*witer
;
504 statusbar_t
**statusbar
= luaA_checkudata(L
, 1, "statusbar");
505 const char *attr
= luaL_checklstring(L
, 2, &len
);
507 if(luaA_usemetatable(L
, 1, 2))
510 switch(a_tokenize(attr
, len
))
513 if((*statusbar
)->screen
== SCREEN_UNDEF
)
515 lua_pushnumber(L
, (*statusbar
)->screen
+ 1);
518 lua_pushstring(L
, draw_align_tostr((*statusbar
)->align
));
521 luaA_pushcolor(L
, &(*statusbar
)->colors
.fg
);
524 luaA_pushcolor(L
, &(*statusbar
)->colors
.bg
);
527 lua_pushstring(L
, position_tostr((*statusbar
)->position
));
531 for(witer
= (*statusbar
)->widgets
; witer
; witer
= witer
->next
)
533 luaA_widget_userdata_new(L
, witer
->widget
);
534 lua_rawseti(L
, -2, ++i
);
544 /** Remove a statubar from a screen.
545 * \param statusbar Statusbar to detach from screen.
548 statusbar_remove(statusbar_t
*statusbar
)
550 if(statusbar
->screen
!= SCREEN_UNDEF
)
554 statusbar_systray_kickout(statusbar
->phys_screen
);
557 p
= statusbar
->position
;
558 statusbar
->position
= Off
;
559 statusbar_position_update(statusbar
);
560 /* restore position */
561 statusbar
->position
= p
;
563 statusbar_list_detach(&globalconf
.screens
[statusbar
->screen
].statusbar
, statusbar
);
564 globalconf
.screens
[statusbar
->screen
].need_arrange
= true;
565 statusbar
->screen
= SCREEN_UNDEF
;
566 statusbar_unref(&statusbar
);
570 /** Statusbar newindex.
571 * \param L The Lua VM state.
572 * \return The number of elements pushed on stack.
575 luaA_statusbar_newindex(lua_State
*L
)
578 statusbar_t
*s
, **statusbar
= luaA_checkudata(L
, 1, "statusbar");
579 const char *buf
, *attr
= luaL_checklstring(L
, 2, &len
);
582 widget_node_t
*witer
;
584 switch(a_tokenize(attr
, len
))
588 statusbar_remove(*statusbar
);
591 screen
= luaL_checknumber(L
, 3) - 1;
593 luaA_checkscreen(screen
);
595 if((*statusbar
)->screen
== screen
)
596 luaL_error(L
, "this statusbar is already on screen %d",
597 (*statusbar
)->screen
+ 1);
599 /* Check for uniq name and id. */
600 for(s
= globalconf
.screens
[screen
].statusbar
; s
; s
= s
->next
)
601 if(!a_strcmp(s
->name
, (*statusbar
)->name
))
602 luaL_error(L
, "a statusbar with that name is already on screen %d\n",
605 statusbar_remove(*statusbar
);
607 (*statusbar
)->screen
= screen
;
608 (*statusbar
)->phys_screen
= screen_virttophys(screen
);
610 statusbar_list_append(&globalconf
.screens
[screen
].statusbar
, *statusbar
);
611 statusbar_ref(statusbar
);
613 /* All the other statusbar and ourselves need to be repositioned */
614 for(s
= globalconf
.screens
[screen
].statusbar
; s
; s
= s
->next
)
615 statusbar_position_update(s
);
617 ewmh_update_workarea((*statusbar
)->phys_screen
);
621 buf
= luaL_checklstring(L
, 3, &len
);
622 (*statusbar
)->align
= draw_align_fromstr(buf
, len
);
623 statusbar_position_update(*statusbar
);
626 if((buf
= luaL_checklstring(L
, 3, &len
)))
627 if(xcolor_init_reply(globalconf
.connection
,
628 xcolor_init_unchecked(globalconf
.connection
,
629 &(*statusbar
)->colors
.fg
,
630 globalconf
.default_screen
,
633 if((*statusbar
)->ctx
)
634 (*statusbar
)->ctx
->fg
= (*statusbar
)->colors
.fg
;
635 (*statusbar
)->need_update
= true;
639 if((buf
= luaL_checklstring(L
, 3, &len
)))
640 if(xcolor_init_reply(globalconf
.connection
,
641 xcolor_init_unchecked(globalconf
.connection
,
642 &(*statusbar
)->colors
.bg
,
643 globalconf
.default_screen
, buf
, len
)))
645 if((*statusbar
)->ctx
)
646 (*statusbar
)->ctx
->bg
= (*statusbar
)->colors
.bg
;
648 (*statusbar
)->need_update
= true;
652 buf
= luaL_checklstring(L
, 3, &len
);
653 p
= position_fromstr(buf
, len
);
654 if(p
!= (*statusbar
)->position
)
656 (*statusbar
)->position
= p
;
657 if((*statusbar
)->screen
!= SCREEN_UNDEF
)
659 for(s
= globalconf
.screens
[(*statusbar
)->screen
].statusbar
; s
; s
= s
->next
)
660 statusbar_position_update(s
);
661 ewmh_update_workarea((*statusbar
)->phys_screen
);
666 luaA_checktable(L
, 3);
668 /* remove all widgets */
669 for(witer
= (*statusbar
)->widgets
; witer
; witer
= (*statusbar
)->widgets
)
671 if(witer
->widget
->detach
)
672 witer
->widget
->detach(witer
->widget
, *statusbar
);
673 widget_unref(&witer
->widget
);
674 widget_node_list_detach(&(*statusbar
)->widgets
, witer
);
678 (*statusbar
)->need_update
= true;
680 /* now read all widgets and add them */
682 while(lua_next(L
, 3))
684 widget_t
**widget
= luaA_checkudata(L
, -1, "widget");
685 widget_node_t
*w
= p_new(widget_node_t
, 1);
687 widget_node_list_append(&(*statusbar
)->widgets
, w
);
699 const struct luaL_reg awesome_statusbar_methods
[] =
701 { "__call", luaA_statusbar_new
},
704 const struct luaL_reg awesome_statusbar_meta
[] =
706 { "__index", luaA_statusbar_index
},
707 { "__newindex", luaA_statusbar_newindex
},
708 { "__gc", luaA_statusbar_gc
},
709 { "__eq", luaA_statusbar_eq
},
710 { "__tostring", luaA_statusbar_tostring
},
714 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80