Change to the linux kernel coding style
[wmaker-crm.git] / src / xinerama.c
1 /*
2  *  Window Maker window manager
3  *
4  *  Copyright (c) 1997-2003 Alfredo K. Kojima
5  *
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.
10  *
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.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
19  *  USA.
20  */
21
22 #include "wconfig.h"
23
24 #include "xinerama.h"
25
26 #include "screen.h"
27 #include "window.h"
28 #include "framewin.h"
29 #include "wcore.h"
30 #include "funcs.h"
31
32 #ifdef XINERAMA
33 # ifdef SOLARIS_XINERAMA        /* sucks */
34 #  include <X11/extensions/xinerama.h>
35 # else
36 #  include <X11/extensions/Xinerama.h>
37 # endif
38 #endif
39
40 extern WPreferences wPreferences;
41
42 void wInitXinerama(WScreen * scr)
43 {
44         scr->xine_info.primary_head = 0;
45         scr->xine_info.screens = NULL;
46         scr->xine_info.count = 0;
47 #ifdef XINERAMA
48 # ifdef SOLARIS_XINERAMA
49         if (XineramaGetState(dpy, scr->screen)) {
50                 WXineramaInfo *info = &scr->xine_info;
51                 XRectangle head[MAXFRAMEBUFFERS];
52                 unsigned char hints[MAXFRAMEBUFFERS];
53                 int i;
54
55                 if (XineramaGetInfo(dpy, scr->screen, head, hints, &info->count)) {
56
57                         info->screens = wmalloc(sizeof(WMRect) * (info->count + 1));
58
59                         for (i = 0; i < info->count; i++) {
60                                 info->screens[i].pos.x = head[i].x;
61                                 info->screens[i].pos.y = head[i].y;
62                                 info->screens[i].size.width = head[i].width;
63                                 info->screens[i].size.height = head[i].height;
64                         }
65                 }
66         }
67 # else                          /* !SOLARIS_XINERAMA */
68         if (XineramaIsActive(dpy)) {
69                 XineramaScreenInfo *xine_screens;
70                 WXineramaInfo *info = &scr->xine_info;
71                 int i;
72
73                 xine_screens = XineramaQueryScreens(dpy, &info->count);
74
75                 info->screens = wmalloc(sizeof(WMRect) * (info->count + 1));
76
77                 for (i = 0; i < info->count; i++) {
78                         info->screens[i].pos.x = xine_screens[i].x_org;
79                         info->screens[i].pos.y = xine_screens[i].y_org;
80                         info->screens[i].size.width = xine_screens[i].width;
81                         info->screens[i].size.height = xine_screens[i].height;
82                 }
83                 XFree(xine_screens);
84         }
85 # endif                         /* !SOLARIS_XINERAMA */
86 #endif                          /* XINERAMA */
87 }
88
89 int wGetRectPlacementInfo(WScreen * scr, WMRect rect, int *flags)
90 {
91         int best;
92         unsigned long area, totalArea;
93         int i;
94         int rx = rect.pos.x;
95         int ry = rect.pos.y;
96         int rw = rect.size.width;
97         int rh = rect.size.height;
98
99         wassertrv(flags != NULL, 0);
100
101         best = -1;
102         area = 0;
103         totalArea = 0;
104
105         *flags = XFLAG_NONE;
106
107         if (scr->xine_info.count <= 1) {
108                 unsigned long a;
109
110                 a = calcIntersectionArea(rx, ry, rw, rh, 0, 0, scr->scr_width, scr->scr_height);
111
112                 if (a == 0) {
113                         *flags |= XFLAG_DEAD;
114                 } else if (a != rw * rh) {
115                         *flags |= XFLAG_PARTIAL;
116                 }
117
118                 return scr->xine_info.primary_head;
119         }
120
121         for (i = 0; i < wXineramaHeads(scr); i++) {
122                 unsigned long a;
123
124                 a = calcIntersectionArea(rx, ry, rw, rh,
125                                          scr->xine_info.screens[i].pos.x,
126                                          scr->xine_info.screens[i].pos.y,
127                                          scr->xine_info.screens[i].size.width,
128                                          scr->xine_info.screens[i].size.height);
129
130                 totalArea += a;
131                 if (a > area) {
132                         if (best != -1)
133                                 *flags |= XFLAG_MULTIPLE;
134                         area = a;
135                         best = i;
136                 }
137         }
138
139         if (best == -1) {
140                 *flags |= XFLAG_DEAD;
141                 best = wGetHeadForPointerLocation(scr);
142         } else if (totalArea != rw * rh)
143                 *flags |= XFLAG_PARTIAL;
144
145         return best;
146 }
147
148 /* get the head that covers most of the rectangle */
149 int wGetHeadForRect(WScreen * scr, WMRect rect)
150 {
151         int best;
152         unsigned long area;
153         int i;
154         int rx = rect.pos.x;
155         int ry = rect.pos.y;
156         int rw = rect.size.width;
157         int rh = rect.size.height;
158
159         if (!scr->xine_info.count)
160                 return scr->xine_info.primary_head;
161
162         best = -1;
163         area = 0;
164
165         for (i = 0; i < wXineramaHeads(scr); i++) {
166                 unsigned long a;
167
168                 a = calcIntersectionArea(rx, ry, rw, rh,
169                                          scr->xine_info.screens[i].pos.x,
170                                          scr->xine_info.screens[i].pos.y,
171                                          scr->xine_info.screens[i].size.width,
172                                          scr->xine_info.screens[i].size.height);
173
174                 if (a > area) {
175                         area = a;
176                         best = i;
177                 }
178         }
179
180         /*
181          * in case rect is in dead space, return valid head
182          */
183         if (best == -1)
184                 best = wGetHeadForPointerLocation(scr);
185
186         return best;
187 }
188
189 Bool wWindowTouchesHead(WWindow * wwin, int head)
190 {
191         WScreen *scr;
192         WMRect rect;
193         int a;
194
195         if (!wwin || !wwin->frame)
196                 return False;
197
198         scr = wwin->screen_ptr;
199         rect = wGetRectForHead(scr, head);
200         a = calcIntersectionArea(wwin->frame_x, wwin->frame_y,
201                                  wwin->frame->core->width,
202                                  wwin->frame->core->height,
203                                  rect.pos.x, rect.pos.y, rect.size.width, rect.size.height);
204
205         return (a != 0);
206 }
207
208 int wGetHeadForWindow(WWindow * wwin)
209 {
210         WMRect rect;
211
212         if (wwin == NULL || wwin->frame == NULL)
213                 return 0;
214
215         rect.pos.x = wwin->frame_x;
216         rect.pos.y = wwin->frame_y;
217         rect.size.width = wwin->frame->core->width;
218         rect.size.height = wwin->frame->core->height;
219
220         return wGetHeadForRect(wwin->screen_ptr, rect);
221 }
222
223 /*
224 int
225 wGetHeadForPoint(WScreen *scr, WMPoint point, int *flags)
226 {
227     int i;
228
229     // paranoia
230     if (flags == NULL) {
231         static int tmp;
232         flags = &tmp;
233     }
234     *flags = XFLAG_NONE;
235
236     for (i = 0; i < scr->xine_info.count; i++) {
237 #if 0
238         int yy, xx;
239
240         xx = scr->xine_info.screens[i].pos.x + scr->xine_info.screens[i].size.width;
241         yy = scr->xine_info.screens[i].pos.y + scr->xine_info.screens[i].size.height;
242         if (point.x >= scr->xine_info.screens[i].pos.x &&
243             point.y >= scr->xine_info.screens[i].pos.y &&
244             point.x < xx && point.y < yy) {
245             return i;
246         }
247 #else
248         XineramaScreenInfo *xsi = &scr->xine_info.screens[i];
249
250         if ((unsigned)(point.x - xsi->x_org) < xsi->width &&
251             (unsigned)(point.y - xsi->y_org) < xsi->height)
252             return i;
253 #endif
254     }
255
256     *flags |= XFLAG_DEAD;
257
258     return scr->xine_primary_head;
259 }
260 */
261
262 int wGetHeadForPoint(WScreen * scr, WMPoint point)
263 {
264         int i;
265
266         for (i = 0; i < scr->xine_info.count; i++) {
267                 WMRect *rect = &scr->xine_info.screens[i];
268
269                 if ((unsigned)(point.x - rect->pos.x) < rect->size.width &&
270                     (unsigned)(point.y - rect->pos.y) < rect->size.height)
271                         return i;
272         }
273         return scr->xine_info.primary_head;
274 }
275
276 int wGetHeadForPointerLocation(WScreen * scr)
277 {
278         WMPoint point;
279         Window bla;
280         int ble;
281         unsigned int blo;
282
283         if (!scr->xine_info.count)
284                 return scr->xine_info.primary_head;
285
286         if (!XQueryPointer(dpy, scr->root_win, &bla, &bla, &point.x, &point.y, &ble, &ble, &blo))
287                 return scr->xine_info.primary_head;
288
289         return wGetHeadForPoint(scr, point);
290 }
291
292 /* get the dimensions of the head */
293 WMRect wGetRectForHead(WScreen * scr, int head)
294 {
295         WMRect rect;
296
297         if (head < scr->xine_info.count) {
298                 rect.pos.x = scr->xine_info.screens[head].pos.x;
299                 rect.pos.y = scr->xine_info.screens[head].pos.y;
300                 rect.size.width = scr->xine_info.screens[head].size.width;
301                 rect.size.height = scr->xine_info.screens[head].size.height;
302         } else {
303                 rect.pos.x = 0;
304                 rect.pos.y = 0;
305                 rect.size.width = scr->scr_width;
306                 rect.size.height = scr->scr_height;
307         }
308
309         return rect;
310 }
311
312 WArea wGetUsableAreaForHead(WScreen * scr, int head, WArea * totalAreaPtr, Bool noicons)
313 {
314         WArea totalArea, usableArea;
315         WMRect rect = wGetRectForHead(scr, head);
316
317         totalArea.x1 = rect.pos.x;
318         totalArea.y1 = rect.pos.y;
319         totalArea.x2 = totalArea.x1 + rect.size.width;
320         totalArea.y2 = totalArea.y1 + rect.size.height;
321
322         if (totalAreaPtr != NULL)
323                 *totalAreaPtr = totalArea;
324
325         if (head < wXineramaHeads(scr)) {
326                 usableArea = noicons ? scr->totalUsableArea[head] : scr->usableArea[head];
327         } else
328                 usableArea = totalArea;
329
330         return usableArea;
331 }
332
333 WMPoint wGetPointToCenterRectInHead(WScreen * scr, int head, int width, int height)
334 {
335         WMPoint p;
336         WMRect rect = wGetRectForHead(scr, head);
337
338         p.x = rect.pos.x + (rect.size.width - width) / 2;
339         p.y = rect.pos.y + (rect.size.height - height) / 2;
340
341         return p;
342 }