move define
[awesome.git] / screen.c
blobad22c69b4039f984c7652b8bd4f03db80d9f8fb7
1 /*
2 * screen.c - screen management
4 * Copyright © 2007 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 <X11/extensions/Xinerama.h>
24 #include "screen.h"
25 #include "tag.h"
26 #include "focus.h"
27 #include "client.h"
28 #include "layouts/floating.h"
29 #include "common/util.h"
31 extern AwesomeConf globalconf;
33 /** Get screens info
34 * \param screen Screen number
35 * \param statusbar statusbar
36 * \param padding Padding
37 * \return Area
39 Area
40 get_screen_area(int screen, Statusbar *statusbar, Padding *padding)
42 Area area;
43 Statusbar *sb;
45 area = globalconf.screens[screen].geometry;
47 /* make padding corrections */
48 if(padding)
50 area.x += padding->left;
51 area.y += padding->top;
52 area.width -= padding->left + padding->right;
53 area.height -= padding->top + padding->bottom;
56 for(sb = statusbar; sb; sb = sb->next)
57 switch(sb->position)
59 case Top:
60 area.y += sb->height;
61 case Bottom:
62 area.height -= sb->height;
63 break;
64 case Left:
65 area.x += sb->height;
66 case Right:
67 area.width -= sb->height;
68 break;
69 case Off:
70 break;
73 return area;
76 /** Get display info
77 * \param screen Screen number
78 * \param statusbar the statusbar
79 * \param padding Padding
80 * \return Area
82 Area
83 get_display_area(int screen, Statusbar *statusbar, Padding *padding)
85 Area area = { 0, 0, 0, 0, NULL };
86 Statusbar *sb;
88 area.width = DisplayWidth(globalconf.display, screen);
89 area.height = DisplayHeight(globalconf.display, screen);
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 /** Return the Xinerama screen number where the coordinates belongs to
109 * \param x x coordinate of the window
110 * \param y y coordinate of the window
111 * \return screen number or DefaultScreen of disp on no match
114 get_screen_bycoord(int x, int y)
116 int i;
117 Area area;
119 /* don't waste our time */
120 if(!XineramaIsActive(globalconf.display))
121 return DefaultScreen(globalconf.display);
123 for(i = 0; i < globalconf.nscreen; i++)
125 area = get_screen_area(i, NULL, NULL);
126 if((x < 0 || (x >= area.x && x < area.x + area.width))
127 && (y < 0 || (y >= area.y && y < area.y + area.height)))
128 return i;
130 return DefaultScreen(globalconf.display);
134 static inline Area
135 screen_xsi_to_area(XineramaScreenInfo si)
137 Area a;
139 a.x = si.x_org;
140 a.y = si.y_org;
141 a.width = si.width;
142 a.height = si.height;
143 a.next = NULL;
145 return a;
148 void
149 screen_build_screens(void)
151 XineramaScreenInfo *si;
152 int xinerama_screen_number, screen, screen_to_test;
153 Bool drop;
155 if(XineramaIsActive(globalconf.display))
157 si = XineramaQueryScreens(globalconf.display, &xinerama_screen_number);
158 globalconf.screens = p_new(VirtScreen, xinerama_screen_number);
159 globalconf.nscreen = 0;
161 /* now check if screens overlaps (same x,y): if so, we take only the biggest one */
162 for(screen = 0; screen < xinerama_screen_number; screen++)
164 drop = False;
165 for(screen_to_test = 0; screen_to_test < globalconf.nscreen; screen_to_test++)
166 if(si[screen].x_org == globalconf.screens[screen_to_test].geometry.x
167 && si[screen].y_org == globalconf.screens[screen_to_test].geometry.y)
169 /* we already have a screen for this area, just check if
170 * it's not bigger and drop it */
171 drop = True;
172 globalconf.screens[screen_to_test].geometry.width =
173 MAX(si[screen].width, si[screen_to_test].width);
174 globalconf.screens[screen_to_test].geometry.height =
175 MAX(si[screen].height, si[screen_to_test].height);
177 if(!drop)
178 globalconf.screens[globalconf.nscreen++].geometry = screen_xsi_to_area(si[screen]);
181 /* realloc smaller if xinerama_screen_number != screen registered */
182 if(xinerama_screen_number != globalconf.nscreen)
184 VirtScreen *newscreens = p_new(VirtScreen, globalconf.nscreen);
185 memcpy(newscreens, globalconf.screens, globalconf.nscreen * sizeof(VirtScreen));
186 p_delete(&globalconf.screens);
187 globalconf.screens = newscreens;
190 XFree(si);
192 else
194 globalconf.nscreen = ScreenCount(globalconf.display);
195 globalconf.screens = p_new(VirtScreen, globalconf.nscreen);
196 for(screen = 0; screen < globalconf.nscreen; screen++)
198 globalconf.screens[screen].geometry.x = 0;
199 globalconf.screens[screen].geometry.y = 0;
200 globalconf.screens[screen].geometry.width =
201 DisplayWidth(globalconf.display, screen);
202 globalconf.screens[screen].geometry.height =
203 DisplayHeight(globalconf.display, screen);
209 /** This returns the real X screen number for a logical
210 * screen if Xinerama is active.
211 * \param screen the logical screen
212 * \return the X screen
215 get_phys_screen(int screen)
217 if(XineramaIsActive(globalconf.display))
218 return DefaultScreen(globalconf.display);
219 return screen;
222 /** Move a client to a virtual screen
223 * \param c the client
224 * \param new_screen The destinatiuon screen
225 * \param doresize set to True if we also move the client to the new x and
226 * y of the new screen
228 void
229 move_client_to_screen(Client *c, int new_screen, Bool doresize)
231 Tag *tag;
232 int old_screen = c->screen;
233 Area from, to;
235 for(tag = globalconf.screens[old_screen].tags; tag; tag = tag->next)
236 untag_client(c, tag);
238 c->screen = new_screen;
240 /* tag client with new screen tags */
241 tag_client_with_current_selected(c);
243 /* resize the windows if it's floating */
244 if(doresize && old_screen != c->screen)
246 Area new_geometry, new_f_geometry;
247 new_f_geometry = c->f_geometry;
249 to = get_screen_area(c->screen, NULL, NULL);
250 from = get_screen_area(old_screen, NULL, NULL);
252 /* compute new coords in new screen */
253 new_f_geometry.x = (c->f_geometry.x - from.x) + to.x;
254 new_f_geometry.y = (c->f_geometry.y - from.y) + to.y;
256 /* check that new coords are still in the screen */
257 if(new_f_geometry.width > to.width)
258 new_f_geometry.width = to.width;
259 if(new_f_geometry.height > to.height)
260 new_f_geometry.height = to.height;
261 if(new_f_geometry.x + new_f_geometry.width >= to.x + to.width)
262 new_f_geometry.x = to.x + to.width - new_f_geometry.width - 2 * c->border;
263 if(new_f_geometry.y + new_f_geometry.height >= to.y + to.height)
264 new_f_geometry.y = to.y + to.height - new_f_geometry.height - 2 * c->border;
266 if(c->ismax)
268 new_geometry = c->geometry;
270 /* compute new coords in new screen */
271 new_geometry.x = (c->geometry.x - from.x) + to.x;
272 new_geometry.y = (c->geometry.y - from.y) + to.y;
274 /* check that new coords are still in the screen */
275 if(new_geometry.width > to.width)
276 new_geometry.width = to.width;
277 if(new_geometry.height > to.height)
278 new_geometry.height = to.height;
279 if(new_geometry.x + new_geometry.width >= to.x + to.width)
280 new_geometry.x = to.x + to.width - new_geometry.width - 2 * c->border;
281 if(new_geometry.y + new_geometry.height >= to.y + to.height)
282 new_geometry.y = to.y + to.height - new_geometry.height - 2 * c->border;
284 /* compute new coords for max in new screen */
285 c->m_geometry.x = (c->m_geometry.x - from.x) + to.x;
286 c->m_geometry.y = (c->m_geometry.y - from.y) + to.y;
288 /* check that new coords are still in the screen */
289 if(c->m_geometry.width > to.width)
290 c->m_geometry.width = to.width;
291 if(c->m_geometry.height > to.height)
292 c->m_geometry.height = to.height;
293 if(c->m_geometry.x + c->m_geometry.width >= to.x + to.width)
294 c->m_geometry.x = to.x + to.width - c->m_geometry.width - 2 * c->border;
295 if(c->m_geometry.y + c->m_geometry.height >= to.y + to.height)
296 c->m_geometry.y = to.y + to.height - c->m_geometry.height - 2 * c->border;
298 client_resize(c, new_geometry, False);
300 /* if floating, move to this new coords */
301 else if(c->isfloating)
302 client_resize(c, new_f_geometry, False);
303 /* otherwise just register them */
304 else
306 c->f_geometry = new_f_geometry;
307 globalconf.screens[old_screen].need_arrange = True;
308 globalconf.screens[c->screen].need_arrange = True;
313 /** Move mouse pointer to x_org and y_xorg of specified screen
314 * \param screen screen number
316 static void
317 move_mouse_pointer_to_screen(int screen)
319 if(XineramaIsActive(globalconf.display))
321 Area area = get_screen_area(screen, NULL, NULL);
322 XWarpPointer(globalconf.display,
323 None,
324 DefaultRootWindow(globalconf.display),
325 0, 0, 0, 0, area.x, area.y);
327 else
328 XWarpPointer(globalconf.display,
329 None,
330 RootWindow(globalconf.display, screen),
331 0, 0, 0, 0, 0, 0);
335 /** Switch focus to a specified screen
336 * \param screen Screen ID
337 * \param arg screen number
338 * \ingroup ui_callback
340 void
341 uicb_screen_focus(int screen, char *arg)
343 int new_screen;
345 if(arg)
346 new_screen = compute_new_value_from_arg(arg, screen);
347 else
348 new_screen = screen + 1;
350 if (new_screen < 0)
351 new_screen = globalconf.nscreen - 1;
352 if (new_screen > (globalconf.nscreen - 1))
353 new_screen = 0;
355 client_focus(NULL, new_screen, False);
357 move_mouse_pointer_to_screen(new_screen);
360 /** Move client to a virtual screen (if Xinerama is active)
361 * \param screen Screen ID
362 * \param arg screen number
363 * \ingroup ui_callback
365 void
366 uicb_client_movetoscreen(int screen __attribute__ ((unused)), char *arg)
368 int new_screen, prev_screen;
369 Client *sel = globalconf.focus->client;
371 if(!sel || !XineramaIsActive(globalconf.display))
372 return;
374 if(arg)
375 new_screen = compute_new_value_from_arg(arg, sel->screen);
376 else
377 new_screen = sel->screen + 1;
379 if(new_screen >= globalconf.nscreen)
380 new_screen = 0;
381 else if(new_screen < 0)
382 new_screen = globalconf.nscreen - 1;
384 prev_screen = sel->screen;
385 move_client_to_screen(sel, new_screen, True);
386 move_mouse_pointer_to_screen(new_screen);
387 client_focus(sel, sel->screen, False);
389 // vim: filetype=c:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=80