xutil: make xutil_lock_mask_get() asynchronous
[awesome.git] / screen.c
blob9ed554876c63fc06f09f6c83216e70f9325af364
1 /*
2 * screen.c - screen management
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 <stdio.h>
24 #include <xcb/xcb.h>
25 #include <xcb/xcb_aux.h>
27 #include "screen.h"
28 #include "ewmh.h"
29 #include "tag.h"
30 #include "client.h"
32 extern awesome_t globalconf;
34 /** Get screens info.
35 * \param screen Screen number.
36 * \param statusbar Statusbar list to remove.
37 * \param padding Padding.
38 * \return The screen area.
40 area_t
41 screen_area_get(area_t *geometry, statusbar_t *statusbar, padding_t *padding)
43 area_t area = *geometry;
44 statusbar_t *sb;
46 /* make padding corrections */
47 if(padding)
49 area.x += padding->left;
50 area.y += padding->top;
51 area.width -= padding->left + padding->right;
52 area.height -= padding->top + padding->bottom;
55 for(sb = statusbar; sb; sb = sb->next)
56 switch(sb->position)
58 case Top:
59 area.y += sb->height;
60 case Bottom:
61 area.height -= sb->height;
62 break;
63 case Left:
64 area.x += sb->height;
65 case Right:
66 area.width -= sb->height;
67 break;
68 default:
69 break;
72 return area;
75 /** Get display info.
76 * \param phys_screen Physical screen number.
77 * \param statusbar The statusbars.
78 * \param padding Padding.
79 * \return The display area.
81 area_t
82 display_area_get(int phys_screen, statusbar_t *statusbar, padding_t *padding)
84 area_t area = { 0, 0, 0, 0 };
85 statusbar_t *sb;
86 xcb_screen_t *s = xutil_screen_get(globalconf.connection, phys_screen);
88 area.width = s->width_in_pixels;
89 area.height = s->height_in_pixels;
91 for(sb = statusbar; sb; sb = sb->next)
93 area.y += sb->position == Top ? sb->height : 0;
94 area.height -= (sb->position == Top || sb->position == Bottom) ? sb->height : 0;
97 /* make padding corrections */
98 if(padding)
100 area.x += padding->left;
101 area.y += padding->top;
102 area.width -= padding->left + padding->right;
103 area.height -= padding->top + padding->bottom;
105 return area;
108 /** This returns the real X screen number for a logical
109 * screen if Xinerama is active.
110 * \param screen The logical screen.
111 * \return The X screen.
114 screen_virttophys(int screen)
116 if(globalconf.screens_info->xinerama_is_active)
117 return globalconf.default_screen;
118 return screen;
121 /** Move a client to a virtual screen.
122 * \param c The client to move.
123 * \param new_screen The destinatiuon screen number.
124 * \param doresize Set to true if we also move the client to the new x and
125 * y of the new screen.
127 void
128 screen_client_moveto(client_t *c, int new_screen, bool doresize)
130 int i, old_screen = c->screen;
131 tag_array_t *old_tags = &globalconf.screens[old_screen].tags,
132 *new_tags = &globalconf.screens[new_screen].tags;
133 area_t from, to;
135 c->screen = new_screen;
137 /* remove old tags */
138 for(i = 0; i < old_tags->len; i++)
139 untag_client(c, old_tags->tab[i]);
141 /* add new tags */
142 for(i = 0; i < new_tags->len; i++)
143 if(new_tags->tab[i]->selected)
144 tag_client(c, new_tags->tab[i]);
146 /* resize the windows if it's floating */
147 if(doresize && old_screen != c->screen)
149 area_t new_geometry, new_f_geometry;
150 new_f_geometry = c->f_geometry;
152 to = screen_area_get(&globalconf.screens[c->screen].geometry,
153 NULL, NULL);
154 from = screen_area_get(&globalconf.screens[old_screen].geometry,
155 NULL, NULL);
157 /* compute new coords in new screen */
158 new_f_geometry.x = (c->f_geometry.x - from.x) + to.x;
159 new_f_geometry.y = (c->f_geometry.y - from.y) + to.y;
161 /* check that new coords are still in the screen */
162 if(new_f_geometry.width > to.width)
163 new_f_geometry.width = to.width;
164 if(new_f_geometry.height > to.height)
165 new_f_geometry.height = to.height;
166 if(new_f_geometry.x + new_f_geometry.width >= to.x + to.width)
167 new_f_geometry.x = to.x + to.width - new_f_geometry.width - 2 * c->border;
168 if(new_f_geometry.y + new_f_geometry.height >= to.y + to.height)
169 new_f_geometry.y = to.y + to.height - new_f_geometry.height - 2 * c->border;
171 if(c->ismax)
173 new_geometry = c->geometry;
175 /* compute new coords in new screen */
176 new_geometry.x = (c->geometry.x - from.x) + to.x;
177 new_geometry.y = (c->geometry.y - from.y) + to.y;
179 /* check that new coords are still in the screen */
180 if(new_geometry.width > to.width)
181 new_geometry.width = to.width;
182 if(new_geometry.height > to.height)
183 new_geometry.height = to.height;
184 if(new_geometry.x + new_geometry.width >= to.x + to.width)
185 new_geometry.x = to.x + to.width - new_geometry.width - 2 * c->border;
186 if(new_geometry.y + new_geometry.height >= to.y + to.height)
187 new_geometry.y = to.y + to.height - new_geometry.height - 2 * c->border;
189 /* compute new coords for max in new screen */
190 c->m_geometry.x = (c->m_geometry.x - from.x) + to.x;
191 c->m_geometry.y = (c->m_geometry.y - from.y) + to.y;
193 /* check that new coords are still in the screen */
194 if(c->m_geometry.width > to.width)
195 c->m_geometry.width = to.width;
196 if(c->m_geometry.height > to.height)
197 c->m_geometry.height = to.height;
198 if(c->m_geometry.x + c->m_geometry.width >= to.x + to.width)
199 c->m_geometry.x = to.x + to.width - c->m_geometry.width - 2 * c->border;
200 if(c->m_geometry.y + c->m_geometry.height >= to.y + to.height)
201 c->m_geometry.y = to.y + to.height - c->m_geometry.height - 2 * c->border;
203 client_resize(c, new_geometry, false);
205 /* if floating, move to this new coords */
206 else if(c->isfloating)
207 client_resize(c, new_f_geometry, false);
208 /* otherwise just register them */
209 else
211 c->f_geometry = new_f_geometry;
212 globalconf.screens[old_screen].need_arrange = true;
213 globalconf.screens[c->screen].need_arrange = true;
218 /** Screen module.
219 * \param L The Lua VM state.
220 * \return The number of elements pushed on stack.
221 * \luastack
222 * \lfield number The screen number, to get a screen.
224 static int
225 luaA_screen_module_index(lua_State *L)
227 int screen = luaL_checknumber(L, 2) - 1;
229 luaA_checkscreen(screen);
230 lua_pushlightuserdata(L, &globalconf.screens[screen]);
231 return luaA_settype(L, "screen");
234 /** A screen.
235 * \param L The Lua VM state.
236 * \luastack
237 * \lfield padding The screen padding. A table with top, right, left and bottom
238 * keys and values in pixel.
239 * \lfield coords The screen coordinates. Immutable.
240 * \lfield workarea The screen workarea, i.e. without statusbar.
242 static int
243 luaA_screen_index(lua_State *L)
245 size_t len;
246 const char *buf = luaL_checklstring(L, 2, &len);
247 screen_t *s;
248 area_t g;
249 int i;
251 s = lua_touserdata(L, 1);
253 switch(a_tokenize(buf, len))
255 case A_TK_PADDING:
256 lua_newtable(L);
257 lua_pushnumber(L, s->padding.right);
258 lua_setfield(L, -2, "right");
259 lua_pushnumber(L, s->padding.left);
260 lua_setfield(L, -2, "left");
261 lua_pushnumber(L, s->padding.top);
262 lua_setfield(L, -2, "top");
263 lua_pushnumber(L, s->padding.bottom);
264 lua_setfield(L, -2, "bottom");
265 break;
266 case A_TK_COORDS:
267 /* \todo lua_pushgeometry() ? */
268 lua_newtable(L);
269 lua_pushnumber(L, s->geometry.x);
270 lua_setfield(L, -2, "x");
271 lua_pushnumber(L, s->geometry.y);
272 lua_setfield(L, -2, "y");
273 lua_pushnumber(L, s->geometry.width);
274 lua_setfield(L, -2, "width");
275 lua_pushnumber(L, s->geometry.height);
276 lua_setfield(L, -2, "height");
277 break;
278 case A_TK_WORKAREA:
279 g = screen_area_get(&s->geometry, s->statusbar, &s->padding);
280 lua_newtable(L);
281 lua_pushnumber(L, g.x);
282 lua_setfield(L, -2, "x");
283 lua_pushnumber(L, g.y);
284 lua_setfield(L, -2, "y");
285 lua_pushnumber(L, g.width);
286 lua_setfield(L, -2, "width");
287 lua_pushnumber(L, g.height);
288 lua_setfield(L, -2, "height");
289 break;
290 case A_TK_TAGS:
291 lua_newtable(L);
292 for(i = 0; i < s->tags.len; i++)
294 luaA_tag_userdata_new(L, s->tags.tab[i]);
295 lua_rawseti(L, -2, i + 1);
297 break;
298 default:
299 return 0;
302 return 1;
305 static int
306 luaA_screen_newindex(lua_State *L)
308 size_t len;
309 const char *buf = luaL_checklstring(L, 2, &len);
310 screen_t *s;
311 tag_t **tag;
312 int i;
314 s = lua_touserdata(L, 1);
316 switch(a_tokenize(buf, len))
318 case A_TK_PADDING:
319 luaA_checktable(L, 3);
320 s->padding.right = luaA_getopt_number(L, 2, "right", 0);
321 s->padding.left = luaA_getopt_number(L, 2, "left", 0);
322 s->padding.top = luaA_getopt_number(L, 2, "top", 0);
323 s->padding.bottom = luaA_getopt_number(L, 2, "bottom", 0);
325 ewmh_update_workarea(screen_virttophys(s->index));
327 break;
328 case A_TK_TAGS:
329 luaA_checktable(L, 3);
331 /* remove current tags */
332 for(i = 0; i < s->tags.len; i++)
333 s->tags.tab[i]->screen = SCREEN_UNDEF;
335 tag_array_wipe(&s->tags);
336 tag_array_init(&s->tags);
338 s->need_arrange = true;
340 /* push new tags */
341 lua_pushnil(L);
342 while(lua_next(L, 3))
344 tag = luaA_checkudata(L, -1, "tag");
345 tag_append_to_screen(*tag, s);
346 lua_pop(L, 1);
348 break;
349 default:
350 return 0;
353 return 0;
356 /** Get the screen count.
357 * \param L The Lua VM state.
358 * \return The number of elements pushed on stack.
360 * \luastack
361 * \lreturn The screen count, at least 1.
363 static int
364 luaA_screen_count(lua_State *L)
366 lua_pushnumber(L, globalconf.screens_info->nscreen);
367 return 1;
370 const struct luaL_reg awesome_screen_methods[] =
372 { "count", luaA_screen_count },
373 { "__index", luaA_screen_module_index },
374 { NULL, NULL }
377 const struct luaL_reg awesome_screen_meta[] =
379 { "__index", luaA_screen_index },
380 { "__newindex", luaA_screen_newindex },
381 { NULL, NULL }
384 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80