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.
25 #include <xcb/xcb_aux.h>
31 #include "statusbar.h"
32 #include "layouts/tile.h"
34 extern awesome_t globalconf
;
37 * \param screen Screen number.
38 * \param statusbar Statusbar list to remove.
39 * \param padding Padding.
40 * \return The screen area.
43 screen_area_get(area_t
*geometry
, statusbar_t
*statusbar
, padding_t
*padding
)
45 area_t area
= *geometry
;
48 /* make padding corrections */
51 area
.x
+= padding
->left
;
52 area
.y
+= padding
->top
;
53 area
.width
-= padding
->left
+ padding
->right
;
54 area
.height
-= padding
->top
+ padding
->bottom
;
57 for(sb
= statusbar
; sb
; sb
= sb
->next
)
63 area
.height
-= sb
->height
;
68 area
.width
-= sb
->height
;
78 * \param phys_screen Physical screen number.
79 * \param statusbar The statusbars.
80 * \param padding Padding.
81 * \return The display area.
84 display_area_get(int phys_screen
, statusbar_t
*statusbar
, padding_t
*padding
)
86 area_t area
= { 0, 0, 0, 0 };
88 xcb_screen_t
*s
= xutil_screen_get(globalconf
.connection
, phys_screen
);
90 area
.width
= s
->width_in_pixels
;
91 area
.height
= s
->height_in_pixels
;
93 for(sb
= statusbar
; sb
; sb
= sb
->next
)
95 area
.y
+= sb
->position
== Top
? sb
->height
: 0;
96 area
.height
-= (sb
->position
== Top
|| sb
->position
== Bottom
) ? sb
->height
: 0;
99 /* make padding corrections */
102 area
.x
+= padding
->left
;
103 area
.y
+= padding
->top
;
104 area
.width
-= padding
->left
+ padding
->right
;
105 area
.height
-= padding
->top
+ padding
->bottom
;
110 /** This returns the real X screen number for a logical
111 * screen if Xinerama is active.
112 * \param screen The logical screen.
113 * \return The X screen.
116 screen_virttophys(int screen
)
118 if(globalconf
.screens_info
->xinerama_is_active
)
119 return globalconf
.default_screen
;
123 /** Move a client to a virtual screen.
124 * \param c The client to move.
125 * \param new_screen The destinatiuon screen number.
126 * \param doresize Set to true if we also move the client to the new x and
127 * y of the new screen.
130 screen_client_moveto(client_t
*c
, int new_screen
, bool doresize
)
132 int i
, old_screen
= c
->screen
;
133 tag_array_t
*old_tags
= &globalconf
.screens
[old_screen
].tags
,
134 *new_tags
= &globalconf
.screens
[new_screen
].tags
;
137 c
->screen
= new_screen
;
139 /* remove old tags */
140 for(i
= 0; i
< old_tags
->len
; i
++)
141 untag_client(c
, old_tags
->tab
[i
]);
144 for(i
= 0; i
< new_tags
->len
; i
++)
145 if(new_tags
->tab
[i
]->selected
)
146 tag_client(c
, new_tags
->tab
[i
]);
148 /* resize the windows if it's floating */
149 if(doresize
&& old_screen
!= c
->screen
)
151 area_t new_geometry
, new_f_geometry
;
152 new_f_geometry
= c
->f_geometry
;
154 to
= screen_area_get(&globalconf
.screens
[c
->screen
].geometry
,
156 from
= screen_area_get(&globalconf
.screens
[old_screen
].geometry
,
159 /* compute new coords in new screen */
160 new_f_geometry
.x
= (c
->f_geometry
.x
- from
.x
) + to
.x
;
161 new_f_geometry
.y
= (c
->f_geometry
.y
- from
.y
) + to
.y
;
163 /* check that new coords are still in the screen */
164 if(new_f_geometry
.width
> to
.width
)
165 new_f_geometry
.width
= to
.width
;
166 if(new_f_geometry
.height
> to
.height
)
167 new_f_geometry
.height
= to
.height
;
168 if(new_f_geometry
.x
+ new_f_geometry
.width
>= to
.x
+ to
.width
)
169 new_f_geometry
.x
= to
.x
+ to
.width
- new_f_geometry
.width
- 2 * c
->border
;
170 if(new_f_geometry
.y
+ new_f_geometry
.height
>= to
.y
+ to
.height
)
171 new_f_geometry
.y
= to
.y
+ to
.height
- new_f_geometry
.height
- 2 * c
->border
;
175 new_geometry
= c
->geometry
;
177 /* compute new coords in new screen */
178 new_geometry
.x
= (c
->geometry
.x
- from
.x
) + to
.x
;
179 new_geometry
.y
= (c
->geometry
.y
- from
.y
) + to
.y
;
181 /* check that new coords are still in the screen */
182 if(new_geometry
.width
> to
.width
)
183 new_geometry
.width
= to
.width
;
184 if(new_geometry
.height
> to
.height
)
185 new_geometry
.height
= to
.height
;
186 if(new_geometry
.x
+ new_geometry
.width
>= to
.x
+ to
.width
)
187 new_geometry
.x
= to
.x
+ to
.width
- new_geometry
.width
- 2 * c
->border
;
188 if(new_geometry
.y
+ new_geometry
.height
>= to
.y
+ to
.height
)
189 new_geometry
.y
= to
.y
+ to
.height
- new_geometry
.height
- 2 * c
->border
;
191 /* compute new coords for max in new screen */
192 c
->m_geometry
.x
= (c
->m_geometry
.x
- from
.x
) + to
.x
;
193 c
->m_geometry
.y
= (c
->m_geometry
.y
- from
.y
) + to
.y
;
195 /* check that new coords are still in the screen */
196 if(c
->m_geometry
.width
> to
.width
)
197 c
->m_geometry
.width
= to
.width
;
198 if(c
->m_geometry
.height
> to
.height
)
199 c
->m_geometry
.height
= to
.height
;
200 if(c
->m_geometry
.x
+ c
->m_geometry
.width
>= to
.x
+ to
.width
)
201 c
->m_geometry
.x
= to
.x
+ to
.width
- c
->m_geometry
.width
- 2 * c
->border
;
202 if(c
->m_geometry
.y
+ c
->m_geometry
.height
>= to
.y
+ to
.height
)
203 c
->m_geometry
.y
= to
.y
+ to
.height
- c
->m_geometry
.height
- 2 * c
->border
;
205 client_resize(c
, new_geometry
, false);
207 /* if floating, move to this new coords */
208 else if(c
->isfloating
)
209 client_resize(c
, new_f_geometry
, false);
210 /* otherwise just register them */
213 c
->f_geometry
= new_f_geometry
;
214 globalconf
.screens
[old_screen
].need_arrange
= true;
215 globalconf
.screens
[c
->screen
].need_arrange
= true;
221 * \param L The Lua VM state.
222 * \return The number of elements pushed on stack.
224 * \lfield number The screen number, to get a screen.
227 luaA_screen_module_index(lua_State
*L
)
229 int screen
= luaL_checknumber(L
, 2) - 1;
231 luaA_checkscreen(screen
);
232 lua_pushlightuserdata(L
, &globalconf
.screens
[screen
]);
233 return luaA_settype(L
, "screen");
236 /** Get or set screen tags.
237 * \param L The Lua VM state.
238 * \return The number of elements pushed on stack.
240 * \lparam None or a table of tags to set to the screen.
241 * The table must contains at least one tag.
242 * \return A table with all screen tags.
245 luaA_screen_tags(lua_State
*L
)
248 screen_t
*s
= lua_touserdata(L
, 1);
251 luaL_typerror(L
, 1, "screen");
253 if(lua_gettop(L
) == 2)
257 luaA_checktable(L
, 2);
259 /* remove current tags */
260 for(i
= 0; i
< s
->tags
.len
; i
++)
261 s
->tags
.tab
[i
]->screen
= SCREEN_UNDEF
;
263 tag_array_wipe(&s
->tags
);
264 tag_array_init(&s
->tags
);
266 s
->need_arrange
= true;
270 while(lua_next(L
, 2))
272 tag
= luaA_checkudata(L
, -1, "tag");
273 tag_append_to_screen(*tag
, s
);
277 /* check there's at least one tag! */
280 tag_append_to_screen(tag_new("default", sizeof("default") - 1, layout_tile
, 0.5, 1, 0), s
);
281 luaL_error(L
, "no tag were added on screen %d, taking last resort action and adding default tag\n", s
->index
);
287 for(i
= 0; i
< s
->tags
.len
; i
++)
289 luaA_tag_userdata_new(L
, s
->tags
.tab
[i
]);
290 lua_rawseti(L
, -2, i
+ 1);
298 * \param L The Lua VM state.
299 * \return The number of elements pushed on stack.
301 * \lfield padding The screen padding. A table with top, right, left and bottom
302 * keys and values in pixel.
303 * \lfield coords The screen coordinates. Immutable.
304 * \lfield workarea The screen workarea, i.e. without statusbar.
307 luaA_screen_index(lua_State
*L
)
314 if(luaA_usemetatable(L
, 1, 2))
317 buf
= luaL_checklstring(L
, 2, &len
);
318 s
= lua_touserdata(L
, 1);
320 switch(a_tokenize(buf
, len
))
323 /* \todo lua_pushgeometry() ? */
325 lua_pushnumber(L
, s
->geometry
.x
);
326 lua_setfield(L
, -2, "x");
327 lua_pushnumber(L
, s
->geometry
.y
);
328 lua_setfield(L
, -2, "y");
329 lua_pushnumber(L
, s
->geometry
.width
);
330 lua_setfield(L
, -2, "width");
331 lua_pushnumber(L
, s
->geometry
.height
);
332 lua_setfield(L
, -2, "height");
335 g
= screen_area_get(&s
->geometry
, s
->statusbar
, &s
->padding
);
337 lua_pushnumber(L
, g
.x
);
338 lua_setfield(L
, -2, "x");
339 lua_pushnumber(L
, g
.y
);
340 lua_setfield(L
, -2, "y");
341 lua_pushnumber(L
, g
.width
);
342 lua_setfield(L
, -2, "width");
343 lua_pushnumber(L
, g
.height
);
344 lua_setfield(L
, -2, "height");
353 /** Set or get the screen padding.
354 * \param L The Lua VM state.
355 * \return The number of elements pushed on stack.
357 * \param None or a table with new padding values.
358 * \return The screen padding. A table with top, right, left and bottom
359 * keys and values in pixel.
362 luaA_screen_padding(lua_State
*L
)
364 screen_t
*s
= lua_touserdata(L
, 1);
367 luaL_typerror(L
, 1, "screen");
369 if(lua_gettop(L
) == 2)
373 luaA_checktable(L
, 2);
375 s
->padding
.right
= luaA_getopt_number(L
, 2, "right", 0);
376 s
->padding
.left
= luaA_getopt_number(L
, 2, "left", 0);
377 s
->padding
.top
= luaA_getopt_number(L
, 2, "top", 0);
378 s
->padding
.bottom
= luaA_getopt_number(L
, 2, "bottom", 0);
380 s
->need_arrange
= true;
382 /* All the statusbar repositioned */
383 for(sb
= s
->statusbar
; sb
; sb
= sb
->next
)
384 statusbar_position_update(sb
);
386 ewmh_update_workarea(screen_virttophys(s
->index
));
391 lua_pushnumber(L
, s
->padding
.right
);
392 lua_setfield(L
, -2, "right");
393 lua_pushnumber(L
, s
->padding
.left
);
394 lua_setfield(L
, -2, "left");
395 lua_pushnumber(L
, s
->padding
.top
);
396 lua_setfield(L
, -2, "top");
397 lua_pushnumber(L
, s
->padding
.bottom
);
398 lua_setfield(L
, -2, "bottom");
404 /** Get the screen count.
405 * \param L The Lua VM state.
406 * \return The number of elements pushed on stack.
409 * \lreturn The screen count, at least 1.
412 luaA_screen_count(lua_State
*L
)
414 lua_pushnumber(L
, globalconf
.screens_info
->nscreen
);
418 const struct luaL_reg awesome_screen_methods
[] =
420 { "count", luaA_screen_count
},
421 { "__index", luaA_screen_module_index
},
425 const struct luaL_reg awesome_screen_meta
[] =
427 { "tags", luaA_screen_tags
},
428 { "padding", luaA_screen_padding
},
429 { "__index", luaA_screen_index
},
433 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80