tabulous: fixed deprecated focus_get/set calls
[awesome.git] / statusbar.c
blob589350709abf8a2b452bbe4fe6062ba10be55728
1 /*
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.
22 #include <xcb/xcb.h>
24 #include "client.h"
25 #include "statusbar.h"
26 #include "screen.h"
27 #include "widget.h"
28 #include "ewmh.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.
39 static void
40 statusbar_systray_kickout(int phys_screen)
42 xembed_window_t *em;
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,
48 XCB_CONFIG_WINDOW_X
49 | XCB_CONFIG_WINDOW_Y,
50 config_win_vals_off);
53 static void
54 statusbar_systray_refresh(statusbar_t *statusbar)
56 widget_node_t *systray;
58 if(statusbar->screen == SCREEN_UNDEF)
59 return;
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 };
67 xembed_window_t *em;
68 position_t pos;
70 if(statusbar->position
71 && systray->widget->isvisible)
73 pos = statusbar->position;
74 /* width */
75 config_win_vals[2] = systray->area.height;
76 /* height */
77 config_win_vals[3] = systray->area.height;
79 else
80 /* hide */
81 pos = Off;
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);
87 switch(pos)
89 case Left:
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,
100 XCB_CONFIG_WINDOW_X
101 | XCB_CONFIG_WINDOW_Y
102 | XCB_CONFIG_WINDOW_WIDTH
103 | XCB_CONFIG_WINDOW_HEIGHT,
104 config_win_vals);
105 config_win_vals[1] -= config_win_vals[3];
107 else
108 xcb_configure_window(globalconf.connection, em->win,
109 XCB_CONFIG_WINDOW_X
110 | XCB_CONFIG_WINDOW_Y,
111 config_win_vals_off);
113 client_stack();
114 break;
115 case Right:
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,
125 XCB_CONFIG_WINDOW_X
126 | XCB_CONFIG_WINDOW_Y
127 | XCB_CONFIG_WINDOW_WIDTH
128 | XCB_CONFIG_WINDOW_HEIGHT,
129 config_win_vals);
130 config_win_vals[1] += config_win_vals[3];
132 else
133 xcb_configure_window(globalconf.connection, em->win,
134 XCB_CONFIG_WINDOW_X
135 | XCB_CONFIG_WINDOW_Y,
136 config_win_vals_off);
138 client_stack();
139 break;
140 case Top:
141 case Bottom:
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,
152 XCB_CONFIG_WINDOW_X
153 | XCB_CONFIG_WINDOW_Y
154 | XCB_CONFIG_WINDOW_WIDTH
155 | XCB_CONFIG_WINDOW_HEIGHT,
156 config_win_vals);
157 config_win_vals[0] += config_win_vals[2];
159 else
160 xcb_configure_window(globalconf.connection, em->win,
161 XCB_CONFIG_WINDOW_X
162 | XCB_CONFIG_WINDOW_Y,
163 config_win_vals_off);
165 client_stack();
166 break;
167 default:
168 statusbar_systray_kickout(statusbar->phys_screen);
169 break;
171 break;
175 /** Draw a statusbar.
176 * \param statusbar The statusbar to draw.
178 static void
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.
198 void
199 statusbar_refresh(void)
201 int screen;
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
211 * create them back.
212 * \param statusbar The statusbar.
214 void
215 statusbar_position_update(statusbar_t *statusbar)
217 statusbar_t *sb;
218 area_t area;
219 xcb_pixmap_t dw;
220 xcb_screen_t *s = NULL;
221 bool ignore = false;
223 globalconf.screens[statusbar->screen].need_arrange = true;
225 simplewindow_delete(&statusbar->sw);
226 draw_context_delete(&statusbar->ctx);
228 if(statusbar->position == Off)
229 return;
231 area = screen_area_get(&globalconf.screens[statusbar->screen].geometry,
232 NULL,
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 */
239 if(statusbar == sb)
241 ignore = true;
242 continue;
244 else if(ignore && statusbar->position == sb->position)
245 continue;
246 switch(sb->position)
248 case Left:
249 switch(statusbar->position)
251 case Left:
252 area.x += statusbar->height;
253 break;
254 default:
255 break;
257 break;
258 case Right:
259 switch(statusbar->position)
261 case Right:
262 area.x -= statusbar->height;
263 break;
264 default:
265 break;
267 break;
268 case Top:
269 switch(statusbar->position)
271 case Top:
272 area.y += sb->height;
273 break;
274 case Left:
275 case Right:
276 area.height -= sb->height;
277 area.y += sb->height;
278 break;
279 default:
280 break;
282 break;
283 case Bottom:
284 switch(statusbar->position)
286 case Bottom:
287 area.y -= sb->height;
288 break;
289 case Left:
290 case Right:
291 area.height -= sb->height;
292 break;
293 default:
294 break;
296 break;
297 default:
298 break;
302 switch(statusbar->position)
304 case Right:
305 case Left:
306 if(!statusbar->width_user)
307 statusbar->width = area.height;
308 statusbar->sw =
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,
319 statusbar->width,
320 statusbar->height,
322 &statusbar->colors.fg,
323 &statusbar->colors.bg);
324 break;
325 default:
326 if(!statusbar->width_user)
327 statusbar->width = area.width;
328 statusbar->sw =
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,
333 statusbar->width,
334 statusbar->height,
335 statusbar->sw->pixmap,
336 &statusbar->colors.fg,
337 &statusbar->colors.bg);
338 break;
341 switch(statusbar->position)
343 default:
344 switch(statusbar->align)
346 default:
347 simplewindow_move(statusbar->sw, area.x, area.y);
348 break;
349 case AlignRight:
350 simplewindow_move(statusbar->sw,
351 area.x + area.width - statusbar->width, area.y);
352 break;
353 case AlignCenter:
354 simplewindow_move(statusbar->sw,
355 area.x + (area.width - statusbar->width) / 2, area.y);
356 break;
358 break;
359 case Bottom:
360 switch(statusbar->align)
362 default:
363 simplewindow_move(statusbar->sw,
364 area.x, (area.y + area.height) - statusbar->height);
365 break;
366 case AlignRight:
367 simplewindow_move(statusbar->sw,
368 area.x + area.width - statusbar->width,
369 (area.y + area.height) - statusbar->height);
370 break;
371 case AlignCenter:
372 simplewindow_move(statusbar->sw,
373 area.x + (area.width - statusbar->width) / 2,
374 (area.y + area.height) - statusbar->height);
375 break;
377 break;
378 case Left:
379 switch(statusbar->align)
381 default:
382 simplewindow_move(statusbar->sw, area.x,
383 (area.y + area.height) - statusbar->sw->geometry.height);
384 break;
385 case AlignRight:
386 simplewindow_move(statusbar->sw, area.x, area.y);
387 break;
388 case AlignCenter:
389 simplewindow_move(statusbar->sw, area.x, (area.y + area.height - statusbar->width) / 2);
391 break;
392 case Right:
393 switch(statusbar->align)
395 default:
396 simplewindow_move(statusbar->sw, area.x + area.width - statusbar->height, area.y);
397 break;
398 case AlignRight:
399 simplewindow_move(statusbar->sw, area.x + area.width - statusbar->height,
400 area.y + area.height - statusbar->width);
401 break;
402 case AlignCenter:
403 simplewindow_move(statusbar->sw, area.x + area.width - statusbar->height,
404 (area.y + area.height - statusbar->width) / 2);
405 break;
407 break;
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.
419 * \luastack
420 * \lvalue A statusbar.
422 static int
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);
427 return 1;
430 /** Create a new statusbar.
431 * \param L The Lua VM state.
433 * \luastack
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.
438 static int
439 luaA_statusbar_new(lua_State *L)
441 statusbar_t *sb;
442 const char *buf;
443 size_t len;
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,
459 &sb->colors.fg,
460 globalconf.default_screen,
461 buf, len);
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,
466 &sb->colors.bg,
467 globalconf.default_screen,
468 buf, len);
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);
474 if(sb->width > 0)
475 sb->width_user = true;
476 sb->height = luaA_getopt_number(L, 2, "height", 0);
477 if(sb->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.
495 * \luastack
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.
502 static int
503 luaA_statusbar_index(lua_State *L)
505 size_t len;
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))
510 return 1;
512 switch(a_tokenize(attr, len))
514 case A_TK_SCREEN:
515 if((*statusbar)->screen == SCREEN_UNDEF)
516 return 0;
517 lua_pushnumber(L, (*statusbar)->screen + 1);
518 break;
519 case A_TK_ALIGN:
520 lua_pushstring(L, draw_align_tostr((*statusbar)->align));
521 break;
522 case A_TK_FG:
523 luaA_pushcolor(L, &(*statusbar)->colors.fg);
524 break;
525 case A_TK_BG:
526 luaA_pushcolor(L, &(*statusbar)->colors.bg);
527 break;
528 case A_TK_POSITION:
529 lua_pushstring(L, position_tostr((*statusbar)->position));
530 break;
531 default:
532 return 0;
535 return 1;
538 /** Get or set the statusbar widgets.
539 * \param L The Lua VM state.
540 * \return The number of elements pushed on stack.
541 * \luastack
542 * \lparam None, or a table of widgets to set.
543 * \lreturn The current statusbar widgets.
545 static int
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;
554 return 1;
556 return luaA_widget_get(L, (*statusbar)->widgets);
559 /** Remove a statubar from a screen.
560 * \param statusbar Statusbar to detach from screen.
562 static void
563 statusbar_remove(statusbar_t *statusbar)
565 if(statusbar->screen != SCREEN_UNDEF)
567 position_t p;
569 statusbar_systray_kickout(statusbar->phys_screen);
571 /* save position */
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.
589 static int
590 luaA_statusbar_newindex(lua_State *L)
592 size_t len;
593 statusbar_t *s, **statusbar = luaA_checkudata(L, 1, "statusbar");
594 const char *buf, *attr = luaL_checklstring(L, 2, &len);
595 position_t p;
596 int screen;
598 switch(a_tokenize(attr, len))
600 case A_TK_SCREEN:
601 if(lua_isnil(L, 3))
602 statusbar_remove(*statusbar);
603 else
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",
617 screen + 1);
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);
633 break;
634 case A_TK_ALIGN:
635 buf = luaL_checklstring(L, 3, &len);
636 (*statusbar)->align = draw_align_fromstr(buf, len);
637 statusbar_position_update(*statusbar);
638 break;
639 case A_TK_FG:
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,
645 buf, len)))
647 if((*statusbar)->ctx)
648 (*statusbar)->ctx->fg = (*statusbar)->colors.fg;
649 (*statusbar)->need_update = true;
651 break;
652 case A_TK_BG:
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;
664 break;
665 case A_TK_POSITION:
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);
678 break;
679 default:
680 return 0;
683 return 0;
686 const struct luaL_reg awesome_statusbar_methods[] =
688 { "__call", luaA_statusbar_new },
689 { NULL, NULL }
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 },
699 { NULL, NULL },
702 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80