Fl_WinAPI_Screen_Driver.cxx 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661
  1. //
  2. // "$Id: Fl_WinAPI_Screen_Driver.cxx 12628 2018-01-09 07:26:49Z manolo $"
  3. //
  4. // Definition of MSWindows Win32/64 Screen interface
  5. //
  6. // Copyright 1998-2017 by Bill Spitzak and others.
  7. //
  8. // This library is free software. Distribution and use rights are outlined in
  9. // the file "COPYING" which should have been included with this file. If this
  10. // file is missing or damaged, see the license at:
  11. //
  12. // http://www.fltk.org/COPYING.php
  13. //
  14. // Please report all bugs and problems on the following page:
  15. //
  16. // http://www.fltk.org/str.php
  17. //
  18. #include "../../config_lib.h"
  19. #include "Fl_WinAPI_Screen_Driver.H"
  20. #include "../GDI/Fl_Font.H"
  21. #include <FL/Fl.H>
  22. #include <FL/x.H>
  23. #include <FL/Fl_Graphics_Driver.H>
  24. #include <FL/Fl_RGB_Image.H>
  25. #include <FL/fl_ask.H>
  26. #include <stdio.h>
  27. // these are set by Fl::args() and override any system colors: from Fl_get_system_colors.cxx
  28. extern const char *fl_fg;
  29. extern const char *fl_bg;
  30. extern const char *fl_bg2;
  31. // end of extern additions workaround
  32. #if !defined(HMONITOR_DECLARED) && (_WIN32_WINNT < 0x0500)
  33. # define COMPILE_MULTIMON_STUBS
  34. # include <multimon.h>
  35. #endif // !HMONITOR_DECLARED && _WIN32_WINNT < 0x0500
  36. /*
  37. Creates a driver that manages all screen and display related calls.
  38. This function must be implemented once for every platform.
  39. */
  40. Fl_Screen_Driver *Fl_Screen_Driver::newScreenDriver()
  41. {
  42. return new Fl_WinAPI_Screen_Driver();
  43. }
  44. int Fl_WinAPI_Screen_Driver::visual(int flags)
  45. {
  46. fl_GetDC(0);
  47. if (flags & FL_DOUBLE) return 0;
  48. HDC gc = (HDC)Fl_Graphics_Driver::default_driver().gc();
  49. if (!(flags & FL_INDEX) &&
  50. GetDeviceCaps(gc,BITSPIXEL) <= 8) return 0;
  51. if ((flags & FL_RGB8) && GetDeviceCaps(gc,BITSPIXEL)<24) return 0;
  52. return 1;
  53. }
  54. // We go the much more difficult route of individually picking some multi-screen
  55. // functions from the USER32.DLL . If these functions are not available, we
  56. // will gracefully fall back to single monitor support.
  57. //
  58. // If we were to insist on the existence of "EnumDisplayMonitors" and
  59. // "GetMonitorInfoA", it would be impossible to use FLTK on Windows 2000
  60. // before SP2 or earlier.
  61. // BOOL EnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM)
  62. typedef BOOL(WINAPI* fl_edm_func)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
  63. // BOOL GetMonitorInfo(HMONITOR, LPMONITORINFO)
  64. typedef BOOL(WINAPI* fl_gmi_func)(HMONITOR, LPMONITORINFO);
  65. static fl_gmi_func fl_gmi = NULL; // used to get a proc pointer for GetMonitorInfoA
  66. BOOL Fl_WinAPI_Screen_Driver::screen_cb(HMONITOR mon, HDC hdc, LPRECT r, LPARAM d)
  67. {
  68. Fl_WinAPI_Screen_Driver *drv = (Fl_WinAPI_Screen_Driver*)d;
  69. return drv->screen_cb(mon, hdc, r);
  70. }
  71. BOOL Fl_WinAPI_Screen_Driver::screen_cb(HMONITOR mon, HDC, LPRECT r)
  72. {
  73. if (num_screens >= MAX_SCREENS) return TRUE;
  74. MONITORINFOEX mi;
  75. mi.cbSize = sizeof(mi);
  76. // GetMonitorInfo(mon, &mi);
  77. // (but we use our self-acquired function pointer instead)
  78. if (fl_gmi(mon, &mi)) {
  79. screens[num_screens] = mi.rcMonitor;
  80. // If we also want to record the work area, we would also store mi.rcWork at this point
  81. work_area[num_screens] = mi.rcWork;
  82. //extern FILE*LOG;fprintf(LOG,"screen_cb ns=%d\n",num_screens);fflush(LOG);
  83. /*fl_alert("screen %d %d,%d,%d,%d work %d,%d,%d,%d",num_screens,
  84. screens[num_screens].left,screens[num_screens].right,screens[num_screens].top,screens[num_screens].bottom,
  85. work_area[num_screens].left,work_area[num_screens].right,work_area[num_screens].top,work_area[num_screens].bottom);
  86. */
  87. // find the pixel size
  88. if (mi.cbSize == sizeof(mi)) {
  89. HDC screen = CreateDC(mi.szDevice, NULL, NULL, NULL);
  90. if (screen) {
  91. dpi[num_screens][0] = (float)GetDeviceCaps(screen, LOGPIXELSX);
  92. dpi[num_screens][1] = (float)GetDeviceCaps(screen, LOGPIXELSY);
  93. }
  94. DeleteDC(screen);
  95. }
  96. num_screens++;
  97. }
  98. return TRUE;
  99. }
  100. void Fl_WinAPI_Screen_Driver::init()
  101. {
  102. open_display();
  103. // Since not all versions of Windows include multiple monitor support,
  104. // we do a run-time check for the required functions...
  105. HMODULE hMod = GetModuleHandle("USER32.DLL");
  106. if (hMod) {
  107. // check that EnumDisplayMonitors is available
  108. fl_edm_func fl_edm = (fl_edm_func)GetProcAddress(hMod, "EnumDisplayMonitors");
  109. if (fl_edm) {
  110. // we have EnumDisplayMonitors - do we also have GetMonitorInfoA ?
  111. fl_gmi = (fl_gmi_func)GetProcAddress(hMod, "GetMonitorInfoA");
  112. if (fl_gmi) {
  113. // We have GetMonitorInfoA, enumerate all the screens...
  114. // EnumDisplayMonitors(0,0,screen_cb,0);
  115. // (but we use our self-acquired function pointer instead)
  116. // NOTE: num_screens is incremented in screen_cb so we must first reset it here...
  117. num_screens = 0;
  118. fl_edm(0, 0, screen_cb, (LPARAM)this);
  119. return;
  120. }
  121. }
  122. }
  123. // If we get here, assume we have 1 monitor...
  124. num_screens = 1;
  125. screens[0].top = 0;
  126. screens[0].left = 0;
  127. screens[0].right = GetSystemMetrics(SM_CXSCREEN);
  128. screens[0].bottom = GetSystemMetrics(SM_CYSCREEN);
  129. work_area[0] = screens[0];
  130. scale_of_screen[0] = 1;
  131. }
  132. float Fl_WinAPI_Screen_Driver::desktop_scale_factor() {
  133. return 0; //indicates each screen has already been assigned its scale factor value
  134. }
  135. void Fl_WinAPI_Screen_Driver::screen_work_area(int &X, int &Y, int &W, int &H, int n)
  136. {
  137. if (num_screens < 0) init();
  138. if (n < 0 || n >= num_screens) n = 0;
  139. X = work_area[n].left/scale_of_screen[n];
  140. Y = work_area[n].top/scale_of_screen[n];
  141. W = (work_area[n].right - X)/scale_of_screen[n];
  142. H = (work_area[n].bottom - Y)/scale_of_screen[n];
  143. }
  144. void Fl_WinAPI_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n)
  145. {
  146. if (num_screens < 0) init();
  147. if ((n < 0) || (n >= num_screens))
  148. n = 0;
  149. if (num_screens > 0) {
  150. X = screens[n].left/scale_of_screen[n];
  151. Y = screens[n].top/scale_of_screen[n];
  152. W = (screens[n].right - screens[n].left)/scale_of_screen[n];
  153. H = (screens[n].bottom - screens[n].top)/scale_of_screen[n];
  154. } else {
  155. /* Fallback if something is broken... */
  156. X = 0;
  157. Y = 0;
  158. W = GetSystemMetrics(SM_CXSCREEN);
  159. H = GetSystemMetrics(SM_CYSCREEN);
  160. }
  161. }
  162. void Fl_WinAPI_Screen_Driver::screen_dpi(float &h, float &v, int n)
  163. {
  164. if (num_screens < 0) init();
  165. h = v = 0.0f;
  166. if (n >= 0 && n < num_screens) {
  167. h = float(dpi[n][0]);
  168. v = float(dpi[n][1]);
  169. }
  170. }
  171. int Fl_WinAPI_Screen_Driver::x()
  172. {
  173. RECT r;
  174. SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  175. return r.left;
  176. }
  177. int Fl_WinAPI_Screen_Driver::y()
  178. {
  179. RECT r;
  180. SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  181. return r.top;
  182. }
  183. int Fl_WinAPI_Screen_Driver::h()
  184. {
  185. RECT r;
  186. SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  187. return r.bottom - r.top;
  188. }
  189. int Fl_WinAPI_Screen_Driver::w()
  190. {
  191. RECT r;
  192. SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
  193. return r.right - r.left;
  194. }
  195. void Fl_WinAPI_Screen_Driver::beep(int type)
  196. {
  197. switch (type) {
  198. case FL_BEEP_QUESTION :
  199. case FL_BEEP_PASSWORD :
  200. MessageBeep(MB_ICONQUESTION);
  201. break;
  202. case FL_BEEP_MESSAGE :
  203. MessageBeep(MB_ICONASTERISK);
  204. break;
  205. case FL_BEEP_NOTIFICATION :
  206. MessageBeep(MB_ICONASTERISK);
  207. break;
  208. case FL_BEEP_ERROR :
  209. MessageBeep(MB_ICONERROR);
  210. break;
  211. default :
  212. MessageBeep(0xFFFFFFFF);
  213. break;
  214. }
  215. }
  216. void Fl_WinAPI_Screen_Driver::flush()
  217. {
  218. GdiFlush();
  219. }
  220. extern void fl_fix_focus(); // in Fl.cxx
  221. // We have to keep track of whether we have captured the mouse, since
  222. // MSWindows shows little respect for this... Grep for fl_capture to
  223. // see where and how this is used.
  224. extern HWND fl_capture;
  225. void Fl_WinAPI_Screen_Driver::grab(Fl_Window* win)
  226. {
  227. if (win) {
  228. if (!Fl::grab_) {
  229. SetActiveWindow(fl_capture = fl_xid(Fl::first_window()));
  230. SetCapture(fl_capture);
  231. }
  232. Fl::grab_ = win;
  233. } else {
  234. if (Fl::grab_) {
  235. fl_capture = 0;
  236. ReleaseCapture();
  237. Fl::grab_ = 0;
  238. fl_fix_focus();
  239. }
  240. }
  241. }
  242. static void set_selection_color(uchar r, uchar g, uchar b)
  243. {
  244. Fl::set_color(FL_SELECTION_COLOR,r,g,b);
  245. }
  246. static void getsyscolor(int what, const char* arg, void (*func)(uchar,uchar,uchar))
  247. {
  248. if (arg) {
  249. uchar r,g,b;
  250. if (!fl_parse_color(arg, r,g,b))
  251. Fl::error("Unknown color: %s", arg);
  252. else
  253. func(r,g,b);
  254. } else {
  255. DWORD x = GetSysColor(what);
  256. func(uchar(x&255), uchar(x>>8), uchar(x>>16));
  257. }
  258. }
  259. void Fl_WinAPI_Screen_Driver::get_system_colors()
  260. {
  261. if (!bg2_set) getsyscolor(COLOR_WINDOW, fl_bg2,Fl::background2);
  262. if (!fg_set) getsyscolor(COLOR_WINDOWTEXT, fl_fg, Fl::foreground);
  263. if (!bg_set) getsyscolor(COLOR_BTNFACE, fl_bg, Fl::background);
  264. getsyscolor(COLOR_HIGHLIGHT, 0, set_selection_color);
  265. }
  266. const char *Fl_WinAPI_Screen_Driver::get_system_scheme()
  267. {
  268. return fl_getenv("FLTK_SCHEME");
  269. }
  270. // ---- timers
  271. struct Win32Timer
  272. {
  273. UINT_PTR handle;
  274. Fl_Timeout_Handler callback;
  275. void *data;
  276. };
  277. static Win32Timer* win32_timers;
  278. static int win32_timer_alloc;
  279. static int win32_timer_used;
  280. static HWND s_TimerWnd;
  281. static void realloc_timers()
  282. {
  283. if (win32_timer_alloc == 0) {
  284. win32_timer_alloc = 8;
  285. }
  286. win32_timer_alloc *= 2;
  287. Win32Timer* new_timers = new Win32Timer[win32_timer_alloc];
  288. memset(new_timers, 0, sizeof(Win32Timer) * win32_timer_used);
  289. memcpy(new_timers, win32_timers, sizeof(Win32Timer) * win32_timer_used);
  290. Win32Timer* delete_me = win32_timers;
  291. win32_timers = new_timers;
  292. delete [] delete_me;
  293. }
  294. static void delete_timer(Win32Timer& t)
  295. {
  296. KillTimer(s_TimerWnd, t.handle);
  297. memset(&t, 0, sizeof(Win32Timer));
  298. }
  299. static LRESULT CALLBACK s_TimerProc(HWND hwnd, UINT msg,
  300. WPARAM wParam, LPARAM lParam)
  301. {
  302. switch (msg) {
  303. case WM_TIMER:
  304. {
  305. unsigned int id = (unsigned) (wParam - 1);
  306. if (id < (unsigned int)win32_timer_used && win32_timers[id].handle) {
  307. Fl_Timeout_Handler cb = win32_timers[id].callback;
  308. void* data = win32_timers[id].data;
  309. delete_timer(win32_timers[id]);
  310. if (cb) {
  311. (*cb)(data);
  312. }
  313. }
  314. }
  315. return 0;
  316. default:
  317. break;
  318. }
  319. return DefWindowProc(hwnd, msg, wParam, lParam);
  320. }
  321. void Fl_WinAPI_Screen_Driver::add_timeout(double time, Fl_Timeout_Handler cb, void* data)
  322. {
  323. repeat_timeout(time, cb, data);
  324. }
  325. void Fl_WinAPI_Screen_Driver::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data)
  326. {
  327. int timer_id = -1;
  328. for (int i = 0; i < win32_timer_used; ++i) {
  329. if ( !win32_timers[i].handle ) {
  330. timer_id = i;
  331. break;
  332. }
  333. }
  334. if (timer_id == -1) {
  335. if (win32_timer_used == win32_timer_alloc) {
  336. realloc_timers();
  337. }
  338. timer_id = win32_timer_used++;
  339. }
  340. unsigned int elapsed = (unsigned int)(time * 1000);
  341. if ( !s_TimerWnd ) {
  342. const char* timer_class = "FLTimer";
  343. WNDCLASSEX wc;
  344. memset(&wc, 0, sizeof(wc));
  345. wc.cbSize = sizeof (wc);
  346. wc.style = CS_CLASSDC;
  347. wc.lpfnWndProc = (WNDPROC)s_TimerProc;
  348. wc.hInstance = fl_display;
  349. wc.lpszClassName = timer_class;
  350. /*ATOM atom =*/ RegisterClassEx(&wc);
  351. // create a zero size window to handle timer events
  352. s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW,
  353. timer_class, "",
  354. WS_POPUP,
  355. 0, 0, 0, 0,
  356. NULL, NULL, fl_display, NULL);
  357. // just in case this OS won't let us create a 0x0 size window:
  358. if (!s_TimerWnd)
  359. s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW,
  360. timer_class, "",
  361. WS_POPUP,
  362. 0, 0, 1, 1,
  363. NULL, NULL, fl_display, NULL);
  364. ShowWindow(s_TimerWnd, SW_SHOWNOACTIVATE);
  365. }
  366. win32_timers[timer_id].callback = cb;
  367. win32_timers[timer_id].data = data;
  368. win32_timers[timer_id].handle =
  369. SetTimer(s_TimerWnd, timer_id + 1, elapsed, NULL);
  370. }
  371. int Fl_WinAPI_Screen_Driver::has_timeout(Fl_Timeout_Handler cb, void* data)
  372. {
  373. for (int i = 0; i < win32_timer_used; ++i) {
  374. Win32Timer& t = win32_timers[i];
  375. if (t.handle && t.callback == cb && t.data == data) {
  376. return 1;
  377. }
  378. }
  379. return 0;
  380. }
  381. void Fl_WinAPI_Screen_Driver::remove_timeout(Fl_Timeout_Handler cb, void* data)
  382. {
  383. int i;
  384. for (i = 0; i < win32_timer_used; ++i) {
  385. Win32Timer& t = win32_timers[i];
  386. if (t.handle && t.callback == cb &&
  387. (t.data == data || data == NULL)) {
  388. delete_timer(t);
  389. }
  390. }
  391. }
  392. int Fl_WinAPI_Screen_Driver::compose(int &del) {
  393. unsigned char ascii = (unsigned char)Fl::e_text[0];
  394. int condition = (Fl::e_state & (FL_ALT | FL_META)) && !(ascii & 128) ;
  395. if (condition) { // this stuff is to be treated as a function key
  396. del = 0;
  397. return 0;
  398. }
  399. del = Fl::compose_state;
  400. Fl::compose_state = 0;
  401. // Only insert non-control characters:
  402. if ( (!Fl::compose_state) && ! (ascii & ~31 && ascii!=127)) {
  403. return 0;
  404. }
  405. return 1;
  406. }
  407. Fl_RGB_Image * // O - image or NULL if failed
  408. Fl_WinAPI_Screen_Driver::read_win_rectangle(uchar *p, // I - Pixel buffer or NULL to allocate
  409. int X, // I - Left position
  410. int Y, // I - Top position
  411. int w, // I - Width of area to read
  412. int h, // I - Height of area to read
  413. int alpha) // I - Alpha value for image (0 for none)
  414. {
  415. float s = Fl_Surface_Device::surface()->driver()->scale();
  416. return read_win_rectangle_unscaled(p, X*s, Y*s, w*s, h*s, alpha);
  417. }
  418. Fl_RGB_Image *Fl_WinAPI_Screen_Driver::read_win_rectangle_unscaled(uchar *p, int X, int Y, int w, int h, int alpha)
  419. {
  420. int d; // Depth of image
  421. // Allocate the image data array as needed...
  422. d = alpha ? 4 : 3;
  423. const uchar *oldp = p;
  424. if (!p) p = new uchar[w * h * d];
  425. // Initialize the default colors/alpha in the whole image...
  426. memset(p, alpha, w * h * d);
  427. // Grab all of the pixels in the image...
  428. // Assure that we are not trying to read non-existing data. If it is so, the
  429. // function should still work, but the out-of-bounds part of the image is
  430. // untouched (initialized with the alpha value or 0 (black), resp.).
  431. int ww = w; // We need the original width for output data line size
  432. int shift_x = 0; // X target shift if X modified
  433. int shift_y = 0; // Y target shift if X modified
  434. if (X < 0) {
  435. shift_x = -X;
  436. w += X;
  437. X = 0;
  438. }
  439. if (Y < 0) {
  440. shift_y = -Y;
  441. h += Y;
  442. Y = 0;
  443. }
  444. if (h < 1 || w < 1) return 0/*p*/; // nothing to copy
  445. int line_size = ((3*w+3)/4) * 4; // each line is aligned on a DWORD (4 bytes)
  446. uchar *dib = new uchar[line_size*h]; // create temporary buffer to read DIB
  447. // fill in bitmap info for GetDIBits
  448. BITMAPINFO bi;
  449. bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  450. bi.bmiHeader.biWidth = w;
  451. bi.bmiHeader.biHeight = -h; // negative => top-down DIB
  452. bi.bmiHeader.biPlanes = 1;
  453. bi.bmiHeader.biBitCount = 24; // 24 bits RGB
  454. bi.bmiHeader.biCompression = BI_RGB;
  455. bi.bmiHeader.biSizeImage = 0;
  456. bi.bmiHeader.biXPelsPerMeter = 0;
  457. bi.bmiHeader.biYPelsPerMeter = 0;
  458. bi.bmiHeader.biClrUsed = 0;
  459. bi.bmiHeader.biClrImportant = 0;
  460. // copy bitmap from original DC (Window, Fl_Offscreen, ...)
  461. HDC gc = (HDC)fl_graphics_driver->gc();
  462. HDC hdc = CreateCompatibleDC(gc);
  463. HBITMAP hbm = CreateCompatibleBitmap(gc,w,h);
  464. int save_dc = SaveDC(hdc); // save context for cleanup
  465. SelectObject(hdc,hbm); // select bitmap
  466. BitBlt(hdc,0,0,w,h,gc,X,Y,SRCCOPY); // copy image section to DDB
  467. // copy RGB image data to the allocated DIB
  468. GetDIBits(hdc, hbm, 0, h, dib, (BITMAPINFO *)&bi, DIB_RGB_COLORS);
  469. // finally copy the image data to the user buffer
  470. for (int j = 0; j<h; j++) {
  471. const uchar *src = dib + j * line_size; // source line
  472. uchar *tg = p + (j + shift_y) * d * ww + shift_x * d; // target line
  473. for (int i = 0; i<w; i++) {
  474. uchar b = *src++;
  475. uchar g = *src++;
  476. *tg++ = *src++; // R
  477. *tg++ = g; // G
  478. *tg++ = b; // B
  479. if (alpha)
  480. *tg++ = alpha; // alpha
  481. }
  482. }
  483. // free used GDI and other structures
  484. RestoreDC(hdc,save_dc); // reset DC
  485. DeleteDC(hdc);
  486. DeleteObject(hbm);
  487. delete[] dib; // delete DIB temporary buffer
  488. Fl_RGB_Image *rgb = new Fl_RGB_Image(p, w, h, d);
  489. if (!oldp) rgb->alloc_array = 1;
  490. return rgb;
  491. }
  492. #ifndef FLTK_HIDPI_SUPPORT
  493. /* Returns the current desktop scaling factor for screen_num (1.75 for example)
  494. */
  495. float Fl_WinAPI_Screen_Driver::DWM_scaling_factor() {
  496. // Compute the global desktop scaling factor: 1, 1.25, 1.5, 1.75, etc...
  497. // This factor can be set in Windows 10 by
  498. // "Change the size of text, apps and other items" in display settings.
  499. // We don't cache this value because it can change while the app is running.
  500. HDC hdc = GetDC(NULL);
  501. int hr = GetDeviceCaps(hdc, HORZRES); // pixels visible to the app
  502. #ifndef DESKTOPHORZRES
  503. #define DESKTOPHORZRES 118
  504. /* As of 27 august 2016, the DESKTOPHORZRES flag for GetDeviceCaps()
  505. has disappeared from Microsoft online doc, but is quoted in numerous coding examples
  506. e.g., https://social.msdn.microsoft.com/Forums/en-US/6acc3b21-23a4-4a00-90b4-968a43e1ccc8/capture-screen-with-high-dpi?forum=vbgeneral
  507. It is necessary for the computation of the scaling factor at runtime as done here.
  508. */
  509. #endif
  510. int dhr = GetDeviceCaps(hdc, DESKTOPHORZRES); // true number of pixels on display
  511. ReleaseDC(NULL, hdc);
  512. float scaling = dhr/float(hr);
  513. scaling = int(scaling * 100 + 0.5)/100.; // round to 2 digits after decimal point
  514. return scaling;
  515. }
  516. #endif // ! FLTK_HIDPI_SUPPORT
  517. void Fl_WinAPI_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &height)
  518. {
  519. BITMAP bitmap;
  520. if ( GetObject(off, sizeof(BITMAP), &bitmap) ) {
  521. width = bitmap.bmWidth;
  522. height = bitmap.bmHeight;
  523. }
  524. }
  525. //NOTICE: returns -1 if x,y is not in any screen
  526. int Fl_WinAPI_Screen_Driver::screen_num_unscaled(int x, int y)
  527. {
  528. int screen = -1;
  529. if (num_screens < 0) init();
  530. for (int i = 0; i < num_screens; i ++) {
  531. if (x >= screens[i].left && x < screens[i].right &&
  532. y >= screens[i].top && y < screens[i].bottom) {
  533. screen = i;
  534. break;
  535. }
  536. }
  537. return screen;
  538. }
  539. //
  540. // End of "$Id: Fl_WinAPI_Screen_Driver.cxx 12628 2018-01-09 07:26:49Z manolo $".
  541. //