textbox width is limited to unused space
[awesome.git] / statusbar.c
blob71dd6d0cf94d9a9ef4c7f5912331a6e2a6d23146
1 /*
2 * statusbar.c - statusbar functions
4 * Copyright © 2007 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 <stdio.h>
23 #include <math.h>
25 #include "statusbar.h"
26 #include "screen.h"
27 #include "tag.h"
28 #include "widget.h"
29 #include "common/util.h"
31 extern AwesomeConf globalconf;
33 static void
34 statusbar_update_position(Statusbar *statusbar)
36 Area area;
38 XMapRaised(globalconf.display, statusbar->window);
40 /* Top and Bottom Statusbar have prio */
41 if(statusbar->position == Top || statusbar->position == Bottom)
42 area = get_screen_area(statusbar->screen,
43 NULL,
44 &globalconf.screens[statusbar->screen].padding);
45 else
46 area = get_screen_area(statusbar->screen,
47 globalconf.screens[statusbar->screen].statusbar,
48 &globalconf.screens[statusbar->screen].padding);
50 switch(statusbar->position)
52 case Top:
53 XMoveWindow(globalconf.display, statusbar->window,
54 area.x, area.y);
55 break;
56 case Bottom:
57 XMoveWindow(globalconf.display, statusbar->window,
58 area.x, area.height - statusbar->height);
59 break;
60 case Left:
61 XMoveWindow(globalconf.display, statusbar->window,
62 area.x - statusbar->height, (area.y + area.height) - statusbar->width);
63 break;
64 case Right:
65 XMoveWindow(globalconf.display, statusbar->window,
66 area.x + area.width, area.y);
67 break;
68 case Off:
69 XUnmapWindow(globalconf.display, statusbar->window);
70 break;
74 static void
75 statusbar_draw(Statusbar *statusbar)
77 int phys_screen = get_phys_screen(statusbar->screen);
78 Widget *widget, *last_drawn = NULL;
79 int left = 0, right = 0;
80 Area rectangle = { 0, 0, 0, 0 };
82 /* don't waste our time */
83 if(statusbar->position == Off)
84 return;
86 XFreePixmap(globalconf.display, statusbar->drawable);
88 DrawCtx *ctx = draw_get_context(phys_screen,
89 statusbar->width,
90 statusbar->height);
92 rectangle.width = statusbar->width;
93 rectangle.height = statusbar->height;
94 draw_rectangle(ctx, rectangle, True,
95 globalconf.screens[statusbar->screen].colors_normal[ColBG]);
97 for(widget = statusbar->widgets; widget; widget = widget->next)
98 if (widget->alignment == AlignLeft)
100 widget->cache.needs_update = False;
101 left += widget->draw(widget, ctx, left, (left + right));
104 /* renders right widget from last to first */
105 for(widget = statusbar->widgets; widget; widget = widget->next)
106 if (widget->alignment == AlignRight && last_drawn == widget->next)
108 widget->cache.needs_update = False;
109 right += widget->draw(widget, ctx, right, (left + right));
110 last_drawn = widget;
111 widget = statusbar->widgets;
114 for(widget = statusbar->widgets; widget; widget = widget->next)
115 if (widget->alignment == AlignFlex)
117 widget->cache.needs_update = False;
118 left += widget->draw(widget, ctx, left, (left + right));
121 if(statusbar->position == Right
122 || statusbar->position == Left)
124 if(statusbar->position == Right)
125 statusbar->drawable = draw_rotate(ctx, phys_screen, M_PI_2, statusbar->height, 0);
126 else
127 statusbar->drawable = draw_rotate(ctx, phys_screen, - M_PI_2, 0, statusbar->width);
129 draw_free_context(ctx);
131 else
133 statusbar->drawable = ctx->drawable;
134 /* just delete the struct, don't delete the drawable */
135 p_delete(&ctx);
138 statusbar_display(statusbar);
141 void
142 statusbar_display(Statusbar *statusbar)
144 int phys_screen = get_phys_screen(statusbar->screen);
146 /* don't waste our time */
147 if(statusbar->position == Off)
148 return;
150 if(statusbar->position == Right
151 || statusbar->position == Left)
152 XCopyArea(globalconf.display, statusbar->drawable,
153 statusbar->window,
154 DefaultGC(globalconf.display, phys_screen), 0, 0,
155 statusbar->height,
156 statusbar->width, 0, 0);
157 else
158 XCopyArea(globalconf.display, statusbar->drawable,
159 statusbar->window,
160 DefaultGC(globalconf.display, phys_screen), 0, 0,
161 statusbar->width, statusbar->height, 0, 0);
164 void
165 statusbar_preinit(Statusbar *statusbar)
167 Widget *widget;
169 if(statusbar->height <= 0)
171 /* 1.5 as default factor, it fits nice but no one know why */
172 statusbar->height = globalconf.screens[statusbar->screen].font->height * 1.5;
174 for(widget = statusbar->widgets; widget; widget = widget->next)
175 if(widget->font)
176 statusbar->height = MAX(statusbar->height, widget->font->height * 1.5);
180 void
181 statusbar_init(Statusbar *statusbar)
183 Statusbar *sb;
184 XSetWindowAttributes wa;
185 int phys_screen = get_phys_screen(statusbar->screen);
186 Area area = get_screen_area(statusbar->screen,
187 globalconf.screens[statusbar->screen].statusbar,
188 &globalconf.screens[statusbar->screen].padding);
191 /* Top and Bottom Statusbar have prio */
192 for(sb = globalconf.screens[statusbar->screen].statusbar; sb; sb = sb->next)
193 switch(sb->position)
195 case Left:
196 case Right:
197 area.width += sb->height;
198 break;
199 default:
200 break;
203 if(statusbar->width <= 0)
205 if(statusbar->position == Right || statusbar->position == Left)
206 statusbar->width = area.height;
207 else
208 statusbar->width = area.width;
211 wa.event_mask = SubstructureRedirectMask | SubstructureNotifyMask
212 | EnterWindowMask | LeaveWindowMask | StructureNotifyMask;
213 wa.cursor = globalconf.cursor[CurNormal];
214 wa.override_redirect = 1;
215 wa.background_pixmap = ParentRelative;
216 wa.event_mask = ButtonPressMask | ExposureMask;
217 if(statusbar->dposition == Right || statusbar->dposition == Left)
218 statusbar->window = XCreateWindow(globalconf.display,
219 RootWindow(globalconf.display,
220 phys_screen),
221 0, 0,
222 statusbar->height,
223 statusbar->width,
225 DefaultDepth(globalconf.display,
226 phys_screen),
227 CopyFromParent,
228 DefaultVisual(globalconf.display,
229 phys_screen),
230 CWOverrideRedirect |
231 CWBackPixmap |
232 CWEventMask,
233 &wa);
234 else
235 statusbar->window = XCreateWindow(globalconf.display,
236 RootWindow(globalconf.display,
237 phys_screen),
238 0, 0,
239 statusbar->width,
240 statusbar->height,
242 DefaultDepth(globalconf.display,
243 phys_screen),
244 CopyFromParent,
245 DefaultVisual(globalconf.display,
246 phys_screen),
247 CWOverrideRedirect |
248 CWBackPixmap |
249 CWEventMask,
250 &wa);
252 statusbar->drawable = XCreatePixmap(globalconf.display,
253 RootWindow(globalconf.display, phys_screen),
254 statusbar->width, statusbar->height,
255 DefaultDepth(globalconf.display, phys_screen));
258 XDefineCursor(globalconf.display,
259 statusbar->window,
260 globalconf.cursor[CurNormal]);
262 widget_calculate_alignments(statusbar->widgets);
264 statusbar_update_position(statusbar);
265 XMapRaised(globalconf.display, statusbar->window);
267 statusbar_draw(statusbar);
270 void
271 statusbar_refresh()
273 int screen;
274 Statusbar *statusbar;
275 Widget *widget;
277 for(screen = 0; screen < globalconf.nscreens; screen++)
278 for(statusbar = globalconf.screens[screen].statusbar;
279 statusbar;
280 statusbar = statusbar->next)
281 for(widget = statusbar->widgets; widget; widget = widget->next)
282 if(widget->cache.needs_update)
284 statusbar_draw(statusbar);
285 break;
289 Position
290 statusbar_get_position_from_str(const char *pos)
292 if(!a_strncmp(pos, "off", 3))
293 return Off;
294 else if(!a_strncmp(pos, "bottom", 6))
295 return Bottom;
296 else if(!a_strncmp(pos, "right", 5))
297 return Right;
298 else if(!a_strncmp(pos, "left", 4))
299 return Left;
300 return Top;
303 static Statusbar *
304 get_statusbar_byname(int screen, const char *name)
306 Statusbar *sb;
308 for(sb = globalconf.screens[screen].statusbar; sb; sb = sb->next)
309 if(!a_strcmp(sb->name, name))
310 return sb;
312 return NULL;
315 static void
316 statusbar_toggle(Statusbar *statusbar)
318 if(statusbar->position == Off)
319 statusbar->position = (statusbar->dposition == Off) ? Top : statusbar->dposition;
320 else
321 statusbar->position = Off;
323 statusbar_update_position(statusbar);
324 globalconf.screens[statusbar->screen].need_arrange = True;
327 /** Toggle statusbar
328 * \param screen Screen ID
329 * \param arg statusbar name
330 * \ingroup ui_callback
332 void
333 uicb_statusbar_toggle(int screen, char *arg)
335 Statusbar *sb = get_statusbar_byname(screen, arg);
337 if(sb)
338 statusbar_toggle(sb);
339 else
340 for(sb = globalconf.screens[screen].statusbar; sb; sb = sb->next)
341 statusbar_toggle(sb);
344 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80