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
)
42 xcb_screen_t
*s
= xutil_screen_get(globalconf
.connection
, phys_screen
);
44 xcb_reparent_window(globalconf
.connection
,
45 globalconf
.screens
[phys_screen
].systray
.window
,
48 globalconf
.screens
[phys_screen
].systray
.parent
= s
->root
;
52 statusbar_systray_refresh(statusbar_t
*statusbar
)
54 widget_node_t
*systray
;
56 if(statusbar
->screen
== SCREEN_UNDEF
)
59 for(systray
= statusbar
->widgets
; systray
; systray
= systray
->next
)
60 if(systray
->widget
->type
== systray_new
)
62 uint32_t config_back
[] = { statusbar
->colors
.bg
.pixel
};
63 uint32_t config_win_vals
[4];
64 uint32_t config_win_vals_off
[2] = { -512, -512 };
68 if(statusbar
->position
69 && systray
->widget
->isvisible
70 && systray
->area
.width
)
72 pos
= statusbar
->position
;
74 /* Set background of the systray window. */
75 xcb_change_window_attributes(globalconf
.connection
,
76 globalconf
.screens
[statusbar
->phys_screen
].systray
.window
,
77 XCB_CW_BACK_PIXEL
, config_back
);
79 xcb_map_window(globalconf
.connection
, globalconf
.screens
[statusbar
->phys_screen
].systray
.window
);
81 switch(statusbar
->position
)
84 config_win_vals
[0] = systray
->area
.y
;
85 config_win_vals
[1] = statusbar
->sw
->geometry
.height
- systray
->area
.x
- systray
->area
.width
;
86 config_win_vals
[2] = systray
->area
.height
;
87 config_win_vals
[3] = systray
->area
.width
;
90 config_win_vals
[0] = systray
->area
.y
;
91 config_win_vals
[1] = systray
->area
.x
;
92 config_win_vals
[2] = systray
->area
.height
;
93 config_win_vals
[3] = systray
->area
.width
;
96 config_win_vals
[0] = systray
->area
.x
;
97 config_win_vals
[1] = systray
->area
.y
;
98 config_win_vals
[2] = systray
->area
.width
;
99 config_win_vals
[3] = systray
->area
.height
;
103 if(globalconf
.screens
[statusbar
->phys_screen
].systray
.parent
!= statusbar
->sw
->window
)
105 xcb_reparent_window(globalconf
.connection
,
106 globalconf
.screens
[statusbar
->phys_screen
].systray
.window
,
107 statusbar
->sw
->window
,
108 config_win_vals
[0], config_win_vals
[1]);
109 globalconf
.screens
[statusbar
->phys_screen
].systray
.parent
= statusbar
->sw
->window
;
111 xcb_configure_window(globalconf
.connection
,
112 globalconf
.screens
[statusbar
->phys_screen
].systray
.window
,
114 | XCB_CONFIG_WINDOW_Y
115 | XCB_CONFIG_WINDOW_WIDTH
116 | XCB_CONFIG_WINDOW_HEIGHT
,
118 /* width = height = systray height */
119 config_win_vals
[2] = config_win_vals
[3] = systray
->area
.height
;
120 config_win_vals
[0] = 0;
124 xcb_unmap_window(globalconf
.connection
, globalconf
.screens
[statusbar
->phys_screen
].systray
.window
);
132 config_win_vals
[1] = systray
->area
.width
- config_win_vals
[3];
133 for(em
= globalconf
.embedded
; em
; em
= em
->next
)
134 if(em
->phys_screen
== statusbar
->phys_screen
)
136 if(config_win_vals
[1] - config_win_vals
[2] >= (uint32_t) statusbar
->sw
->geometry
.y
)
138 xcb_map_window(globalconf
.connection
, em
->win
);
139 xcb_configure_window(globalconf
.connection
, em
->win
,
141 | XCB_CONFIG_WINDOW_Y
142 | XCB_CONFIG_WINDOW_WIDTH
143 | XCB_CONFIG_WINDOW_HEIGHT
,
145 config_win_vals
[1] -= config_win_vals
[3];
148 xcb_configure_window(globalconf
.connection
, em
->win
,
150 | XCB_CONFIG_WINDOW_Y
,
151 config_win_vals_off
);
155 config_win_vals
[1] = 0;
156 for(em
= globalconf
.embedded
; em
; em
= em
->next
)
157 if(em
->phys_screen
== statusbar
->phys_screen
)
159 if(config_win_vals
[1] + config_win_vals
[3] <= (uint32_t) statusbar
->sw
->geometry
.y
+ statusbar
->ctx
->width
)
161 xcb_map_window(globalconf
.connection
, em
->win
);
162 xcb_configure_window(globalconf
.connection
, em
->win
,
164 | XCB_CONFIG_WINDOW_Y
165 | XCB_CONFIG_WINDOW_WIDTH
166 | XCB_CONFIG_WINDOW_HEIGHT
,
168 config_win_vals
[1] += config_win_vals
[3];
171 xcb_configure_window(globalconf
.connection
, em
->win
,
173 | XCB_CONFIG_WINDOW_Y
,
174 config_win_vals_off
);
179 config_win_vals
[1] = 0;
180 for(em
= globalconf
.embedded
; em
; em
= em
->next
)
181 if(em
->phys_screen
== statusbar
->phys_screen
)
183 /* if(x + width < systray.x + systray.width) */
184 if(config_win_vals
[0] + config_win_vals
[2] <= (uint32_t) AREA_RIGHT(systray
->area
) + statusbar
->sw
->geometry
.x
)
186 xcb_map_window(globalconf
.connection
, em
->win
);
187 xcb_configure_window(globalconf
.connection
, em
->win
,
189 | XCB_CONFIG_WINDOW_Y
190 | XCB_CONFIG_WINDOW_WIDTH
191 | XCB_CONFIG_WINDOW_HEIGHT
,
193 config_win_vals
[0] += config_win_vals
[2];
196 xcb_configure_window(globalconf
.connection
, em
->win
,
198 | XCB_CONFIG_WINDOW_Y
,
199 config_win_vals_off
);
203 statusbar_systray_kickout(statusbar
->phys_screen
);
210 /** Draw a statusbar.
211 * \param statusbar The statusbar to draw.
214 statusbar_draw(statusbar_t
*statusbar
)
216 statusbar
->need_update
= false;
218 if(statusbar
->position
)
220 widget_render(statusbar
->widgets
, statusbar
->ctx
, statusbar
->sw
->gc
,
221 statusbar
->sw
->pixmap
,
222 statusbar
->screen
, statusbar
->position
,
223 statusbar
->sw
->geometry
.x
, statusbar
->sw
->geometry
.y
,
224 statusbar
, AWESOME_TYPE_STATUSBAR
);
225 simplewindow_refresh_pixmap(statusbar
->sw
);
228 statusbar_systray_refresh(statusbar
);
231 /** Get a statusbar by its window.
232 * \param w The window id.
233 * \return A statusbar if found, NULL otherwise.
236 statusbar_getbywin(xcb_window_t w
)
239 for(int i
= 0; i
< globalconf
.screens_info
->nscreen
; i
++)
240 for(s
= globalconf
.screens
[i
].statusbar
; s
; s
= s
->next
)
241 if(s
->sw
->window
== w
)
246 /** Statusbar refresh function.
249 statusbar_refresh(void)
252 statusbar_t
*statusbar
;
254 for(screen
= 0; screen
< globalconf
.screens_info
->nscreen
; screen
++)
255 for(statusbar
= globalconf
.screens
[screen
].statusbar
; statusbar
; statusbar
= statusbar
->next
)
256 if(statusbar
->need_update
)
257 statusbar_draw(statusbar
);
261 statusbar_clean(statusbar_t
*statusbar
)
263 /* Who! Check that we're not deleting a statusbar with a systray, because it
264 * may be its parent. If so, we reparent to root before, otherwise it will
266 statusbar_systray_kickout(statusbar
->phys_screen
);
268 simplewindow_delete(&statusbar
->sw
);
269 draw_context_delete(&statusbar
->ctx
);
272 /** Update the statusbar position. It deletes every statusbar resources and
274 * \param statusbar The statusbar.
277 statusbar_position_update(statusbar_t
*statusbar
)
280 area_t area
, wingeometry
;
282 xcb_screen_t
*s
= NULL
;
285 if(statusbar
->position
== Off
)
286 return statusbar_clean(statusbar
);
288 area
= screen_area_get(statusbar
->screen
, NULL
,
289 &globalconf
.screens
[statusbar
->screen
].padding
, true);
291 /* Top and Bottom statusbar_t have prio */
292 for(sb
= globalconf
.screens
[statusbar
->screen
].statusbar
; sb
; sb
= sb
->next
)
294 /* Ignore every statusbar after me that is in the same position */
300 else if(ignore
&& statusbar
->position
== sb
->position
)
305 switch(statusbar
->position
)
308 area
.x
+= statusbar
->height
;
315 switch(statusbar
->position
)
318 area
.x
-= statusbar
->height
;
325 switch(statusbar
->position
)
328 area
.y
+= sb
->height
;
332 area
.height
-= sb
->height
;
333 area
.y
+= sb
->height
;
340 switch(statusbar
->position
)
343 area
.y
-= sb
->height
;
347 area
.height
-= sb
->height
;
358 switch(statusbar
->position
)
361 if(statusbar
->width_user
)
362 wingeometry
.height
= statusbar
->width
;
364 wingeometry
.height
= area
.height
;
365 wingeometry
.width
= statusbar
->height
;
366 switch(statusbar
->align
)
369 wingeometry
.x
= area
.x
+ area
.width
- wingeometry
.width
;
370 wingeometry
.y
= area
.y
;
373 wingeometry
.x
= area
.x
+ area
.width
- wingeometry
.width
;
374 wingeometry
.y
= area
.y
+ area
.height
- wingeometry
.height
;
377 wingeometry
.x
= area
.x
+ area
.width
- wingeometry
.width
;
378 wingeometry
.y
= (area
.y
+ area
.height
- wingeometry
.height
) / 2;
383 if(statusbar
->width_user
)
384 wingeometry
.height
= statusbar
->width
;
386 wingeometry
.height
= area
.height
;
387 wingeometry
.width
= statusbar
->height
;
388 switch(statusbar
->align
)
391 wingeometry
.x
= area
.x
;
392 wingeometry
.y
= (area
.y
+ area
.height
) - wingeometry
.height
;
395 wingeometry
.x
= area
.x
;
396 wingeometry
.y
= area
.y
;
399 wingeometry
.x
= area
.x
;
400 wingeometry
.y
= (area
.y
+ area
.height
- wingeometry
.height
) / 2;
404 if(statusbar
->width_user
)
405 wingeometry
.width
= statusbar
->width
;
407 wingeometry
.width
= area
.width
;
408 wingeometry
.height
= statusbar
->height
;
409 switch(statusbar
->align
)
412 wingeometry
.x
= area
.x
;
413 wingeometry
.y
= (area
.y
+ area
.height
) - wingeometry
.height
;
416 wingeometry
.x
= area
.x
+ area
.width
- wingeometry
.width
;
417 wingeometry
.y
= (area
.y
+ area
.height
) - wingeometry
.height
;
420 wingeometry
.x
= area
.x
+ (area
.width
- wingeometry
.width
) / 2;
421 wingeometry
.y
= (area
.y
+ area
.height
) - wingeometry
.height
;
426 if(statusbar
->width_user
)
427 wingeometry
.width
= statusbar
->width
;
429 wingeometry
.width
= area
.width
;
430 wingeometry
.height
= statusbar
->height
;
431 switch(statusbar
->align
)
434 wingeometry
.x
= area
.x
;
435 wingeometry
.y
= area
.y
;
438 wingeometry
.x
= area
.x
+ area
.width
- wingeometry
.width
;
439 wingeometry
.y
= area
.y
;
442 wingeometry
.x
= area
.x
+ (area
.width
- wingeometry
.width
) / 2;
443 wingeometry
.y
= area
.y
;
449 /* same window size and position ? */
451 || wingeometry
.width
!= statusbar
->sw
->geometry
.width
452 || wingeometry
.height
!= statusbar
->sw
->geometry
.height
)
454 statusbar_clean(statusbar
);
457 simplewindow_new(statusbar
->phys_screen
, 0, 0,
458 wingeometry
.width
, wingeometry
.height
, 0);
460 switch(statusbar
->position
)
464 statusbar
->width
= wingeometry
.height
;
465 s
= xutil_screen_get(globalconf
.connection
, statusbar
->phys_screen
);
466 /* we need a new pixmap this way [ ] to render */
467 dw
= xcb_generate_id(globalconf
.connection
);
468 xcb_create_pixmap(globalconf
.connection
,
469 s
->root_depth
, dw
, s
->root
,
470 statusbar
->width
, statusbar
->height
);
471 statusbar
->ctx
= draw_context_new(statusbar
->phys_screen
,
475 &statusbar
->colors
.fg
,
476 &statusbar
->colors
.bg
);
479 statusbar
->width
= wingeometry
.width
;
480 statusbar
->ctx
= draw_context_new(statusbar
->phys_screen
,
483 statusbar
->sw
->pixmap
,
484 &statusbar
->colors
.fg
,
485 &statusbar
->colors
.bg
);
488 simplewindow_move(statusbar
->sw
, wingeometry
.x
, wingeometry
.y
);
489 xcb_map_window(globalconf
.connection
, statusbar
->sw
->window
);
490 statusbar
->need_update
= true;
492 else if(wingeometry
.x
!= statusbar
->sw
->geometry
.x
493 || wingeometry
.y
!= statusbar
->sw
->geometry
.y
)
494 simplewindow_move(statusbar
->sw
, wingeometry
.x
, wingeometry
.y
);
496 /* Set need update */
497 globalconf
.screens
[statusbar
->screen
].need_arrange
= true;
500 /** Convert a statusbar to a printable string.
501 * \param L The Lua VM state.
504 * \lvalue A statusbar.
507 luaA_statusbar_tostring(lua_State
*L
)
509 statusbar_t
**p
= luaA_checkudata(L
, 1, "statusbar");
510 lua_pushfstring(L
, "[statusbar udata(%p) name(%s)]", *p
, (*p
)->name
);
514 /** Create a new statusbar.
515 * \param L The Lua VM state.
518 * \lparam A table with at least a name attribute. Optionaly defined values are:
519 * position, align, fg, bg, width and height.
520 * \lreturn A brand new statusbar.
523 luaA_statusbar_new(lua_State
*L
)
528 xcolor_init_request_t reqs
[2];
529 int8_t i
, reqs_nbr
= -1;
531 luaA_checktable(L
, 2);
533 if(!(buf
= luaA_getopt_string(L
, 2, "name", NULL
)))
534 luaL_error(L
, "object statusbar must have a name");
536 sb
= p_new(statusbar_t
, 1);
538 sb
->name
= a_strdup(buf
);
540 sb
->colors
.fg
= globalconf
.colors
.fg
;
541 if((buf
= luaA_getopt_lstring(L
, 2, "fg", NULL
, &len
)))
542 reqs
[++reqs_nbr
] = xcolor_init_unchecked(&sb
->colors
.fg
, buf
, len
);
544 sb
->colors
.bg
= globalconf
.colors
.bg
;
545 if((buf
= luaA_getopt_lstring(L
, 2, "bg", NULL
, &len
)))
546 reqs
[++reqs_nbr
] = xcolor_init_unchecked(&sb
->colors
.bg
, buf
, len
);
548 buf
= luaA_getopt_lstring(L
, 2, "align", "left", &len
);
549 sb
->align
= draw_align_fromstr(buf
, len
);
551 sb
->width
= luaA_getopt_number(L
, 2, "width", 0);
553 sb
->width_user
= true;
554 sb
->height
= luaA_getopt_number(L
, 2, "height", 0);
556 /* 1.5 as default factor, it fits nice but no one knows why */
557 sb
->height
= 1.5 * globalconf
.font
->height
;
559 buf
= luaA_getopt_lstring(L
, 2, "position", "top", &len
);
560 sb
->position
= position_fromstr(buf
, len
);
562 sb
->screen
= SCREEN_UNDEF
;
564 for(i
= 0; i
<= reqs_nbr
; i
++)
565 xcolor_init_reply(reqs
[i
]);
567 return luaA_statusbar_userdata_new(L
, sb
);
570 /** Statusbar object.
571 * \param L The Lua VM state.
572 * \return The number of elements pushed on stack.
574 * \lfield screen Screen number.
575 * \lfield align The alignment.
576 * \lfield fg Foreground color.
577 * \lfield bg Background color.
578 * \lfield position The position.
581 luaA_statusbar_index(lua_State
*L
)
584 statusbar_t
**statusbar
= luaA_checkudata(L
, 1, "statusbar");
585 const char *attr
= luaL_checklstring(L
, 2, &len
);
587 if(luaA_usemetatable(L
, 1, 2))
590 switch(a_tokenize(attr
, len
))
593 if((*statusbar
)->screen
== SCREEN_UNDEF
)
595 lua_pushnumber(L
, (*statusbar
)->screen
+ 1);
598 lua_pushstring(L
, draw_align_tostr((*statusbar
)->align
));
601 luaA_pushcolor(L
, &(*statusbar
)->colors
.fg
);
604 luaA_pushcolor(L
, &(*statusbar
)->colors
.bg
);
607 lua_pushstring(L
, position_tostr((*statusbar
)->position
));
616 /** Get or set the statusbar widgets.
617 * \param L The Lua VM state.
618 * \return The number of elements pushed on stack.
620 * \lparam None, or a table of widgets to set.
621 * \lreturn The current statusbar widgets.
624 luaA_statusbar_widgets(lua_State
*L
)
626 statusbar_t
**statusbar
= luaA_checkudata(L
, 1, "statusbar");
628 if(lua_gettop(L
) == 2)
630 luaA_widget_set(L
, 2, *statusbar
, &(*statusbar
)->widgets
);
631 (*statusbar
)->need_update
= true;
632 (*statusbar
)->mouse_over
= NULL
;
635 return luaA_widget_get(L
, (*statusbar
)->widgets
);
638 /** Remove a statubar from a screen.
639 * \param statusbar Statusbar to detach from screen.
642 statusbar_remove(statusbar_t
*statusbar
)
644 if(statusbar
->screen
!= SCREEN_UNDEF
)
648 statusbar_systray_kickout(statusbar
->phys_screen
);
651 p
= statusbar
->position
;
652 statusbar
->position
= Off
;
653 statusbar_position_update(statusbar
);
654 /* restore position */
655 statusbar
->position
= p
;
657 statusbar_list_detach(&globalconf
.screens
[statusbar
->screen
].statusbar
, statusbar
);
658 globalconf
.screens
[statusbar
->screen
].need_arrange
= true;
659 statusbar
->screen
= SCREEN_UNDEF
;
660 statusbar_unref(&statusbar
);
664 /** Statusbar newindex.
665 * \param L The Lua VM state.
666 * \return The number of elements pushed on stack.
669 luaA_statusbar_newindex(lua_State
*L
)
672 statusbar_t
*s
, **statusbar
= luaA_checkudata(L
, 1, "statusbar");
673 const char *buf
, *attr
= luaL_checklstring(L
, 2, &len
);
677 switch(a_tokenize(attr
, len
))
681 statusbar_remove(*statusbar
);
684 screen
= luaL_checknumber(L
, 3) - 1;
686 luaA_checkscreen(screen
);
688 if((*statusbar
)->screen
== screen
)
689 luaL_error(L
, "this statusbar is already on screen %d",
690 (*statusbar
)->screen
+ 1);
692 /* Check for uniq name and id. */
693 for(s
= globalconf
.screens
[screen
].statusbar
; s
; s
= s
->next
)
694 if(!a_strcmp(s
->name
, (*statusbar
)->name
))
695 luaL_error(L
, "a statusbar with that name is already on screen %d\n",
698 statusbar_remove(*statusbar
);
700 (*statusbar
)->screen
= screen
;
701 (*statusbar
)->phys_screen
= screen_virttophys(screen
);
703 statusbar_list_append(&globalconf
.screens
[screen
].statusbar
, *statusbar
);
704 statusbar_ref(statusbar
);
706 /* All the other statusbar and ourselves need to be repositioned */
707 for(s
= globalconf
.screens
[screen
].statusbar
; s
; s
= s
->next
)
708 statusbar_position_update(s
);
710 ewmh_update_workarea((*statusbar
)->phys_screen
);
714 buf
= luaL_checklstring(L
, 3, &len
);
715 (*statusbar
)->align
= draw_align_fromstr(buf
, len
);
716 statusbar_position_update(*statusbar
);
719 if((buf
= luaL_checklstring(L
, 3, &len
)))
720 if(xcolor_init_reply(xcolor_init_unchecked(&(*statusbar
)->colors
.fg
, buf
, len
)))
722 if((*statusbar
)->ctx
)
723 (*statusbar
)->ctx
->fg
= (*statusbar
)->colors
.fg
;
724 (*statusbar
)->need_update
= true;
728 if((buf
= luaL_checklstring(L
, 3, &len
)))
729 if(xcolor_init_reply(xcolor_init_unchecked(&(*statusbar
)->colors
.bg
, buf
, len
)))
731 if((*statusbar
)->ctx
)
732 (*statusbar
)->ctx
->bg
= (*statusbar
)->colors
.bg
;
734 (*statusbar
)->need_update
= true;
738 buf
= luaL_checklstring(L
, 3, &len
);
739 p
= position_fromstr(buf
, len
);
740 if(p
!= (*statusbar
)->position
)
742 (*statusbar
)->position
= p
;
743 if((*statusbar
)->screen
!= SCREEN_UNDEF
)
745 for(s
= globalconf
.screens
[(*statusbar
)->screen
].statusbar
; s
; s
= s
->next
)
746 statusbar_position_update(s
);
747 ewmh_update_workarea((*statusbar
)->phys_screen
);
758 const struct luaL_reg awesome_statusbar_methods
[] =
760 { "__call", luaA_statusbar_new
},
763 const struct luaL_reg awesome_statusbar_meta
[] =
765 { "widgets", luaA_statusbar_widgets
},
766 { "__index", luaA_statusbar_index
},
767 { "__newindex", luaA_statusbar_newindex
},
768 { "__gc", luaA_statusbar_gc
},
769 { "__eq", luaA_statusbar_eq
},
770 { "__tostring", luaA_statusbar_tostring
},
774 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80