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.
30 #include "placement.h"
34 # ifdef SOLARIS_XINERAMA /* sucks */
35 # include <X11/extensions/xinerama.h>
37 # include <X11/extensions/Xinerama.h>
41 void wInitXinerama(WScreen
* scr
)
43 scr
->xine_info
.primary_head
= 0;
44 scr
->xine_info
.screens
= NULL
;
45 scr
->xine_info
.count
= 0;
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
];
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
;
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
;
84 # endif /* !SOLARIS_XINERAMA */
85 #endif /* USE_XINERAMA */
88 int wGetRectPlacementInfo(WScreen
* scr
, WMRect rect
, int *flags
)
91 unsigned long area
, totalArea
;
95 int rw
= rect
.size
.width
;
96 int rh
= rect
.size
.height
;
98 wassertrv(flags
!= NULL
, 0);
106 if (scr
->xine_info
.count
<= 1) {
109 a
= calcIntersectionArea(rx
, ry
, rw
, rh
, 0, 0, scr
->scr_width
, scr
->scr_height
);
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
++) {
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
);
132 *flags
|= XFLAG_MULTIPLE
;
139 *flags
|= XFLAG_DEAD
;
140 best
= wGetHeadForPointerLocation(scr
);
141 } else if (totalArea
!= rw
* rh
)
142 *flags
|= XFLAG_PARTIAL
;
147 /* get the head that covers most of the rectangle */
148 int wGetHeadForRect(WScreen
* scr
, WMRect rect
)
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
;
164 for (i
= 0; i
< wXineramaHeads(scr
); i
++) {
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
);
180 * in case rect is in dead space, return valid head
183 best
= wGetHeadForPointerLocation(scr
);
188 Bool
wWindowTouchesHead(WWindow
* wwin
, int head
)
194 if (!wwin
|| !wwin
->frame
)
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
);
207 Bool
wAppIconTouchesHead(WAppIcon
* aicon
, int head
)
213 if (!aicon
|| !aicon
->icon
)
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
);
226 int wGetHeadForWindow(WWindow
* wwin
)
230 if (wwin
== NULL
|| wwin
->frame
== NULL
)
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
244 int wGetHeadRelativeToCurrentHead(WScreen
*scr
, int current_head
, int direction
)
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
)
257 WMRect
*rect
= &scr
->xine_info
.screens
[i
];
259 /* calculate distance from the next screen to current one */
262 if (rect
->pos
.x
< crect
.pos
.x
) {
264 distance
= abs((rect
->pos
.x
+ (int)rect
->size
.width
)
265 - crect
.pos
.x
) + abs(rect
->pos
.y
+ crect
.pos
.y
);
268 case DIRECTION_RIGHT
:
269 if (rect
->pos
.x
> crect
.pos
.x
) {
271 distance
= abs((crect
.pos
.x
+ (int)crect
.size
.width
)
272 - rect
->pos
.x
) + abs(rect
->pos
.y
+ crect
.pos
.y
);
276 if (rect
->pos
.y
< crect
.pos
.y
) {
278 distance
= abs((rect
->pos
.y
+ (int)rect
->size
.height
)
279 - crect
.pos
.y
) + abs(rect
->pos
.x
+ crect
.pos
.x
);
283 if (rect
->pos
.y
> crect
.pos
.y
) {
285 distance
= abs((crect
.pos
.y
+ (int)crect
.size
.height
)
286 - rect
->pos
.y
) + abs(rect
->pos
.x
+ crect
.pos
.x
);
291 if (found
&& distance
== 0)
294 if (smallest_distance
== 0)
295 smallest_distance
= distance
;
297 if (abs(distance
) <= smallest_distance
) {
298 smallest_distance
= distance
;
303 if (found
&& smallest_distance
!= 0 && nearest_head
!= current_head
)
309 int wGetHeadForPoint(WScreen
* scr
, WMPoint point
)
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
)
320 return scr
->xine_info
.primary_head
;
323 int wGetHeadForPointerLocation(WScreen
* scr
)
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
)
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
;
352 rect
.size
.width
= scr
->scr_width
;
353 rect
.size
.height
= scr
->scr_height
;
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
];
375 usableArea
= totalArea
;
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
;
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
;
403 WMPoint
wGetPointToCenterRectInHead(WScreen
* scr
, int head
, int width
, int height
)
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;
414 /* Find the bounding rect of the union of two rectangles */
415 void wGetRectUnion(const WMRect
*rect1
, const WMRect
*rect2
, WMRect
*dest
)
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
;