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>
32 extern awesome_t globalconf
;
35 * \param screen Screen number.
36 * \param statusbar Statusbar list to remove.
37 * \param padding Padding.
38 * \return The screen area.
41 screen_area_get(area_t
*geometry
, statusbar_t
*statusbar
, padding_t
*padding
)
43 area_t area
= *geometry
;
46 /* make padding corrections */
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
)
61 area
.height
-= sb
->height
;
66 area
.width
-= sb
->height
;
76 * \param phys_screen Physical screen number.
77 * \param statusbar The statusbars.
78 * \param padding Padding.
79 * \return The display area.
82 display_area_get(int phys_screen
, statusbar_t
*statusbar
, padding_t
*padding
)
84 area_t area
= { 0, 0, 0, 0 };
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 */
100 area
.x
+= padding
->left
;
101 area
.y
+= padding
->top
;
102 area
.width
-= padding
->left
+ padding
->right
;
103 area
.height
-= padding
->top
+ padding
->bottom
;
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
;
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.
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
;
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
]);
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
,
154 from
= screen_area_get(&globalconf
.screens
[old_screen
].geometry
,
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
;
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 */
211 c
->f_geometry
= new_f_geometry
;
212 globalconf
.screens
[old_screen
].need_arrange
= true;
213 globalconf
.screens
[c
->screen
].need_arrange
= true;
219 * \param L The Lua VM state.
220 * \return The number of elements pushed on stack.
222 * \lfield number The screen number, to get a screen.
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");
235 * \param L The Lua VM state.
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.
243 luaA_screen_index(lua_State
*L
)
246 const char *buf
= luaL_checklstring(L
, 2, &len
);
251 s
= lua_touserdata(L
, 1);
253 switch(a_tokenize(buf
, len
))
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");
267 /* \todo lua_pushgeometry() ? */
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");
279 g
= screen_area_get(&s
->geometry
, s
->statusbar
, &s
->padding
);
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");
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);
306 luaA_screen_newindex(lua_State
*L
)
309 const char *buf
= luaL_checklstring(L
, 2, &len
);
314 s
= lua_touserdata(L
, 1);
316 switch(a_tokenize(buf
, len
))
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
));
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;
342 while(lua_next(L
, 3))
344 tag
= luaA_checkudata(L
, -1, "tag");
345 tag_append_to_screen(*tag
, s
);
356 /** Get the screen count.
357 * \param L The Lua VM state.
358 * \return The number of elements pushed on stack.
361 * \lreturn The screen count, at least 1.
364 luaA_screen_count(lua_State
*L
)
366 lua_pushnumber(L
, globalconf
.screens_info
->nscreen
);
370 const struct luaL_reg awesome_screen_methods
[] =
372 { "count", luaA_screen_count
},
373 { "__index", luaA_screen_module_index
},
377 const struct luaL_reg awesome_screen_meta
[] =
379 { "__index", luaA_screen_index
},
380 { "__newindex", luaA_screen_newindex
},
384 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80