blob: 5cf37598606678993916c2b65af214e3bdffa51e [file] [log] [blame]
DRC2ff39b82011-07-28 08:38:59 +00001//
2// "$Id: screen_xywh.cxx 8783 2011-06-06 09:37:21Z AlbrechtS $"
3//
4// Screen/monitor bounding box API for the Fast Light Tool Kit (FLTK).
5//
6// Copyright 1998-2010 by Bill Spitzak and others.
7//
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.
12//
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.
17//
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
21// USA.
22//
23// Please report all bugs and problems on the following page:
24//
25// http://www.fltk.org/str.php
26//
27
28
29#include <FL/Fl.H>
30#include <FL/x.H>
31#include <config.h>
32
33
34// Number of screens returned by multi monitor aware API; -1 before init
35static int num_screens = -1;
36
37#ifdef WIN32
38# if !defined(HMONITOR_DECLARED) && (_WIN32_WINNT < 0x0500)
39# define COMPILE_MULTIMON_STUBS
40# include <multimon.h>
41# endif // !HMONITOR_DECLARED && _WIN32_WINNT < 0x0500
42
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.
46//
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.
50
51// BOOL EnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM)
52typedef BOOL (WINAPI* fl_edm_func)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
53// BOOL GetMonitorInfo(HMONITOR, LPMONITORINFO)
54typedef BOOL (WINAPI* fl_gmi_func)(HMONITOR, LPMONITORINFO);
55
56static fl_gmi_func fl_gmi = NULL; // used to get a proc pointer for GetMonitorInfoA
57
58static RECT screens[16];
59static float dpi[16][2];
60
61static BOOL CALLBACK screen_cb(HMONITOR mon, HDC, LPRECT r, LPARAM) {
62 if (num_screens >= 16) return TRUE;
63
64 MONITORINFOEX mi;
65 mi.cbSize = sizeof(mi);
66
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;
71
72 // find the pixel size
73 if (mi.cbSize == sizeof(mi)) {
74 HDC screen = CreateDC(mi.szDevice, NULL, NULL, NULL);
75 if (screen) {
76 dpi[num_screens][0] = (float)GetDeviceCaps(screen, LOGPIXELSX);
77 dpi[num_screens][1] = (float)GetDeviceCaps(screen, LOGPIXELSY);
78 }
79 ReleaseDC(0L, screen);
80 }
81
82 num_screens ++;
83 }
84 return TRUE;
85}
86
87static void screen_init() {
88 num_screens = 0;
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");
92
93 if (hMod) {
94 // check that EnumDisplayMonitors is available
95 fl_edm_func fl_edm = (fl_edm_func)GetProcAddress(hMod, "EnumDisplayMonitors");
96
97 if (fl_edm) {
98 // We do have EnumDisplayMonitors, so lets find out how many monitors...
99 num_screens = GetSystemMetrics(SM_CMONITORS);
100
101// if (num_screens > 1) {
102 // If there is more than 1 monitor, enumerate them...
103 fl_gmi = (fl_gmi_func)GetProcAddress(hMod, "GetMonitorInfoA");
104
105 if (fl_gmi) {
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);
110 return;
111 }
112// }
113 }
114 }
115
116 // If we get here, assume we have 1 monitor...
117 num_screens = 1;
118 screens[0].top = 0;
119 screens[0].left = 0;
120 screens[0].right = GetSystemMetrics(SM_CXSCREEN);
121 screens[0].bottom = GetSystemMetrics(SM_CYSCREEN);
122}
123#elif defined(__APPLE__)
124static XRectangle screens[16];
125static float dpi_h[16];
126static float dpi_v[16];
127
128static void screen_init() {
129 CGDirectDisplayID displays[16];
130 CGDisplayCount count, i;
131 CGRect r;
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);
142 }
143 num_screens = count;
144}
145#elif HAVE_XINERAMA
146# include <X11/extensions/Xinerama.h>
147
148// Screen data...
149static XineramaScreenInfo *screens;
150static float dpi[16][2];
151
152static void screen_init() {
153 if (!fl_display) fl_open_display();
154
155 if (XineramaIsActive(fl_display)) {
156 screens = XineramaQueryScreens(fl_display, &num_screens);
157 int i;
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;
167 }
168 } else { // ! XineramaIsActive()
169 num_screens = 1;
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];
174 }
175}
176#else
177static float dpi[2];
178static void screen_init() {
179 num_screens = 1;
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];
185}
186#endif // WIN32
187
188
189/**
190 Gets the number of available screens.
191*/
192int Fl::screen_count() {
193 if (num_screens < 0) screen_init();
194
195 return num_screens ? num_screens : 1;
196}
197
198/**
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
203*/
204void Fl::screen_xywh(int &X, int &Y, int &W, int &H, int mx, int my) {
205 int screen = 0;
206 int i;
207
208 if (num_screens < 0) screen_init();
209
210 for (i = 0; i < num_screens; i ++) {
211 int sx, sy, sw, sh;
212 Fl::screen_xywh(sx, sy, sw, sh, i);
213 if ((mx >= sx) && (mx < (sx+sw)) && (my >= sy) && (my < (sy+sh))) {
214 screen = i;
215 break;
216 }
217 }
218
219 screen_xywh(X, Y, W, H, screen);
220}
221
222/**
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)
227*/
228void Fl::screen_xywh(int &X, int &Y, int &W, int &H, int n) {
229 if (num_screens < 0) screen_init();
230
231 if ((n < 0) || (n >= num_screens))
232 n = 0;
233
234#ifdef WIN32
235 if (num_screens > 0) {
236 X = screens[n].left;
237 Y = screens[n].top;
238 W = screens[n].right - screens[n].left;
239 H = screens[n].bottom - screens[n].top;
240 } else {
241 /* Fallback if something is broken... */
242 X = 0;
243 Y = 0;
244 W = GetSystemMetrics(SM_CXSCREEN);
245 H = GetSystemMetrics(SM_CYSCREEN);
246 }
247#elif defined(__APPLE__)
248 if (num_screens > 0) {
249 X = screens[n].x;
250 Y = screens[n].y;
251 W = screens[n].width;
252 H = screens[n].height;
253 } else {
254 /* Fallback if something is broken... */
255 X = Fl::x();
256 Y = Fl::y();
257 W = Fl::w();
258 H = Fl::h();
259 }
260#else
261#if HAVE_XINERAMA
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;
267 } else
268#endif // HAVE_XINERAMA
269 {
270 /* Fallback if something is broken (or no Xinerama)... */
271 X = 0;
272 Y = 0;
273 W = DisplayWidth(fl_display, fl_screen);
274 H = DisplayHeight(fl_display, fl_screen);
275 }
276#endif // WIN32
277}
278
279static 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)
282 return 0.;
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);
288}
289
290/**
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)
297 */
298void Fl::screen_xywh(int &X, int &Y, int &W, int &H, int mx, int my, int mw, int mh) {
299 int best_screen = 0;
300 float best_intersection = 0.;
301 for(int i = 0; i < Fl::screen_count(); i++) {
302 int sx, sy, sw, sh;
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) {
306 best_screen = i;
307 best_intersection = sintersection;
308 }
309 }
310 screen_xywh(X, Y, W, H, best_screen);
311}
312
313
314
315/**
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)
320 */
321void Fl::screen_dpi(float &h, float &v, int n)
322{
323 if (num_screens < 0) screen_init();
324 h = v = 0.0f;
325
326#ifdef WIN32
327 if (n >= 0 && n < num_screens) {
328 h = float(dpi[n][0]);
329 v = float(dpi[n][1]);
330 }
331#elif defined(__APPLE__)
332 if (n >= 0 && n < num_screens) {
333 h = dpi_h[n];
334 v = dpi_v[n];
335 }
336#elif HAVE_XINERAMA
337 if (n >= 0 && n < num_screens) {
338 h = dpi[n][0];
339 v = dpi[n][1];
340 }
341#else
342 if (n >= 0 && n < num_screens) {
343 h = dpi[0];
344 v = dpi[1];
345 }
346#endif // WIN32
347}
348
349
350
351//
352// End of "$Id: screen_xywh.cxx 8783 2011-06-06 09:37:21Z AlbrechtS $".
353//