Properly die when the X server dies
[awesome.git] / titlebar.c
blobe09abcfb52965f557191c104067cd7b84ae18f47
1 /*
2 * titlebar.c - titlebar management
4 * Copyright © 2008-2009 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 "titlebar.h"
25 #include "client.h"
26 #include "widget.h"
27 #include "wibox.h"
28 #include "screen.h"
29 #include "luaa.h"
31 /** Get a client by its titlebar.
32 * \param titlebar The titlebar.
33 * \return A client.
35 client_t *
36 client_getbytitlebar(wibox_t *titlebar)
38 foreach(c, globalconf.clients)
39 if((*c)->titlebar == titlebar)
40 return *c;
42 return NULL;
45 /** Get a client by its titlebar window.
46 * \param win The window.
47 * \return A client.
49 client_t *
50 client_getbytitlebarwin(xcb_window_t win)
52 foreach(c, globalconf.clients)
53 if((*c)->titlebar && (*c)->titlebar->window == win)
54 return *c;
56 return NULL;
59 /** Move a titlebar out of the viewport.
60 * \param titlebar The titlebar.
62 void
63 titlebar_ban(wibox_t *titlebar)
65 /* Do it manually because client geometry remains unchanged. */
66 if(titlebar && !titlebar->isbanned)
68 client_t *c;
70 if(titlebar->window)
71 xcb_unmap_window(globalconf.connection, titlebar->window);
73 /* Remove titlebar geometry from client. */
74 if((c = client_getbytitlebar(titlebar)))
75 c->geometry = titlebar_geometry_remove(titlebar, 0, c->geometry);
77 titlebar->isbanned = true;
81 /** Move a titlebar on top of its client.
82 * \param titlebar The titlebar.
84 void
85 titlebar_unban(wibox_t *titlebar)
87 /* Do this manually because the system doesn't know we moved the toolbar.
88 * Note that !visible titlebars are unmapped and for fullscreen it'll
89 * end up offscreen anyway. */
90 if(titlebar && titlebar->isbanned)
92 client_t *c;
94 if(titlebar->window)
95 xcb_map_window(globalconf.connection, titlebar->window);
97 titlebar->isbanned = false;
99 /* Add titlebar geometry from client. */
100 if((c = client_getbytitlebar(titlebar)))
101 c->geometry = titlebar_geometry_add(titlebar, 0, c->geometry);
105 /** Get titlebar area.
106 * \param c The client
107 * \param geometry The client geometry including borders, excluding titlebars.
108 * \param res Pointer to area of titlebar, must be allocated already.
110 void
111 titlebar_geometry_compute(client_t *c, area_t geometry, area_t *res)
113 int height, width, x_offset = 0, y_offset = 0;
115 switch(c->titlebar->position)
117 default:
118 return;
119 case Top:
120 width = MAX(1, geometry.width);
121 switch(c->titlebar->align)
123 default:
124 break;
125 case AlignRight:
126 x_offset = geometry.width - width;
127 break;
128 case AlignCenter:
129 x_offset = (geometry.width - width) / 2;
130 break;
132 res->x = geometry.x + x_offset;
133 res->y = geometry.y - c->titlebar->geometry.height;
134 res->width = width;
135 res->height = c->titlebar->geometry.height;
136 break;
137 case Bottom:
138 width = MAX(1, geometry.width);
139 switch(c->titlebar->align)
141 default:
142 break;
143 case AlignRight:
144 x_offset = geometry.width - width;
145 break;
146 case AlignCenter:
147 x_offset = (geometry.width - width) / 2;
148 break;
150 res->x = geometry.x + x_offset;
151 res->y = geometry.y + geometry.height;
152 res->width = width;
153 res->height = c->titlebar->geometry.height;
154 break;
155 case Left:
156 height = MAX(1, geometry.height);
157 switch(c->titlebar->align)
159 default:
160 break;
161 case AlignRight:
162 y_offset = geometry.height - height;
163 break;
164 case AlignCenter:
165 y_offset = (geometry.height - height) / 2;
166 break;
168 res->x = geometry.x - c->titlebar->geometry.width;
169 res->y = geometry.y + y_offset;
170 res->width = c->titlebar->geometry.width;
171 res->height = height;
172 break;
173 case Right:
174 height = MAX(1, geometry.height);
175 switch(c->titlebar->align)
177 default:
178 break;
179 case AlignRight:
180 y_offset = geometry.height - height;
181 break;
182 case AlignCenter:
183 y_offset = (geometry.height - height) / 2;
184 break;
186 res->x = geometry.x + geometry.width;
187 res->y = geometry.y + y_offset;
188 res->width = c->titlebar->geometry.width;
189 res->height = height;
190 break;
194 static void
195 workaround_broken_titlebars(client_t *c)
197 /* Ugly hack to fix #610 */
198 if(c->maximized_horizontal)
200 c->maximized_horizontal = false;
201 client_set_maximized_horizontal(globalconf.L, -1, true);
203 if(c->maximized_vertical)
205 c->maximized_vertical = false;
206 client_set_maximized_vertical(globalconf.L, -1, true);
210 /** Detach a wibox titlebar from its client.
211 * \param c The client.
213 void
214 titlebar_client_detach(client_t *c)
216 /* If client has a titlebar, kick it out. */
217 if(c && c->titlebar)
219 /* Update client geometry to exclude the titlebar. */
220 c->geometry = titlebar_geometry_remove(c->titlebar, 0, c->geometry);
221 wibox_wipe(c->titlebar);
222 c->titlebar->type = WIBOX_TYPE_NORMAL;
223 c->titlebar->screen = NULL;
225 luaA_object_unref(globalconf.L, c->titlebar);
226 c->titlebar = NULL;
228 hook_property(c, "titlebar");
229 luaA_object_push(globalconf.L, c);
230 luaA_object_emit_signal(globalconf.L, -1, "property::titlebar", 0);
232 workaround_broken_titlebars(c);
234 lua_pop(globalconf.L, 1);
235 client_stack();
239 /** Attach a wibox to a client as its titlebar.
240 * \param c The client.
242 void
243 titlebar_client_attach(client_t *c)
245 /* check if we can register the object */
246 wibox_t *t = luaA_object_ref_class(globalconf.L, -1, &wibox_class);
248 titlebar_client_detach(c);
250 /* check if titlebar is already on a client */
251 titlebar_client_detach(client_getbytitlebar(t));
253 /* check if client already has a titlebar. */
254 titlebar_client_detach(c);
256 /* set the object as new client's titlebar */
257 c->titlebar = t;
259 t->type = WIBOX_TYPE_TITLEBAR;
260 t->screen = c->screen;
262 switch(t->position)
264 case Top:
265 case Bottom:
266 if(!t->geometry.height)
267 t->geometry.height = 1.5 * globalconf.font->height;
268 break;
269 case Left:
270 case Right:
271 if(!t->geometry.width)
272 t->geometry.width = 1.5 * globalconf.font->height;
273 break;
276 /* Update client geometry to include the titlebar. */
277 c->geometry = titlebar_geometry_add(c->titlebar, 0, c->geometry);
279 /* Client geometry without titlebar, but including borders, since that is always consistent. */
280 titlebar_geometry_compute(c, titlebar_geometry_remove(c->titlebar, 0, c->geometry), &t->geometry);
282 wibox_init(t, c->phys_screen);
284 t->need_update = true;
286 /* Call update geometry. This will move the wibox to the right place,
287 * which might be the same as `wingeom', but then it will ban the
288 * titlebar if needed. */
289 titlebar_update_geometry(c);
291 xcb_map_window(globalconf.connection, t->window);
293 hook_property(c, "titlebar");
295 luaA_object_push(globalconf.L, c);
296 luaA_object_emit_signal(globalconf.L, -1, "property::titlebar", 0);
298 workaround_broken_titlebars(c);
300 lua_pop(globalconf.L, 1);
301 client_stack();
304 /** Map or unmap a titlebar wibox.
305 * \param t The wibox/titlebar.
306 * \param visible The new state of the titlebar.
308 void
309 titlebar_set_visible(wibox_t *t, bool visible)
311 if(visible != t->visible)
313 if((t->visible = visible))
314 titlebar_unban(t);
315 else
316 titlebar_ban(t);
318 hook_property(t, "visible");
319 client_stack();
324 luaA_titlebar_set_position(lua_State *L, int udx)
326 wibox_t *titlebar = luaA_checkudata(L, udx, &wibox_class);
327 size_t len;
328 const char *buf = luaL_checklstring(L, -1, &len);
329 position_t position = position_fromstr(buf, len);
330 if(position != titlebar->position)
332 switch(position)
334 case Left:
335 switch(titlebar->position)
337 int tmp;
338 case Left:
339 case Right:
340 break;
341 case Top:
342 case Bottom:
343 tmp = titlebar->geometry.width;
344 titlebar->geometry.width = titlebar->geometry.height;
345 titlebar->geometry.height = tmp;
346 break;
348 wibox_set_orientation(L, udx, North);
349 break;
350 case Right:
351 switch(titlebar->position)
353 int tmp;
354 case Left:
355 case Right:
356 break;
357 case Top:
358 case Bottom:
359 tmp = titlebar->geometry.width;
360 titlebar->geometry.width = titlebar->geometry.height;
361 titlebar->geometry.height = tmp;
362 break;
364 wibox_set_orientation(L, udx, South);
365 break;
366 case Top:
367 case Bottom:
368 switch(titlebar->position)
370 int tmp;
371 case Left:
372 case Right:
373 tmp = titlebar->geometry.width;
374 titlebar->geometry.width = titlebar->geometry.height;
375 titlebar->geometry.height = tmp;
376 break;
377 case Top:
378 case Bottom:
379 break;
381 wibox_set_orientation(L, udx, East);
382 break;
384 titlebar->position = position;
385 client_t *c;
386 if((c = client_getbytitlebar(titlebar)))
388 titlebar_update_geometry(c);
389 /* call geometry hook for client because some like to
390 * set titlebar width in that hook, which make sense */
391 hook_property(c, "geometry");
394 return 0;
397 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80