Update Serbian translation from master branch
[wmaker-crm.git] / src / xinerama.c
blobbb7412f916a7ef3c7b7cbef178c3fbc609100189
1 /*
2 * Window Maker window manager
4 * Copyright (c) 1997-2003 Alfredo K. Kojima
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.
21 #include <stdlib.h>
23 #include "wconfig.h"
25 #include "xinerama.h"
27 #include "screen.h"
28 #include "window.h"
29 #include "framewin.h"
30 #include "placement.h"
31 #include "dock.h"
33 #ifdef USE_XINERAMA
34 # ifdef SOLARIS_XINERAMA /* sucks */
35 # include <X11/extensions/xinerama.h>
36 # else
37 # include <X11/extensions/Xinerama.h>
38 # endif
39 #endif
41 void wInitXinerama(WScreen * scr)
43 scr->xine_info.primary_head = 0;
44 scr->xine_info.screens = NULL;
45 scr->xine_info.count = 0;
46 #ifdef USE_XINERAMA
47 # ifdef SOLARIS_XINERAMA
48 if (XineramaGetState(dpy, scr->screen)) {
49 WXineramaInfo *info = &scr->xine_info;
50 XRectangle head[MAXFRAMEBUFFERS];
51 unsigned char hints[MAXFRAMEBUFFERS];
52 int i;
54 if (XineramaGetInfo(dpy, scr->screen, head, hints, &info->count)) {
56 info->screens = wmalloc(sizeof(WMRect) * (info->count + 1));
58 for (i = 0; i < info->count; i++) {
59 info->screens[i].pos.x = head[i].x;
60 info->screens[i].pos.y = head[i].y;
61 info->screens[i].size.width = head[i].width;
62 info->screens[i].size.height = head[i].height;
66 # else /* !SOLARIS_XINERAMA */
67 if (XineramaIsActive(dpy)) {
68 XineramaScreenInfo *xine_screens;
69 WXineramaInfo *info = &scr->xine_info;
70 int i;
72 xine_screens = XineramaQueryScreens(dpy, &info->count);
74 info->screens = wmalloc(sizeof(WMRect) * (info->count + 1));
76 for (i = 0; i < info->count; i++) {
77 info->screens[i].pos.x = xine_screens[i].x_org;
78 info->screens[i].pos.y = xine_screens[i].y_org;
79 info->screens[i].size.width = xine_screens[i].width;
80 info->screens[i].size.height = xine_screens[i].height;
82 XFree(xine_screens);
84 # endif /* !SOLARIS_XINERAMA */
85 #endif /* USE_XINERAMA */
88 int wGetRectPlacementInfo(WScreen * scr, WMRect rect, int *flags)
90 int best;
91 unsigned long area, totalArea;
92 int i;
93 int rx = rect.pos.x;
94 int ry = rect.pos.y;
95 int rw = rect.size.width;
96 int rh = rect.size.height;
98 wassertrv(flags != NULL, 0);
100 best = -1;
101 area = 0;
102 totalArea = 0;
104 *flags = XFLAG_NONE;
106 if (scr->xine_info.count <= 1) {
107 unsigned long a;
109 a = calcIntersectionArea(rx, ry, rw, rh, 0, 0, scr->scr_width, scr->scr_height);
111 if (a == 0) {
112 *flags |= XFLAG_DEAD;
113 } else if (a != rw * rh) {
114 *flags |= XFLAG_PARTIAL;
117 return scr->xine_info.primary_head;
120 for (i = 0; i < wXineramaHeads(scr); i++) {
121 unsigned long a;
123 a = calcIntersectionArea(rx, ry, rw, rh,
124 scr->xine_info.screens[i].pos.x,
125 scr->xine_info.screens[i].pos.y,
126 scr->xine_info.screens[i].size.width,
127 scr->xine_info.screens[i].size.height);
129 totalArea += a;
130 if (a > area) {
131 if (best != -1)
132 *flags |= XFLAG_MULTIPLE;
133 area = a;
134 best = i;
138 if (best == -1) {
139 *flags |= XFLAG_DEAD;
140 best = wGetHeadForPointerLocation(scr);
141 } else if (totalArea != rw * rh)
142 *flags |= XFLAG_PARTIAL;
144 return best;
147 /* get the head that covers most of the rectangle */
148 int wGetHeadForRect(WScreen * scr, WMRect rect)
150 int best;
151 unsigned long area;
152 int i;
153 int rx = rect.pos.x;
154 int ry = rect.pos.y;
155 int rw = rect.size.width;
156 int rh = rect.size.height;
158 if (!scr->xine_info.count)
159 return scr->xine_info.primary_head;
161 best = -1;
162 area = 0;
164 for (i = 0; i < wXineramaHeads(scr); i++) {
165 unsigned long a;
167 a = calcIntersectionArea(rx, ry, rw, rh,
168 scr->xine_info.screens[i].pos.x,
169 scr->xine_info.screens[i].pos.y,
170 scr->xine_info.screens[i].size.width,
171 scr->xine_info.screens[i].size.height);
173 if (a > area) {
174 area = a;
175 best = i;
180 * in case rect is in dead space, return valid head
182 if (best == -1)
183 best = wGetHeadForPointerLocation(scr);
185 return best;
188 Bool wWindowTouchesHead(WWindow * wwin, int head)
190 WScreen *scr;
191 WMRect rect;
192 int a;
194 if (!wwin || !wwin->frame)
195 return False;
197 scr = wwin->screen_ptr;
198 rect = wGetRectForHead(scr, head);
199 a = calcIntersectionArea(wwin->frame_x, wwin->frame_y,
200 wwin->frame->core->width,
201 wwin->frame->core->height,
202 rect.pos.x, rect.pos.y, rect.size.width, rect.size.height);
204 return (a != 0);
207 Bool wAppIconTouchesHead(WAppIcon * aicon, int head)
209 WScreen *scr;
210 WMRect rect;
211 int a;
213 if (!aicon || !aicon->icon)
214 return False;
216 scr = aicon->icon->core->screen_ptr;
217 rect = wGetRectForHead(scr, head);
218 a = calcIntersectionArea(aicon->x_pos, aicon->y_pos,
219 aicon->icon->core->width,
220 aicon->icon->core->height,
221 rect.pos.x, rect.pos.y, rect.size.width, rect.size.height);
223 return (a != 0);
226 int wGetHeadForWindow(WWindow * wwin)
228 WMRect rect;
230 if (wwin == NULL || wwin->frame == NULL)
231 return 0;
233 rect.pos.x = wwin->frame_x;
234 rect.pos.y = wwin->frame_y;
235 rect.size.width = wwin->frame->core->width;
236 rect.size.height = wwin->frame->core->height;
238 return wGetHeadForRect(wwin->screen_ptr, rect);
241 /* Find head on left, right, up or down direction relative to current
242 head. If there is no screen available on pointed direction, -1 will be
243 returned.*/
244 int wGetHeadRelativeToCurrentHead(WScreen *scr, int current_head, int direction)
246 short int found = 0;
247 int i;
248 int distance = 0;
249 int smallest_distance = 0;
250 int nearest_head = scr->xine_info.primary_head;
251 WMRect crect = wGetRectForHead(scr, current_head);
253 for (i = 0; i < scr->xine_info.count; i++) {
254 if (i == current_head)
255 continue;
257 WMRect *rect = &scr->xine_info.screens[i];
259 /* calculate distance from the next screen to current one */
260 switch (direction) {
261 case DIRECTION_LEFT:
262 if (rect->pos.x < crect.pos.x) {
263 found = 1;
264 distance = abs((rect->pos.x + (int)rect->size.width)
265 - crect.pos.x) + abs(rect->pos.y + crect.pos.y);
267 break;
268 case DIRECTION_RIGHT:
269 if (rect->pos.x > crect.pos.x) {
270 found = 1;
271 distance = abs((crect.pos.x + (int)crect.size.width)
272 - rect->pos.x) + abs(rect->pos.y + crect.pos.y);
274 break;
275 case DIRECTION_UP:
276 if (rect->pos.y < crect.pos.y) {
277 found = 1;
278 distance = abs((rect->pos.y + (int)rect->size.height)
279 - crect.pos.y) + abs(rect->pos.x + crect.pos.x);
281 break;
282 case DIRECTION_DOWN:
283 if (rect->pos.y > crect.pos.y) {
284 found = 1;
285 distance = abs((crect.pos.y + (int)crect.size.height)
286 - rect->pos.y) + abs(rect->pos.x + crect.pos.x);
288 break;
291 if (found && distance == 0)
292 return i;
294 if (smallest_distance == 0)
295 smallest_distance = distance;
297 if (abs(distance) <= smallest_distance) {
298 smallest_distance = distance;
299 nearest_head = i;
303 if (found && smallest_distance != 0 && nearest_head != current_head)
304 return nearest_head;
306 return -1;
309 int wGetHeadForPoint(WScreen * scr, WMPoint point)
311 int i;
313 for (i = 0; i < scr->xine_info.count; i++) {
314 WMRect *rect = &scr->xine_info.screens[i];
316 if ((unsigned)(point.x - rect->pos.x) < rect->size.width &&
317 (unsigned)(point.y - rect->pos.y) < rect->size.height)
318 return i;
320 return scr->xine_info.primary_head;
323 int wGetHeadForPointerLocation(WScreen * scr)
325 WMPoint point;
326 Window bla;
327 int ble;
328 unsigned int blo;
330 if (!scr->xine_info.count)
331 return scr->xine_info.primary_head;
333 if (!XQueryPointer(dpy, scr->root_win, &bla, &bla, &point.x, &point.y, &ble, &ble, &blo))
334 return scr->xine_info.primary_head;
336 return wGetHeadForPoint(scr, point);
339 /* get the dimensions of the head */
340 WMRect wGetRectForHead(WScreen * scr, int head)
342 WMRect rect;
344 if (head < scr->xine_info.count) {
345 rect.pos.x = scr->xine_info.screens[head].pos.x;
346 rect.pos.y = scr->xine_info.screens[head].pos.y;
347 rect.size.width = scr->xine_info.screens[head].size.width;
348 rect.size.height = scr->xine_info.screens[head].size.height;
349 } else {
350 rect.pos.x = 0;
351 rect.pos.y = 0;
352 rect.size.width = scr->scr_width;
353 rect.size.height = scr->scr_height;
356 return rect;
359 WArea wGetUsableAreaForHead(WScreen * scr, int head, WArea * totalAreaPtr, Bool noicons)
361 WArea totalArea, usableArea;
362 WMRect rect = wGetRectForHead(scr, head);
364 totalArea.x1 = rect.pos.x;
365 totalArea.y1 = rect.pos.y;
366 totalArea.x2 = totalArea.x1 + rect.size.width;
367 totalArea.y2 = totalArea.y1 + rect.size.height;
369 if (totalAreaPtr != NULL)
370 *totalAreaPtr = totalArea;
372 if (head < wXineramaHeads(scr)) {
373 usableArea = noicons ? scr->totalUsableArea[head] : scr->usableArea[head];
374 } else
375 usableArea = totalArea;
377 if (noicons) {
378 /* check if user wants dock covered */
379 if (scr->dock && wPreferences.no_window_over_dock && wAppIconTouchesHead(scr->dock->icon_array[0], head)) {
380 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
382 if (scr->dock->on_right_side)
383 usableArea.x2 -= offset;
384 else
385 usableArea.x1 += offset;
388 /* check if icons are on the same side as dock, and adjust if not done already */
389 if (scr->dock && wPreferences.no_window_over_icons && !wPreferences.no_window_over_dock && (wPreferences.icon_yard & IY_VERT)) {
390 int offset = wPreferences.icon_size + DOCK_EXTRA_SPACE;
392 if (scr->dock->on_right_side && (wPreferences.icon_yard & IY_RIGHT))
393 usableArea.x2 -= offset;
394 /* can't use IY_LEFT in if, it's 0 ... */
395 if (!scr->dock->on_right_side && !(wPreferences.icon_yard & IY_RIGHT))
396 usableArea.x1 += offset;
400 return usableArea;
403 WMPoint wGetPointToCenterRectInHead(WScreen * scr, int head, int width, int height)
405 WMPoint p;
406 WMRect rect = wGetRectForHead(scr, head);
408 p.x = rect.pos.x + (rect.size.width - width) / 2;
409 p.y = rect.pos.y + (rect.size.height - height) / 2;
411 return p;
414 /* Find the bounding rect of the union of two rectangles */
415 void wGetRectUnion(const WMRect *rect1, const WMRect *rect2, WMRect *dest)
417 int dest_x, dest_y;
418 int dest_w, dest_h;
420 dest_x = rect1->pos.x;
421 dest_y = rect1->pos.y;
422 dest_w = rect1->size.width;
423 dest_h = rect1->size.height;
425 if (rect2->pos.x < dest_x) {
426 dest_w += dest_x - rect2->pos.x;
427 dest_x = rect2->pos.x;
429 if (rect2->pos.y < dest_y) {
430 dest_h += dest_y - rect2->pos.y;
431 dest_y = rect2->pos.y;
433 if (rect2->pos.x + rect2->size.width > dest_x + dest_w)
434 dest_w = rect2->pos.x + rect2->size.width - dest_x;
435 if (rect2->pos.y + rect2->size.height > dest_y + dest_h)
436 dest_h = rect2->pos.y + rect2->size.height - dest_y;
438 dest->pos.x = dest_x;
439 dest->pos.y = dest_y;
440 dest->size.width = dest_w;
441 dest->size.height = dest_h;