2 // "$Id: screen_xywh.cxx 8783 2011-06-06 09:37:21Z AlbrechtS $"
4 // Screen/monitor bounding box API for the Fast Light Tool Kit (FLTK).
6 // Copyright 1998-2010 by Bill Spitzak and others.
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Library General Public
10 // License as published by the Free Software Foundation; either
11 // version 2 of the License, or (at your option) any later version.
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 // You should have received a copy of the GNU Library General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 // Please report all bugs and problems on the following page:
25 // http://www.fltk.org/str.php
34 // Number of screens returned by multi monitor aware API; -1 before init
35 static int num_screens
= -1;
38 # if !defined(HMONITOR_DECLARED) && (_WIN32_WINNT < 0x0500)
39 # define COMPILE_MULTIMON_STUBS
40 # include <multimon.h>
41 # endif // !HMONITOR_DECLARED && _WIN32_WINNT < 0x0500
43 // We go the much more difficult route of individually picking some multi-screen
44 // functions from the USER32.DLL . If these functions are not available, we
45 // will gracefully fall back to single monitor support.
47 // If we were to insist on the existence of "EnumDisplayMonitors" and
48 // "GetMonitorInfoA", it would be impossible to use FLTK on Windows 2000
49 // before SP2 or earlier.
51 // BOOL EnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM)
52 typedef BOOL (WINAPI
* fl_edm_func
)(HDC
, LPCRECT
, MONITORENUMPROC
, LPARAM
);
53 // BOOL GetMonitorInfo(HMONITOR, LPMONITORINFO)
54 typedef BOOL (WINAPI
* fl_gmi_func
)(HMONITOR
, LPMONITORINFO
);
56 static fl_gmi_func fl_gmi
= NULL
; // used to get a proc pointer for GetMonitorInfoA
58 static RECT screens
[16];
59 static float dpi
[16][2];
61 static BOOL CALLBACK
screen_cb(HMONITOR mon
, HDC
, LPRECT r
, LPARAM
) {
62 if (num_screens
>= 16) return TRUE
;
65 mi
.cbSize
= sizeof(mi
);
67 // GetMonitorInfo(mon, &mi);
68 // (but we use our self-aquired function pointer instead)
69 if (fl_gmi(mon
, &mi
)) {
70 screens
[num_screens
] = mi
.rcMonitor
;
72 // find the pixel size
73 if (mi
.cbSize
== sizeof(mi
)) {
74 HDC screen
= CreateDC(mi
.szDevice
, NULL
, NULL
, NULL
);
76 dpi
[num_screens
][0] = (float)GetDeviceCaps(screen
, LOGPIXELSX
);
77 dpi
[num_screens
][1] = (float)GetDeviceCaps(screen
, LOGPIXELSY
);
79 ReleaseDC(0L, screen
);
87 static void screen_init() {
89 // Since not all versions of Windows include multiple monitor support,
90 // we do a run-time check for the required functions...
91 HMODULE hMod
= GetModuleHandle("USER32.DLL");
94 // check that EnumDisplayMonitors is available
95 fl_edm_func fl_edm
= (fl_edm_func
)GetProcAddress(hMod
, "EnumDisplayMonitors");
98 // We do have EnumDisplayMonitors, so lets find out how many monitors...
99 num_screens
= GetSystemMetrics(SM_CMONITORS
);
101 // if (num_screens > 1) {
102 // If there is more than 1 monitor, enumerate them...
103 fl_gmi
= (fl_gmi_func
)GetProcAddress(hMod
, "GetMonitorInfoA");
106 // We have GetMonitorInfoA, enumerate all the screens...
107 // EnumDisplayMonitors(0,0,screen_cb,0);
108 // (but we use our self-aquired function pointer instead)
109 fl_edm(0, 0, screen_cb
, 0);
116 // If we get here, assume we have 1 monitor...
120 screens
[0].right
= GetSystemMetrics(SM_CXSCREEN
);
121 screens
[0].bottom
= GetSystemMetrics(SM_CYSCREEN
);
123 #elif defined(__APPLE__)
124 static XRectangle screens
[16];
125 static float dpi_h
[16];
126 static float dpi_v
[16];
128 static void screen_init() {
129 CGDirectDisplayID displays
[16];
130 CGDisplayCount count
, i
;
132 CGGetActiveDisplayList(16, displays
, &count
);
133 for( i
= 0; i
< count
; i
++) {
134 r
= CGDisplayBounds(displays
[i
]);
135 screens
[i
].x
= int(r
.origin
.x
);
136 screens
[i
].y
= int(r
.origin
.y
);
137 screens
[i
].width
= int(r
.size
.width
);
138 screens
[i
].height
= int(r
.size
.height
);
139 CGSize s
= CGDisplayScreenSize(displays
[i
]);
140 dpi_h
[i
] = screens
[i
].width
/ (s
.width
/25.4);
141 dpi_v
[i
] = screens
[i
].height
/ (s
.height
/25.4);
146 # include <X11/extensions/Xinerama.h>
149 static XineramaScreenInfo
*screens
;
150 static float dpi
[16][2];
152 static void screen_init() {
153 if (!fl_display
) fl_open_display();
155 if (XineramaIsActive(fl_display
)) {
156 screens
= XineramaQueryScreens(fl_display
, &num_screens
);
158 // Xlib and Xinerama may disagree on the screen count. Sigh...
159 // Use the minimum of the reported counts.
160 // Use the previous screen's info for non-existent ones.
161 int sc
= ScreenCount(fl_display
); // Xlib screen count
162 for (i
=0; i
<num_screens
; i
++) {
163 int mm
= (i
< sc
) ? DisplayWidthMM(fl_display
, i
) : 0;
164 dpi
[i
][0] = mm
? screens
[i
].width
*25.4f
/mm
: (i
> 0) ? dpi
[i
-1][0] : 0.0f
;
165 mm
= (i
< sc
) ? DisplayHeightMM(fl_display
, i
) : 0;
166 dpi
[i
][1] = mm
? screens
[i
].height
*25.4f
/mm
: (i
> 0) ? dpi
[i
-1][1] : 0.0f
;
168 } else { // ! XineramaIsActive()
170 int mm
= DisplayWidthMM(fl_display
, fl_screen
);
171 dpi
[0][0] = mm
? Fl::w()*25.4f
/mm
: 0.0f
;
172 mm
= DisplayHeightMM(fl_display
, fl_screen
);
173 dpi
[0][1] = mm
? Fl::h()*25.4f
/mm
: dpi
[0][0];
178 static void screen_init() {
180 if (!fl_display
) fl_open_display();
181 int mm
= DisplayWidthMM(fl_display
, fl_screen
);
182 dpi
[0] = mm
? Fl::w()*25.4f
/mm
: 0.0f
;
183 mm
= DisplayHeightMM(fl_display
, fl_screen
);
184 dpi
[1] = mm
? Fl::h()*25.4f
/mm
: dpi
[0];
190 Gets the number of available screens.
192 int Fl::screen_count() {
193 if (num_screens
< 0) screen_init();
195 return num_screens
? num_screens
: 1;
199 Gets the bounding box of a screen
200 that contains the specified screen position \p mx, \p my
201 \param[out] X,Y,W,H the corresponding screen bounding box
202 \param[in] mx, my the absolute screen position
204 void Fl::screen_xywh(int &X
, int &Y
, int &W
, int &H
, int mx
, int my
) {
208 if (num_screens
< 0) screen_init();
210 for (i
= 0; i
< num_screens
; i
++) {
212 Fl::screen_xywh(sx
, sy
, sw
, sh
, i
);
213 if ((mx
>= sx
) && (mx
< (sx
+sw
)) && (my
>= sy
) && (my
< (sy
+sh
))) {
219 screen_xywh(X
, Y
, W
, H
, screen
);
223 Gets the screen bounding rect for the given screen.
224 \param[out] X,Y,W,H the corresponding screen bounding box
225 \param[in] n the screen number (0 to Fl::screen_count() - 1)
226 \see void screen_xywh(int &x, int &y, int &w, int &h, int mx, int my)
228 void Fl::screen_xywh(int &X
, int &Y
, int &W
, int &H
, int n
) {
229 if (num_screens
< 0) screen_init();
231 if ((n
< 0) || (n
>= num_screens
))
235 if (num_screens
> 0) {
238 W
= screens
[n
].right
- screens
[n
].left
;
239 H
= screens
[n
].bottom
- screens
[n
].top
;
241 /* Fallback if something is broken... */
244 W
= GetSystemMetrics(SM_CXSCREEN
);
245 H
= GetSystemMetrics(SM_CYSCREEN
);
247 #elif defined(__APPLE__)
248 if (num_screens
> 0) {
251 W
= screens
[n
].width
;
252 H
= screens
[n
].height
;
254 /* Fallback if something is broken... */
262 if (num_screens
> 0 && screens
) {
263 X
= screens
[n
].x_org
;
264 Y
= screens
[n
].y_org
;
265 W
= screens
[n
].width
;
266 H
= screens
[n
].height
;
268 #endif // HAVE_XINERAMA
270 /* Fallback if something is broken (or no Xinerama)... */
273 W
= DisplayWidth(fl_display
, fl_screen
);
274 H
= DisplayHeight(fl_display
, fl_screen
);
279 static inline float fl_intersection(int x1
, int y1
, int w1
, int h1
,
280 int x2
, int y2
, int w2
, int h2
) {
281 if(x1
+w1
< x2
|| x2
+w2
< x1
|| y1
+h1
< y2
|| y2
+h2
< y1
)
283 int int_left
= x1
> x2
? x1
: x2
;
284 int int_right
= x1
+w1
> x2
+w2
? x2
+w2
: x1
+w1
;
285 int int_top
= y1
> y2
? y1
: y2
;
286 int int_bottom
= y1
+h1
> y2
+h2
? y2
+h2
: y1
+h1
;
287 return (float)(int_right
- int_left
) * (int_bottom
- int_top
);
291 Gets the screen bounding rect for the screen
292 which intersects the most with the rectangle
293 defined by \p mx, \p my, \p mw, \p mh.
294 \param[out] X,Y,W,H the corresponding screen bounding box
295 \param[in] mx, my, mw, mh the rectangle to search for intersection with
296 \see void screen_xywh(int &X, int &Y, int &W, int &H, int n)
298 void Fl::screen_xywh(int &X
, int &Y
, int &W
, int &H
, int mx
, int my
, int mw
, int mh
) {
300 float best_intersection
= 0.;
301 for(int i
= 0; i
< Fl::screen_count(); i
++) {
303 Fl::screen_xywh(sx
, sy
, sw
, sh
, i
);
304 float sintersection
= fl_intersection(mx
, my
, mw
, mh
, sx
, sy
, sw
, sh
);
305 if(sintersection
> best_intersection
) {
307 best_intersection
= sintersection
;
310 screen_xywh(X
, Y
, W
, H
, best_screen
);
316 Gets the screen resolution in dots-per-inch for the given screen.
317 \param[out] h, v horizontal and vertical resolution
318 \param[in] n the screen number (0 to Fl::screen_count() - 1)
319 \see void screen_xywh(int &x, int &y, int &w, int &h, int mx, int my)
321 void Fl::screen_dpi(float &h
, float &v
, int n
)
323 if (num_screens
< 0) screen_init();
327 if (n
>= 0 && n
< num_screens
) {
328 h
= float(dpi
[n
][0]);
329 v
= float(dpi
[n
][1]);
331 #elif defined(__APPLE__)
332 if (n
>= 0 && n
< num_screens
) {
337 if (n
>= 0 && n
< num_screens
) {
342 if (n
>= 0 && n
< num_screens
) {
352 // End of "$Id: screen_xywh.cxx 8783 2011-06-06 09:37:21Z AlbrechtS $".