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_back
[] = { globalconf
.colors
.bg
.pixel
};
65 uint32_t config_win_vals
[4];
66 uint32_t config_win_vals_off
[2] = { -512, -512 };
70 if(statusbar
->position
71 && systray
->widget
->isvisible
)
73 pos
= statusbar
->position
;
75 config_win_vals
[2] = systray
->area
.height
;
77 config_win_vals
[3] = systray
->area
.height
;
83 for(em
= globalconf
.embedded
; em
; em
= em
->next
)
84 if(em
->phys_screen
== statusbar
->phys_screen
)
85 xcb_change_window_attributes(globalconf
.connection
, em
->win
, XCB_CW_BACK_PIXEL
, config_back
);
90 config_win_vals
[0] = statusbar
->sw
->geometry
.x
+ systray
->area
.y
;
91 config_win_vals
[1] = statusbar
->sw
->geometry
.y
+ statusbar
->sw
->geometry
.height
92 - systray
->area
.x
- config_win_vals
[3];
93 for(em
= globalconf
.embedded
; em
; em
= em
->next
)
94 if(em
->phys_screen
== statusbar
->phys_screen
)
96 if(config_win_vals
[1] - config_win_vals
[2] >= (uint32_t) statusbar
->sw
->geometry
.y
)
98 xcb_map_window(globalconf
.connection
, em
->win
);
99 xcb_configure_window(globalconf
.connection
, em
->win
,
101 | XCB_CONFIG_WINDOW_Y
102 | XCB_CONFIG_WINDOW_WIDTH
103 | XCB_CONFIG_WINDOW_HEIGHT
,
105 config_win_vals
[1] -= config_win_vals
[3];
108 xcb_configure_window(globalconf
.connection
, em
->win
,
110 | XCB_CONFIG_WINDOW_Y
,
111 config_win_vals_off
);
116 config_win_vals
[0] = statusbar
->sw
->geometry
.x
- systray
->area
.y
;
117 config_win_vals
[1] = statusbar
->sw
->geometry
.y
+ systray
->area
.x
;
118 for(em
= globalconf
.embedded
; em
; em
= em
->next
)
119 if(em
->phys_screen
== statusbar
->phys_screen
)
121 if(config_win_vals
[1] + config_win_vals
[3] <= (uint32_t) statusbar
->sw
->geometry
.y
+ statusbar
->ctx
->width
)
123 xcb_map_window(globalconf
.connection
, em
->win
);
124 xcb_configure_window(globalconf
.connection
, em
->win
,
126 | XCB_CONFIG_WINDOW_Y
127 | XCB_CONFIG_WINDOW_WIDTH
128 | XCB_CONFIG_WINDOW_HEIGHT
,
130 config_win_vals
[1] += config_win_vals
[3];
133 xcb_configure_window(globalconf
.connection
, em
->win
,
135 | XCB_CONFIG_WINDOW_Y
,
136 config_win_vals_off
);
142 config_win_vals
[0] = statusbar
->sw
->geometry
.x
+ systray
->area
.x
;
143 config_win_vals
[1] = statusbar
->sw
->geometry
.y
+ systray
->area
.y
;
144 for(em
= globalconf
.embedded
; em
; em
= em
->next
)
145 if(em
->phys_screen
== statusbar
->phys_screen
)
147 /* if(x + width < systray.x + systray.width) */
148 if(config_win_vals
[0] + config_win_vals
[2] <= (uint32_t) AREA_RIGHT(systray
->area
) + statusbar
->sw
->geometry
.x
)
150 xcb_map_window(globalconf
.connection
, em
->win
);
151 xcb_configure_window(globalconf
.connection
, em
->win
,
153 | XCB_CONFIG_WINDOW_Y
154 | XCB_CONFIG_WINDOW_WIDTH
155 | XCB_CONFIG_WINDOW_HEIGHT
,
157 config_win_vals
[0] += config_win_vals
[2];
160 xcb_configure_window(globalconf
.connection
, em
->win
,
162 | XCB_CONFIG_WINDOW_Y
,
163 config_win_vals_off
);
168 statusbar_systray_kickout(statusbar
->phys_screen
);
175 /** Draw a statusbar.
176 * \param statusbar The statusbar to draw.
179 statusbar_draw(statusbar_t
*statusbar
)
181 statusbar
->need_update
= false;
183 if(statusbar
->position
)
185 widget_render(statusbar
->widgets
, statusbar
->ctx
, statusbar
->sw
->gc
,
186 statusbar
->sw
->pixmap
,
187 statusbar
->screen
, statusbar
->position
,
188 statusbar
->sw
->geometry
.x
, statusbar
->sw
->geometry
.y
,
189 statusbar
, AWESOME_TYPE_STATUSBAR
);
190 simplewindow_refresh_pixmap(statusbar
->sw
);
193 statusbar_systray_refresh(statusbar
);
196 /** Statusbar refresh function.
199 statusbar_refresh(void)
202 statusbar_t
*statusbar
;
204 for(screen
= 0; screen
< globalconf
.screens_info
->nscreen
; screen
++)
205 for(statusbar
= globalconf
.screens
[screen
].statusbar
; statusbar
; statusbar
= statusbar
->next
)
206 if(statusbar
->need_update
)
207 statusbar_draw(statusbar
);
210 /** Update the statusbar position. It deletes every statusbar resources and
212 * \param statusbar The statusbar.
215 statusbar_position_update(statusbar_t
*statusbar
)
220 xcb_screen_t
*s
= NULL
;
223 globalconf
.screens
[statusbar
->screen
].need_arrange
= true;
225 simplewindow_delete(&statusbar
->sw
);
226 draw_context_delete(&statusbar
->ctx
);
228 if(statusbar
->position
== Off
)
231 area
= screen_area_get(&globalconf
.screens
[statusbar
->screen
].geometry
,
233 &globalconf
.screens
[statusbar
->screen
].padding
);
235 /* Top and Bottom statusbar_t have prio */
236 for(sb
= globalconf
.screens
[statusbar
->screen
].statusbar
; sb
; sb
= sb
->next
)
238 /* Ignore every statusbar after me that is in the same position */
244 else if(ignore
&& statusbar
->position
== sb
->position
)
249 switch(statusbar
->position
)
252 area
.x
+= statusbar
->height
;
259 switch(statusbar
->position
)
262 area
.x
-= statusbar
->height
;
269 switch(statusbar
->position
)
272 area
.y
+= sb
->height
;
276 area
.height
-= sb
->height
;
277 area
.y
+= sb
->height
;
284 switch(statusbar
->position
)
287 area
.y
-= sb
->height
;
291 area
.height
-= sb
->height
;
302 switch(statusbar
->position
)
306 if(!statusbar
->width_user
)
307 statusbar
->width
= area
.height
;
309 simplewindow_new(globalconf
.connection
, statusbar
->phys_screen
, 0, 0,
310 statusbar
->height
, statusbar
->width
, 0);
311 s
= xutil_screen_get(globalconf
.connection
, statusbar
->phys_screen
);
312 /* we need a new pixmap this way [ ] to render */
313 dw
= xcb_generate_id(globalconf
.connection
);
314 xcb_create_pixmap(globalconf
.connection
,
315 s
->root_depth
, dw
, s
->root
,
316 statusbar
->width
, statusbar
->height
);
317 statusbar
->ctx
= draw_context_new(globalconf
.connection
,
318 statusbar
->phys_screen
,
322 &statusbar
->colors
.fg
,
323 &statusbar
->colors
.bg
);
326 if(!statusbar
->width_user
)
327 statusbar
->width
= area
.width
;
329 simplewindow_new(globalconf
.connection
, statusbar
->phys_screen
, 0, 0,
330 statusbar
->width
, statusbar
->height
, 0);
331 statusbar
->ctx
= draw_context_new(globalconf
.connection
,
332 statusbar
->phys_screen
,
335 statusbar
->sw
->pixmap
,
336 &statusbar
->colors
.fg
,
337 &statusbar
->colors
.bg
);
341 switch(statusbar
->position
)
344 switch(statusbar
->align
)
347 simplewindow_move(statusbar
->sw
, area
.x
, area
.y
);
350 simplewindow_move(statusbar
->sw
,
351 area
.x
+ area
.width
- statusbar
->width
, area
.y
);
354 simplewindow_move(statusbar
->sw
,
355 area
.x
+ (area
.width
- statusbar
->width
) / 2, area
.y
);
360 switch(statusbar
->align
)
363 simplewindow_move(statusbar
->sw
,
364 area
.x
, (area
.y
+ area
.height
) - statusbar
->height
);
367 simplewindow_move(statusbar
->sw
,
368 area
.x
+ area
.width
- statusbar
->width
,
369 (area
.y
+ area
.height
) - statusbar
->height
);
372 simplewindow_move(statusbar
->sw
,
373 area
.x
+ (area
.width
- statusbar
->width
) / 2,
374 (area
.y
+ area
.height
) - statusbar
->height
);
379 switch(statusbar
->align
)
382 simplewindow_move(statusbar
->sw
, area
.x
,
383 (area
.y
+ area
.height
) - statusbar
->sw
->geometry
.height
);
386 simplewindow_move(statusbar
->sw
, area
.x
, area
.y
);
389 simplewindow_move(statusbar
->sw
, area
.x
, (area
.y
+ area
.height
- statusbar
->width
) / 2);
393 switch(statusbar
->align
)
396 simplewindow_move(statusbar
->sw
, area
.x
+ area
.width
- statusbar
->height
, area
.y
);
399 simplewindow_move(statusbar
->sw
, area
.x
+ area
.width
- statusbar
->height
,
400 area
.y
+ area
.height
- statusbar
->width
);
403 simplewindow_move(statusbar
->sw
, area
.x
+ area
.width
- statusbar
->height
,
404 (area
.y
+ area
.height
- statusbar
->width
) / 2);
410 xcb_map_window(globalconf
.connection
, statusbar
->sw
->window
);
412 /* Set need update */
413 statusbar
->need_update
= true;
416 /** Convert a statusbar to a printable string.
417 * \param L The Lua VM state.
420 * \lvalue A statusbar.
423 luaA_statusbar_tostring(lua_State
*L
)
425 statusbar_t
**p
= luaA_checkudata(L
, 1, "statusbar");
426 lua_pushfstring(L
, "[statusbar udata(%p) name(%s)]", *p
, (*p
)->name
);
430 /** Create a new statusbar.
431 * \param L The Lua VM state.
434 * \lparam A table with at least a name attribute. Optionaly defined values are:
435 * position, align, fg, bg, width and height.
436 * \lreturn A brand new statusbar.
439 luaA_statusbar_new(lua_State
*L
)
444 xcolor_init_request_t reqs
[2];
445 int8_t i
, reqs_nbr
= -1;
447 luaA_checktable(L
, 2);
449 if(!(buf
= luaA_getopt_string(L
, 2, "name", NULL
)))
450 luaL_error(L
, "object statusbar must have a name");
452 sb
= p_new(statusbar_t
, 1);
454 sb
->name
= a_strdup(buf
);
456 sb
->colors
.fg
= globalconf
.colors
.fg
;
457 if((buf
= luaA_getopt_lstring(L
, 2, "fg", NULL
, &len
)))
458 reqs
[++reqs_nbr
] = xcolor_init_unchecked(globalconf
.connection
,
460 globalconf
.default_screen
,
463 sb
->colors
.bg
= globalconf
.colors
.bg
;
464 if((buf
= luaA_getopt_lstring(L
, 2, "bg", NULL
, &len
)))
465 reqs
[++reqs_nbr
] = xcolor_init_unchecked(globalconf
.connection
,
467 globalconf
.default_screen
,
470 buf
= luaA_getopt_lstring(L
, 2, "align", "left", &len
);
471 sb
->align
= draw_align_fromstr(buf
, len
);
473 sb
->width
= luaA_getopt_number(L
, 2, "width", 0);
475 sb
->width_user
= true;
476 sb
->height
= luaA_getopt_number(L
, 2, "height", 0);
478 /* 1.5 as default factor, it fits nice but no one knows why */
479 sb
->height
= 1.5 * globalconf
.font
->height
;
481 buf
= luaA_getopt_lstring(L
, 2, "position", "top", &len
);
482 sb
->position
= position_fromstr(buf
, len
);
484 sb
->screen
= SCREEN_UNDEF
;
486 for(i
= 0; i
<= reqs_nbr
; i
++)
487 xcolor_init_reply(globalconf
.connection
, reqs
[i
]);
489 return luaA_statusbar_userdata_new(L
, sb
);
492 /** Statusbar object.
493 * \param L The Lua VM state.
494 * \return The number of elements pushed on stack.
496 * \lfield screen Screen number.
497 * \lfield align The alignment.
498 * \lfield fg Foreground color.
499 * \lfield bg Background color.
500 * \lfield position The position.
503 luaA_statusbar_index(lua_State
*L
)
506 statusbar_t
**statusbar
= luaA_checkudata(L
, 1, "statusbar");
507 const char *attr
= luaL_checklstring(L
, 2, &len
);
509 if(luaA_usemetatable(L
, 1, 2))
512 switch(a_tokenize(attr
, len
))
515 if((*statusbar
)->screen
== SCREEN_UNDEF
)
517 lua_pushnumber(L
, (*statusbar
)->screen
+ 1);
520 lua_pushstring(L
, draw_align_tostr((*statusbar
)->align
));
523 luaA_pushcolor(L
, &(*statusbar
)->colors
.fg
);
526 luaA_pushcolor(L
, &(*statusbar
)->colors
.bg
);
529 lua_pushstring(L
, position_tostr((*statusbar
)->position
));
538 /** Get or set the statusbar widgets.
539 * \param L The Lua VM state.
540 * \return The number of elements pushed on stack.
542 * \lparam None, or a table of widgets to set.
543 * \lreturn The current statusbar widgets.
546 luaA_statusbar_widgets(lua_State
*L
)
548 statusbar_t
**statusbar
= luaA_checkudata(L
, 1, "statusbar");
550 if(lua_gettop(L
) == 2)
552 luaA_widget_set(L
, 2, *statusbar
, &(*statusbar
)->widgets
);
553 (*statusbar
)->need_update
= true;
556 return luaA_widget_get(L
, (*statusbar
)->widgets
);
559 /** Remove a statubar from a screen.
560 * \param statusbar Statusbar to detach from screen.
563 statusbar_remove(statusbar_t
*statusbar
)
565 if(statusbar
->screen
!= SCREEN_UNDEF
)
569 statusbar_systray_kickout(statusbar
->phys_screen
);
572 p
= statusbar
->position
;
573 statusbar
->position
= Off
;
574 statusbar_position_update(statusbar
);
575 /* restore position */
576 statusbar
->position
= p
;
578 statusbar_list_detach(&globalconf
.screens
[statusbar
->screen
].statusbar
, statusbar
);
579 globalconf
.screens
[statusbar
->screen
].need_arrange
= true;
580 statusbar
->screen
= SCREEN_UNDEF
;
581 statusbar_unref(&statusbar
);
585 /** Statusbar newindex.
586 * \param L The Lua VM state.
587 * \return The number of elements pushed on stack.
590 luaA_statusbar_newindex(lua_State
*L
)
593 statusbar_t
*s
, **statusbar
= luaA_checkudata(L
, 1, "statusbar");
594 const char *buf
, *attr
= luaL_checklstring(L
, 2, &len
);
598 switch(a_tokenize(attr
, len
))
602 statusbar_remove(*statusbar
);
605 screen
= luaL_checknumber(L
, 3) - 1;
607 luaA_checkscreen(screen
);
609 if((*statusbar
)->screen
== screen
)
610 luaL_error(L
, "this statusbar is already on screen %d",
611 (*statusbar
)->screen
+ 1);
613 /* Check for uniq name and id. */
614 for(s
= globalconf
.screens
[screen
].statusbar
; s
; s
= s
->next
)
615 if(!a_strcmp(s
->name
, (*statusbar
)->name
))
616 luaL_error(L
, "a statusbar with that name is already on screen %d\n",
619 statusbar_remove(*statusbar
);
621 (*statusbar
)->screen
= screen
;
622 (*statusbar
)->phys_screen
= screen_virttophys(screen
);
624 statusbar_list_append(&globalconf
.screens
[screen
].statusbar
, *statusbar
);
625 statusbar_ref(statusbar
);
627 /* All the other statusbar and ourselves need to be repositioned */
628 for(s
= globalconf
.screens
[screen
].statusbar
; s
; s
= s
->next
)
629 statusbar_position_update(s
);
631 ewmh_update_workarea((*statusbar
)->phys_screen
);
635 buf
= luaL_checklstring(L
, 3, &len
);
636 (*statusbar
)->align
= draw_align_fromstr(buf
, len
);
637 statusbar_position_update(*statusbar
);
640 if((buf
= luaL_checklstring(L
, 3, &len
)))
641 if(xcolor_init_reply(globalconf
.connection
,
642 xcolor_init_unchecked(globalconf
.connection
,
643 &(*statusbar
)->colors
.fg
,
644 globalconf
.default_screen
,
647 if((*statusbar
)->ctx
)
648 (*statusbar
)->ctx
->fg
= (*statusbar
)->colors
.fg
;
649 (*statusbar
)->need_update
= true;
653 if((buf
= luaL_checklstring(L
, 3, &len
)))
654 if(xcolor_init_reply(globalconf
.connection
,
655 xcolor_init_unchecked(globalconf
.connection
,
656 &(*statusbar
)->colors
.bg
,
657 globalconf
.default_screen
, buf
, len
)))
659 if((*statusbar
)->ctx
)
660 (*statusbar
)->ctx
->bg
= (*statusbar
)->colors
.bg
;
662 (*statusbar
)->need_update
= true;
666 buf
= luaL_checklstring(L
, 3, &len
);
667 p
= position_fromstr(buf
, len
);
668 if(p
!= (*statusbar
)->position
)
670 (*statusbar
)->position
= p
;
671 if((*statusbar
)->screen
!= SCREEN_UNDEF
)
673 for(s
= globalconf
.screens
[(*statusbar
)->screen
].statusbar
; s
; s
= s
->next
)
674 statusbar_position_update(s
);
675 ewmh_update_workarea((*statusbar
)->phys_screen
);
686 const struct luaL_reg awesome_statusbar_methods
[] =
688 { "__call", luaA_statusbar_new
},
691 const struct luaL_reg awesome_statusbar_meta
[] =
693 { "widgets", luaA_statusbar_widgets
},
694 { "__index", luaA_statusbar_index
},
695 { "__newindex", luaA_statusbar_newindex
},
696 { "__gc", luaA_statusbar_gc
},
697 { "__eq", luaA_statusbar_eq
},
698 { "__tostring", luaA_statusbar_tostring
},
702 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80