[all] Implement an atom cache in xutil as an ordered linked-list
[awesome.git] / titlebar.c
blobd2f8508da2f872a87635e627eeca0eddc2db5d2a
1 /*
2 * titlebar.c - titlebar management
4 * Copyright © 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>
23 #include <xcb/xcb_aux.h>
25 #include <math.h>
27 #include "titlebar.h"
28 #include "client.h"
29 #include "screen.h"
30 #include "layouts/floating.h"
32 extern AwesomeConf globalconf;
34 static char *
35 titlebar_text(client_t *c)
37 char *text;
39 if(globalconf.focus->client == c)
40 text = c->titlebar.text_focus;
41 else if(c->isurgent)
42 text = c->titlebar.text_urgent;
43 else
44 text = c->titlebar.text_normal;
46 return client_markup_parse(c, text, a_strlen(text));
49 static inline area_t
50 titlebar_size(client_t *c)
52 return draw_text_extents(globalconf.connection, globalconf.default_screen,
53 globalconf.screens[c->screen].styles.normal.font, titlebar_text(c));
56 /** Initialize a titlebar: create the simple_window_t.
57 * We still need to update its geometry to have it placed correctly.
58 * \param c the client
60 void
61 titlebar_init(client_t *c)
63 int width = 0, height = 0;
65 if(!c->titlebar.height)
66 c->titlebar.height = MAX(MAX(draw_text_extents(globalconf.connection, globalconf.default_screen,
67 globalconf.screens[c->screen].styles.focus.font,
68 client_markup_parse(c, c->titlebar.text_focus, a_strlen(c->titlebar.text_focus))).height,
69 draw_text_extents(globalconf.connection, globalconf.default_screen,
70 globalconf.screens[c->screen].styles.normal.font,
71 client_markup_parse(c, c->titlebar.text_normal, a_strlen(c->titlebar.text_normal))).height),
72 draw_text_extents(globalconf.connection, globalconf.default_screen,
73 globalconf.screens[c->screen].styles.urgent.font,
74 client_markup_parse(c, c->titlebar.text_urgent, a_strlen(c->titlebar.text_urgent))).height);
76 switch(c->titlebar.position)
78 case Off:
79 return;
80 default:
81 c->titlebar.position = Off;
82 return;
83 case Top:
84 case Bottom:
85 if(!c->titlebar.width)
86 width = c->geometry.width + 2 * c->border;
87 else
88 width = MIN(c->titlebar.width, c->geometry.width);
89 height = c->titlebar.height;
90 break;
91 case Left:
92 case Right:
93 if(!c->titlebar.width)
94 height = c->geometry.height + 2 * c->border;
95 else
96 height = MIN(c->titlebar.width, c->geometry.height);
97 width = c->titlebar.height;
98 break;
100 c->titlebar.sw = simplewindow_new(globalconf.connection,
101 c->phys_screen, 0, 0,
102 width, height, 0);
103 xcb_map_window(globalconf.connection, c->titlebar.sw->window);
106 /** Add the titlebar geometry to a geometry.
107 * \param t the titlebar
108 * \param geometry the geometry
109 * \return a new geometry bigger if the titlebar is visible
111 area_t
112 titlebar_geometry_add(titlebar_t *t, area_t geometry)
114 if(!t->sw)
115 return geometry;
117 switch(t->position)
119 case Top:
120 geometry.y -= t->sw->geometry.height;
121 geometry.height += t->sw->geometry.height;
122 break;
123 case Bottom:
124 geometry.height += t->sw->geometry.height;
125 break;
126 case Left:
127 geometry.x -= t->sw->geometry.width;
128 geometry.width += t->sw->geometry.width;
129 break;
130 case Right:
131 geometry.width += t->sw->geometry.width;
132 break;
133 default:
134 break;
137 return geometry;
140 /** Remove the titlebar geometry to a geometry.
141 * \param t the titlebar
142 * \param geometry the geometry
143 * \return a new geometry smaller if the titlebar is visible
145 area_t
146 titlebar_geometry_remove(titlebar_t *t, area_t geometry)
148 if(!t->sw)
149 return geometry;
151 switch(t->position)
153 case Top:
154 geometry.y += t->sw->geometry.height;
155 geometry.height -= t->sw->geometry.height;
156 break;
157 case Bottom:
158 geometry.height -= t->sw->geometry.height;
159 break;
160 case Left:
161 geometry.x += t->sw->geometry.width;
162 geometry.width -= t->sw->geometry.width;
163 break;
164 case Right:
165 geometry.width -= t->sw->geometry.width;
166 break;
167 default:
168 break;
171 return geometry;
174 /** Draw the titlebar content.
175 * \param c the client
177 void
178 titlebar_draw(client_t *c)
180 xcb_drawable_t dw = 0;
181 draw_context_t *ctx;
182 area_t geometry;
183 xcb_screen_t *s;
184 char *text;
185 style_t *style;
187 if(!c->titlebar.sw)
188 return;
190 s = xcb_aux_get_screen(globalconf.connection,
191 c->titlebar.sw->phys_screen);
193 switch(c->titlebar.position)
195 case Off:
196 return;
197 case Right:
198 case Left:
199 dw = xcb_generate_id(globalconf.connection);
200 xcb_create_pixmap(globalconf.connection, s->root_depth,
202 s->root,
203 c->titlebar.sw->geometry.height,
204 c->titlebar.sw->geometry.width);
205 ctx = draw_context_new(globalconf.connection, c->titlebar.sw->phys_screen,
206 c->titlebar.sw->geometry.height,
207 c->titlebar.sw->geometry.width,
208 dw);
209 geometry.width = c->titlebar.sw->geometry.height;
210 geometry.height = c->titlebar.sw->geometry.width;
211 break;
212 default:
213 ctx = draw_context_new(globalconf.connection, c->titlebar.sw->phys_screen,
214 c->titlebar.sw->geometry.width,
215 c->titlebar.sw->geometry.height,
216 c->titlebar.sw->drawable);
217 geometry = c->titlebar.sw->geometry;
218 break;
221 text = titlebar_text(c);
222 geometry.x = geometry.y = 0;
223 style = client_style_get(c);
224 draw_text(ctx, geometry, text, style);
225 p_delete(&text);
227 switch(c->titlebar.position)
229 case Left:
230 draw_rotate(ctx, c->titlebar.sw->drawable, ctx->height, ctx->width,
231 - M_PI_2, 0, c->titlebar.sw->geometry.height);
232 xcb_free_pixmap(globalconf.connection, dw);
233 break;
234 case Right:
235 draw_rotate(ctx, c->titlebar.sw->drawable, ctx->height, ctx->width,
236 M_PI_2, c->titlebar.sw->geometry.width, 0);
237 xcb_free_pixmap(globalconf.connection, dw);
238 default:
239 break;
242 simplewindow_refresh_drawable(c->titlebar.sw);
244 draw_context_delete(&ctx);
247 /** Update the titlebar geometry for a floating client.
248 * \param c the client
250 void
251 titlebar_update_geometry_floating(client_t *c)
253 int width, x_offset = 0, y_offset = 0;
255 if(!c->titlebar.sw)
256 return;
258 switch(c->titlebar.position)
260 default:
261 return;
262 case Off:
263 return;
264 case Top:
265 if(!c->titlebar.width)
266 width = c->geometry.width + 2 * c->border;
267 else
268 width = MIN(c->titlebar.width, c->geometry.width);
269 switch(c->titlebar.align)
271 default:
272 break;
273 case AlignRight:
274 x_offset = 2 * c->border + c->geometry.width - width;
275 break;
276 case AlignCenter:
277 x_offset = (c->geometry.width - width) / 2;
278 break;
280 simplewindow_move_resize(c->titlebar.sw,
281 c->geometry.x + x_offset,
282 c->geometry.y - c->titlebar.sw->geometry.height,
283 width,
284 c->titlebar.sw->geometry.height);
285 break;
286 case Bottom:
287 if(!c->titlebar.width)
288 width = c->geometry.width + 2 * c->border;
289 else
290 width = MIN(c->titlebar.width, c->geometry.width);
291 switch(c->titlebar.align)
293 default:
294 break;
295 case AlignRight:
296 x_offset = 2 * c->border + c->geometry.width - width;
297 break;
298 case AlignCenter:
299 x_offset = (c->geometry.width - width) / 2;
300 break;
302 simplewindow_move_resize(c->titlebar.sw,
303 c->geometry.x + x_offset,
304 c->geometry.y + c->geometry.height + 2 * c->border,
305 width,
306 c->titlebar.sw->geometry.height);
307 break;
308 case Left:
309 if(!c->titlebar.width)
310 width = c->geometry.height + 2 * c->border;
311 else
312 width = MIN(c->titlebar.width, c->geometry.height);
313 switch(c->titlebar.align)
315 default:
316 break;
317 case AlignRight:
318 y_offset = 2 * c->border + c->geometry.height - width;
319 break;
320 case AlignCenter:
321 y_offset = (c->geometry.height - width) / 2;
322 break;
324 simplewindow_move_resize(c->titlebar.sw,
325 c->geometry.x - c->titlebar.sw->geometry.width,
326 c->geometry.y + y_offset,
327 c->titlebar.sw->geometry.width,
328 width);
329 break;
330 case Right:
331 if(!c->titlebar.width)
332 width = c->geometry.height + 2 * c->border;
333 else
334 width = MIN(c->titlebar.width, c->geometry.height);
335 switch(c->titlebar.align)
337 default:
338 break;
339 case AlignRight:
340 y_offset = 2 * c->border + c->geometry.height - width;
341 break;
342 case AlignCenter:
343 y_offset = (c->geometry.height - width) / 2;
344 break;
346 simplewindow_move_resize(c->titlebar.sw,
347 c->geometry.x + c->geometry.width + 2 * c->border,
348 c->geometry.y + y_offset,
349 c->titlebar.sw->geometry.width,
350 width);
351 break;
354 titlebar_draw(c);
358 /** Update the titlebar geometry for a tiled client.
359 * \param c the client
360 * \param geometry the geometry the client will receive
362 void
363 titlebar_update_geometry(client_t *c, area_t geometry)
365 int width, x_offset = 0 , y_offset = 0;
367 if(!c->titlebar.sw)
368 return;
370 switch(c->titlebar.position)
372 default:
373 return;
374 case Off:
375 return;
376 case Top:
377 if(!c->titlebar.width)
378 width = geometry.width + 2 * c->border;
379 else
380 width = MIN(c->titlebar.width, geometry.width);
381 switch(c->titlebar.align)
383 default:
384 break;
385 case AlignRight:
386 x_offset = 2 * c->border + geometry.width - width;
387 break;
388 case AlignCenter:
389 x_offset = (geometry.width - width) / 2;
390 break;
392 simplewindow_move_resize(c->titlebar.sw,
393 geometry.x + x_offset,
394 geometry.y,
395 width,
396 c->titlebar.sw->geometry.height);
397 break;
398 case Bottom:
399 if(!c->titlebar.width)
400 width = geometry.width + 2 * c->border;
401 else
402 width = MIN(c->titlebar.width, geometry.width);
403 switch(c->titlebar.align)
405 default:
406 break;
407 case AlignRight:
408 x_offset = 2 * c->border + geometry.width - width;
409 break;
410 case AlignCenter:
411 x_offset = (geometry.width - width) / 2;
412 break;
414 simplewindow_move_resize(c->titlebar.sw,
415 geometry.x + x_offset,
416 geometry.y + geometry.height
417 - c->titlebar.sw->geometry.height + 2 * c->border,
418 width,
419 c->titlebar.sw->geometry.height);
420 break;
421 case Left:
422 if(!c->titlebar.width)
423 width = geometry.height + 2 * c->border;
424 else
425 width = MIN(c->titlebar.width, geometry.height);
426 switch(c->titlebar.align)
428 default:
429 break;
430 case AlignRight:
431 y_offset = 2 * c->border + geometry.height - width;
432 break;
433 case AlignCenter:
434 y_offset = (geometry.height - width) / 2;
435 break;
437 simplewindow_move_resize(c->titlebar.sw,
438 geometry.x,
439 geometry.y + y_offset,
440 c->titlebar.sw->geometry.width,
441 width);
442 break;
443 case Right:
444 if(!c->titlebar.width)
445 width = geometry.height + 2 * c->border;
446 else
447 width = MIN(c->titlebar.width, geometry.height);
448 switch(c->titlebar.align)
450 default:
451 break;
452 case AlignRight:
453 y_offset = 2 * c->border + geometry.height - width;
454 break;
455 case AlignCenter:
456 y_offset = (geometry.height - width) / 2;
457 break;
459 simplewindow_move_resize(c->titlebar.sw,
460 geometry.x + geometry.width
461 - c->titlebar.sw->geometry.width + 2 * c->border,
462 geometry.y + y_offset,
463 c->titlebar.sw->geometry.width,
464 width);
465 break;
468 titlebar_draw(c);
471 void
472 titlebar_position_set(titlebar_t *t, position_t p)
474 if(!t->sw)
475 return;
477 if((t->position = p))
478 xcb_map_window(globalconf.connection, t->sw->window);
479 else
480 xcb_unmap_window(globalconf.connection, t->sw->window);
483 /** Toggle the visibility of the focused window's titlebar.
484 * \param screen screen number (unused)
485 * \param arg unused argument
486 * \ingroup ui_callback
488 void
489 uicb_client_toggletitlebar(int screen __attribute__ ((unused)), char *arg __attribute__ ((unused)))
491 client_t *c = globalconf.focus->client;
493 if(!c || !c->titlebar.sw)
494 return;
496 if(!c->titlebar.position)
497 titlebar_position_set(&c->titlebar, c->titlebar.dposition);
498 else
499 titlebar_position_set(&c->titlebar, Off);
501 if(c->isfloating || layout_get_current(screen)->arrange == layout_floating)
502 titlebar_update_geometry_floating(c);
503 else
504 globalconf.screens[c->screen].need_arrange = true;
507 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80