ewmh: store NET_WM icon
[awesome.git] / screen.c
blob2844e11388916bfc77d03a90aa5b391600d050ad
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 coords The screen coordinates.
223 * \lfield padding The screen padding.
225 static int
226 luaA_screen_module_index(lua_State *L)
228 int screen = luaL_checknumber(L, 2) - 1;
230 luaA_checkscreen(screen);
231 lua_pushlightuserdata(L, &globalconf.screens[screen]);
232 return luaA_settype(L, "screen");
235 /** A screen.
236 * \param L The Lua VM state.
237 * \luastack
238 * \lfield padding The screen padding. A table with top, right, left and bottom
239 * keys and values in pixel.
240 * \lfield coords The screen coordinates. Immutable.
241 * \lfield workarea The screen workarea, i.e. without statusbar.
243 static int
244 luaA_screen_index(lua_State *L)
246 size_t len;
247 const char *buf = luaL_checklstring(L, 2, &len);
248 screen_t *s;
249 area_t g;
250 int i;
252 s = lua_touserdata(L, 1);
254 switch(a_tokenize(buf, len))
256 case A_TK_PADDING:
257 lua_newtable(L);
258 lua_pushnumber(L, s->padding.right);
259 lua_setfield(L, -2, "right");
260 lua_pushnumber(L, s->padding.left);
261 lua_setfield(L, -2, "left");
262 lua_pushnumber(L, s->padding.top);
263 lua_setfield(L, -2, "top");
264 lua_pushnumber(L, s->padding.bottom);
265 lua_setfield(L, -2, "bottom");
266 break;
267 case A_TK_COORDS:
268 /* \todo lua_pushgeometry() ? */
269 lua_newtable(L);
270 lua_pushnumber(L, s->geometry.x);
271 lua_setfield(L, -2, "x");
272 lua_pushnumber(L, s->geometry.y);
273 lua_setfield(L, -2, "y");
274 lua_pushnumber(L, s->geometry.width);
275 lua_setfield(L, -2, "width");
276 lua_pushnumber(L, s->geometry.height);
277 lua_setfield(L, -2, "height");
278 break;
279 case A_TK_WORKAREA:
280 g = screen_area_get(&s->geometry, s->statusbar, &s->padding);
281 lua_newtable(L);
282 lua_pushnumber(L, g.x);
283 lua_setfield(L, -2, "x");
284 lua_pushnumber(L, g.y);
285 lua_setfield(L, -2, "y");
286 lua_pushnumber(L, g.width);
287 lua_setfield(L, -2, "width");
288 lua_pushnumber(L, g.height);
289 lua_setfield(L, -2, "height");
290 break;
291 case A_TK_TAGS:
292 lua_newtable(L);
293 for(i = 0; i < s->tags.len; i++)
295 luaA_tag_userdata_new(L, s->tags.tab[i]);
296 lua_rawseti(L, -2, i + 1);
298 break;
299 default:
300 return 0;
303 return 1;
306 static int
307 luaA_screen_newindex(lua_State *L)
309 size_t len;
310 const char *buf = luaL_checklstring(L, 2, &len);
311 screen_t *s;
313 s = lua_touserdata(L, 1);
315 switch(a_tokenize(buf, len))
317 case A_TK_PADDING:
318 luaA_checktable(L, 3);
319 s->padding.right = luaA_getopt_number(L, 2, "right", 0);
320 s->padding.left = luaA_getopt_number(L, 2, "left", 0);
321 s->padding.top = luaA_getopt_number(L, 2, "top", 0);
322 s->padding.bottom = luaA_getopt_number(L, 2, "bottom", 0);
324 ewmh_update_workarea(screen_virttophys(s->index));
326 break;
327 default:
328 return 0;
331 return 0;
334 /** Get the screen count.
335 * \param L The Lua VM state.
336 * \return The number of elements pushed on stack.
338 * \luastack
339 * \lreturn The screen count, at least 1.
341 static int
342 luaA_screen_count(lua_State *L)
344 lua_pushnumber(L, globalconf.screens_info->nscreen);
345 return 1;
348 const struct luaL_reg awesome_screen_methods[] =
350 { "count", luaA_screen_count },
351 { "__index", luaA_screen_module_index },
352 { NULL, NULL }
355 const struct luaL_reg awesome_screen_meta[] =
357 { "__index", luaA_screen_index },
358 { "__newindex", luaA_screen_newindex },
359 { NULL, NULL }
362 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80