| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661 |
- //
- // "$Id: Fl_WinAPI_Screen_Driver.cxx 12628 2018-01-09 07:26:49Z manolo $"
- //
- // Definition of MSWindows Win32/64 Screen interface
- //
- // Copyright 1998-2017 by Bill Spitzak and others.
- //
- // This library is free software. Distribution and use rights are outlined in
- // the file "COPYING" which should have been included with this file. If this
- // file is missing or damaged, see the license at:
- //
- // http://www.fltk.org/COPYING.php
- //
- // Please report all bugs and problems on the following page:
- //
- // http://www.fltk.org/str.php
- //
- #include "../../config_lib.h"
- #include "Fl_WinAPI_Screen_Driver.H"
- #include "../GDI/Fl_Font.H"
- #include <FL/Fl.H>
- #include <FL/x.H>
- #include <FL/Fl_Graphics_Driver.H>
- #include <FL/Fl_RGB_Image.H>
- #include <FL/fl_ask.H>
- #include <stdio.h>
- // these are set by Fl::args() and override any system colors: from Fl_get_system_colors.cxx
- extern const char *fl_fg;
- extern const char *fl_bg;
- extern const char *fl_bg2;
- // end of extern additions workaround
- #if !defined(HMONITOR_DECLARED) && (_WIN32_WINNT < 0x0500)
- # define COMPILE_MULTIMON_STUBS
- # include <multimon.h>
- #endif // !HMONITOR_DECLARED && _WIN32_WINNT < 0x0500
- /*
- Creates a driver that manages all screen and display related calls.
- This function must be implemented once for every platform.
- */
- Fl_Screen_Driver *Fl_Screen_Driver::newScreenDriver()
- {
- return new Fl_WinAPI_Screen_Driver();
- }
- int Fl_WinAPI_Screen_Driver::visual(int flags)
- {
- fl_GetDC(0);
- if (flags & FL_DOUBLE) return 0;
- HDC gc = (HDC)Fl_Graphics_Driver::default_driver().gc();
- if (!(flags & FL_INDEX) &&
- GetDeviceCaps(gc,BITSPIXEL) <= 8) return 0;
- if ((flags & FL_RGB8) && GetDeviceCaps(gc,BITSPIXEL)<24) return 0;
- return 1;
- }
- // We go the much more difficult route of individually picking some multi-screen
- // functions from the USER32.DLL . If these functions are not available, we
- // will gracefully fall back to single monitor support.
- //
- // If we were to insist on the existence of "EnumDisplayMonitors" and
- // "GetMonitorInfoA", it would be impossible to use FLTK on Windows 2000
- // before SP2 or earlier.
- // BOOL EnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM)
- typedef BOOL(WINAPI* fl_edm_func)(HDC, LPCRECT, MONITORENUMPROC, LPARAM);
- // BOOL GetMonitorInfo(HMONITOR, LPMONITORINFO)
- typedef BOOL(WINAPI* fl_gmi_func)(HMONITOR, LPMONITORINFO);
- static fl_gmi_func fl_gmi = NULL; // used to get a proc pointer for GetMonitorInfoA
- BOOL Fl_WinAPI_Screen_Driver::screen_cb(HMONITOR mon, HDC hdc, LPRECT r, LPARAM d)
- {
- Fl_WinAPI_Screen_Driver *drv = (Fl_WinAPI_Screen_Driver*)d;
- return drv->screen_cb(mon, hdc, r);
- }
- BOOL Fl_WinAPI_Screen_Driver::screen_cb(HMONITOR mon, HDC, LPRECT r)
- {
- if (num_screens >= MAX_SCREENS) return TRUE;
- MONITORINFOEX mi;
- mi.cbSize = sizeof(mi);
- // GetMonitorInfo(mon, &mi);
- // (but we use our self-acquired function pointer instead)
- if (fl_gmi(mon, &mi)) {
- screens[num_screens] = mi.rcMonitor;
- // If we also want to record the work area, we would also store mi.rcWork at this point
- work_area[num_screens] = mi.rcWork;
- //extern FILE*LOG;fprintf(LOG,"screen_cb ns=%d\n",num_screens);fflush(LOG);
- /*fl_alert("screen %d %d,%d,%d,%d work %d,%d,%d,%d",num_screens,
- screens[num_screens].left,screens[num_screens].right,screens[num_screens].top,screens[num_screens].bottom,
- work_area[num_screens].left,work_area[num_screens].right,work_area[num_screens].top,work_area[num_screens].bottom);
- */
- // find the pixel size
- if (mi.cbSize == sizeof(mi)) {
- HDC screen = CreateDC(mi.szDevice, NULL, NULL, NULL);
- if (screen) {
- dpi[num_screens][0] = (float)GetDeviceCaps(screen, LOGPIXELSX);
- dpi[num_screens][1] = (float)GetDeviceCaps(screen, LOGPIXELSY);
- }
- DeleteDC(screen);
- }
- num_screens++;
- }
- return TRUE;
- }
- void Fl_WinAPI_Screen_Driver::init()
- {
- open_display();
- // Since not all versions of Windows include multiple monitor support,
- // we do a run-time check for the required functions...
- HMODULE hMod = GetModuleHandle("USER32.DLL");
- if (hMod) {
- // check that EnumDisplayMonitors is available
- fl_edm_func fl_edm = (fl_edm_func)GetProcAddress(hMod, "EnumDisplayMonitors");
- if (fl_edm) {
- // we have EnumDisplayMonitors - do we also have GetMonitorInfoA ?
- fl_gmi = (fl_gmi_func)GetProcAddress(hMod, "GetMonitorInfoA");
- if (fl_gmi) {
- // We have GetMonitorInfoA, enumerate all the screens...
- // EnumDisplayMonitors(0,0,screen_cb,0);
- // (but we use our self-acquired function pointer instead)
- // NOTE: num_screens is incremented in screen_cb so we must first reset it here...
- num_screens = 0;
- fl_edm(0, 0, screen_cb, (LPARAM)this);
- return;
- }
- }
- }
- // If we get here, assume we have 1 monitor...
- num_screens = 1;
- screens[0].top = 0;
- screens[0].left = 0;
- screens[0].right = GetSystemMetrics(SM_CXSCREEN);
- screens[0].bottom = GetSystemMetrics(SM_CYSCREEN);
- work_area[0] = screens[0];
- scale_of_screen[0] = 1;
- }
- float Fl_WinAPI_Screen_Driver::desktop_scale_factor() {
- return 0; //indicates each screen has already been assigned its scale factor value
- }
- void Fl_WinAPI_Screen_Driver::screen_work_area(int &X, int &Y, int &W, int &H, int n)
- {
- if (num_screens < 0) init();
- if (n < 0 || n >= num_screens) n = 0;
- X = work_area[n].left/scale_of_screen[n];
- Y = work_area[n].top/scale_of_screen[n];
- W = (work_area[n].right - X)/scale_of_screen[n];
- H = (work_area[n].bottom - Y)/scale_of_screen[n];
- }
- void Fl_WinAPI_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n)
- {
- if (num_screens < 0) init();
- if ((n < 0) || (n >= num_screens))
- n = 0;
- if (num_screens > 0) {
- X = screens[n].left/scale_of_screen[n];
- Y = screens[n].top/scale_of_screen[n];
- W = (screens[n].right - screens[n].left)/scale_of_screen[n];
- H = (screens[n].bottom - screens[n].top)/scale_of_screen[n];
- } else {
- /* Fallback if something is broken... */
- X = 0;
- Y = 0;
- W = GetSystemMetrics(SM_CXSCREEN);
- H = GetSystemMetrics(SM_CYSCREEN);
- }
- }
- void Fl_WinAPI_Screen_Driver::screen_dpi(float &h, float &v, int n)
- {
- if (num_screens < 0) init();
- h = v = 0.0f;
- if (n >= 0 && n < num_screens) {
- h = float(dpi[n][0]);
- v = float(dpi[n][1]);
- }
- }
- int Fl_WinAPI_Screen_Driver::x()
- {
- RECT r;
- SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
- return r.left;
- }
- int Fl_WinAPI_Screen_Driver::y()
- {
- RECT r;
- SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
- return r.top;
- }
- int Fl_WinAPI_Screen_Driver::h()
- {
- RECT r;
- SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
- return r.bottom - r.top;
- }
- int Fl_WinAPI_Screen_Driver::w()
- {
- RECT r;
- SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0);
- return r.right - r.left;
- }
- void Fl_WinAPI_Screen_Driver::beep(int type)
- {
- switch (type) {
- case FL_BEEP_QUESTION :
- case FL_BEEP_PASSWORD :
- MessageBeep(MB_ICONQUESTION);
- break;
- case FL_BEEP_MESSAGE :
- MessageBeep(MB_ICONASTERISK);
- break;
- case FL_BEEP_NOTIFICATION :
- MessageBeep(MB_ICONASTERISK);
- break;
- case FL_BEEP_ERROR :
- MessageBeep(MB_ICONERROR);
- break;
- default :
- MessageBeep(0xFFFFFFFF);
- break;
- }
- }
- void Fl_WinAPI_Screen_Driver::flush()
- {
- GdiFlush();
- }
- extern void fl_fix_focus(); // in Fl.cxx
- // We have to keep track of whether we have captured the mouse, since
- // MSWindows shows little respect for this... Grep for fl_capture to
- // see where and how this is used.
- extern HWND fl_capture;
- void Fl_WinAPI_Screen_Driver::grab(Fl_Window* win)
- {
- if (win) {
- if (!Fl::grab_) {
- SetActiveWindow(fl_capture = fl_xid(Fl::first_window()));
- SetCapture(fl_capture);
- }
- Fl::grab_ = win;
- } else {
- if (Fl::grab_) {
- fl_capture = 0;
- ReleaseCapture();
- Fl::grab_ = 0;
- fl_fix_focus();
- }
- }
- }
- static void set_selection_color(uchar r, uchar g, uchar b)
- {
- Fl::set_color(FL_SELECTION_COLOR,r,g,b);
- }
- static void getsyscolor(int what, const char* arg, void (*func)(uchar,uchar,uchar))
- {
- if (arg) {
- uchar r,g,b;
- if (!fl_parse_color(arg, r,g,b))
- Fl::error("Unknown color: %s", arg);
- else
- func(r,g,b);
- } else {
- DWORD x = GetSysColor(what);
- func(uchar(x&255), uchar(x>>8), uchar(x>>16));
- }
- }
- void Fl_WinAPI_Screen_Driver::get_system_colors()
- {
- if (!bg2_set) getsyscolor(COLOR_WINDOW, fl_bg2,Fl::background2);
- if (!fg_set) getsyscolor(COLOR_WINDOWTEXT, fl_fg, Fl::foreground);
- if (!bg_set) getsyscolor(COLOR_BTNFACE, fl_bg, Fl::background);
- getsyscolor(COLOR_HIGHLIGHT, 0, set_selection_color);
- }
- const char *Fl_WinAPI_Screen_Driver::get_system_scheme()
- {
- return fl_getenv("FLTK_SCHEME");
- }
- // ---- timers
- struct Win32Timer
- {
- UINT_PTR handle;
- Fl_Timeout_Handler callback;
- void *data;
- };
- static Win32Timer* win32_timers;
- static int win32_timer_alloc;
- static int win32_timer_used;
- static HWND s_TimerWnd;
- static void realloc_timers()
- {
- if (win32_timer_alloc == 0) {
- win32_timer_alloc = 8;
- }
- win32_timer_alloc *= 2;
- Win32Timer* new_timers = new Win32Timer[win32_timer_alloc];
- memset(new_timers, 0, sizeof(Win32Timer) * win32_timer_used);
- memcpy(new_timers, win32_timers, sizeof(Win32Timer) * win32_timer_used);
- Win32Timer* delete_me = win32_timers;
- win32_timers = new_timers;
- delete [] delete_me;
- }
- static void delete_timer(Win32Timer& t)
- {
- KillTimer(s_TimerWnd, t.handle);
- memset(&t, 0, sizeof(Win32Timer));
- }
- static LRESULT CALLBACK s_TimerProc(HWND hwnd, UINT msg,
- WPARAM wParam, LPARAM lParam)
- {
- switch (msg) {
- case WM_TIMER:
- {
- unsigned int id = (unsigned) (wParam - 1);
- if (id < (unsigned int)win32_timer_used && win32_timers[id].handle) {
- Fl_Timeout_Handler cb = win32_timers[id].callback;
- void* data = win32_timers[id].data;
- delete_timer(win32_timers[id]);
- if (cb) {
- (*cb)(data);
- }
- }
- }
- return 0;
- default:
- break;
- }
- return DefWindowProc(hwnd, msg, wParam, lParam);
- }
- void Fl_WinAPI_Screen_Driver::add_timeout(double time, Fl_Timeout_Handler cb, void* data)
- {
- repeat_timeout(time, cb, data);
- }
- void Fl_WinAPI_Screen_Driver::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data)
- {
- int timer_id = -1;
- for (int i = 0; i < win32_timer_used; ++i) {
- if ( !win32_timers[i].handle ) {
- timer_id = i;
- break;
- }
- }
- if (timer_id == -1) {
- if (win32_timer_used == win32_timer_alloc) {
- realloc_timers();
- }
- timer_id = win32_timer_used++;
- }
- unsigned int elapsed = (unsigned int)(time * 1000);
- if ( !s_TimerWnd ) {
- const char* timer_class = "FLTimer";
- WNDCLASSEX wc;
- memset(&wc, 0, sizeof(wc));
- wc.cbSize = sizeof (wc);
- wc.style = CS_CLASSDC;
- wc.lpfnWndProc = (WNDPROC)s_TimerProc;
- wc.hInstance = fl_display;
- wc.lpszClassName = timer_class;
- /*ATOM atom =*/ RegisterClassEx(&wc);
- // create a zero size window to handle timer events
- s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW,
- timer_class, "",
- WS_POPUP,
- 0, 0, 0, 0,
- NULL, NULL, fl_display, NULL);
- // just in case this OS won't let us create a 0x0 size window:
- if (!s_TimerWnd)
- s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW,
- timer_class, "",
- WS_POPUP,
- 0, 0, 1, 1,
- NULL, NULL, fl_display, NULL);
- ShowWindow(s_TimerWnd, SW_SHOWNOACTIVATE);
- }
- win32_timers[timer_id].callback = cb;
- win32_timers[timer_id].data = data;
- win32_timers[timer_id].handle =
- SetTimer(s_TimerWnd, timer_id + 1, elapsed, NULL);
- }
- int Fl_WinAPI_Screen_Driver::has_timeout(Fl_Timeout_Handler cb, void* data)
- {
- for (int i = 0; i < win32_timer_used; ++i) {
- Win32Timer& t = win32_timers[i];
- if (t.handle && t.callback == cb && t.data == data) {
- return 1;
- }
- }
- return 0;
- }
- void Fl_WinAPI_Screen_Driver::remove_timeout(Fl_Timeout_Handler cb, void* data)
- {
- int i;
- for (i = 0; i < win32_timer_used; ++i) {
- Win32Timer& t = win32_timers[i];
- if (t.handle && t.callback == cb &&
- (t.data == data || data == NULL)) {
- delete_timer(t);
- }
- }
- }
- int Fl_WinAPI_Screen_Driver::compose(int &del) {
- unsigned char ascii = (unsigned char)Fl::e_text[0];
- int condition = (Fl::e_state & (FL_ALT | FL_META)) && !(ascii & 128) ;
- if (condition) { // this stuff is to be treated as a function key
- del = 0;
- return 0;
- }
- del = Fl::compose_state;
- Fl::compose_state = 0;
- // Only insert non-control characters:
- if ( (!Fl::compose_state) && ! (ascii & ~31 && ascii!=127)) {
- return 0;
- }
- return 1;
- }
- Fl_RGB_Image * // O - image or NULL if failed
- Fl_WinAPI_Screen_Driver::read_win_rectangle(uchar *p, // I - Pixel buffer or NULL to allocate
- int X, // I - Left position
- int Y, // I - Top position
- int w, // I - Width of area to read
- int h, // I - Height of area to read
- int alpha) // I - Alpha value for image (0 for none)
- {
- float s = Fl_Surface_Device::surface()->driver()->scale();
- return read_win_rectangle_unscaled(p, X*s, Y*s, w*s, h*s, alpha);
- }
- Fl_RGB_Image *Fl_WinAPI_Screen_Driver::read_win_rectangle_unscaled(uchar *p, int X, int Y, int w, int h, int alpha)
- {
- int d; // Depth of image
-
- // Allocate the image data array as needed...
- d = alpha ? 4 : 3;
-
- const uchar *oldp = p;
- if (!p) p = new uchar[w * h * d];
-
- // Initialize the default colors/alpha in the whole image...
- memset(p, alpha, w * h * d);
-
- // Grab all of the pixels in the image...
-
- // Assure that we are not trying to read non-existing data. If it is so, the
- // function should still work, but the out-of-bounds part of the image is
- // untouched (initialized with the alpha value or 0 (black), resp.).
-
- int ww = w; // We need the original width for output data line size
-
- int shift_x = 0; // X target shift if X modified
- int shift_y = 0; // Y target shift if X modified
-
- if (X < 0) {
- shift_x = -X;
- w += X;
- X = 0;
- }
- if (Y < 0) {
- shift_y = -Y;
- h += Y;
- Y = 0;
- }
-
- if (h < 1 || w < 1) return 0/*p*/; // nothing to copy
-
- int line_size = ((3*w+3)/4) * 4; // each line is aligned on a DWORD (4 bytes)
- uchar *dib = new uchar[line_size*h]; // create temporary buffer to read DIB
-
- // fill in bitmap info for GetDIBits
-
- BITMAPINFO bi;
- bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
- bi.bmiHeader.biWidth = w;
- bi.bmiHeader.biHeight = -h; // negative => top-down DIB
- bi.bmiHeader.biPlanes = 1;
- bi.bmiHeader.biBitCount = 24; // 24 bits RGB
- bi.bmiHeader.biCompression = BI_RGB;
- bi.bmiHeader.biSizeImage = 0;
- bi.bmiHeader.biXPelsPerMeter = 0;
- bi.bmiHeader.biYPelsPerMeter = 0;
- bi.bmiHeader.biClrUsed = 0;
- bi.bmiHeader.biClrImportant = 0;
-
- // copy bitmap from original DC (Window, Fl_Offscreen, ...)
- HDC gc = (HDC)fl_graphics_driver->gc();
- HDC hdc = CreateCompatibleDC(gc);
- HBITMAP hbm = CreateCompatibleBitmap(gc,w,h);
-
- int save_dc = SaveDC(hdc); // save context for cleanup
- SelectObject(hdc,hbm); // select bitmap
- BitBlt(hdc,0,0,w,h,gc,X,Y,SRCCOPY); // copy image section to DDB
-
- // copy RGB image data to the allocated DIB
-
- GetDIBits(hdc, hbm, 0, h, dib, (BITMAPINFO *)&bi, DIB_RGB_COLORS);
-
- // finally copy the image data to the user buffer
-
- for (int j = 0; j<h; j++) {
- const uchar *src = dib + j * line_size; // source line
- uchar *tg = p + (j + shift_y) * d * ww + shift_x * d; // target line
- for (int i = 0; i<w; i++) {
- uchar b = *src++;
- uchar g = *src++;
- *tg++ = *src++; // R
- *tg++ = g; // G
- *tg++ = b; // B
- if (alpha)
- *tg++ = alpha; // alpha
- }
- }
-
- // free used GDI and other structures
-
- RestoreDC(hdc,save_dc); // reset DC
- DeleteDC(hdc);
- DeleteObject(hbm);
- delete[] dib; // delete DIB temporary buffer
-
- Fl_RGB_Image *rgb = new Fl_RGB_Image(p, w, h, d);
- if (!oldp) rgb->alloc_array = 1;
- return rgb;
- }
- #ifndef FLTK_HIDPI_SUPPORT
- /* Returns the current desktop scaling factor for screen_num (1.75 for example)
- */
- float Fl_WinAPI_Screen_Driver::DWM_scaling_factor() {
- // Compute the global desktop scaling factor: 1, 1.25, 1.5, 1.75, etc...
- // This factor can be set in Windows 10 by
- // "Change the size of text, apps and other items" in display settings.
- // We don't cache this value because it can change while the app is running.
- HDC hdc = GetDC(NULL);
- int hr = GetDeviceCaps(hdc, HORZRES); // pixels visible to the app
- #ifndef DESKTOPHORZRES
- #define DESKTOPHORZRES 118
- /* As of 27 august 2016, the DESKTOPHORZRES flag for GetDeviceCaps()
- has disappeared from Microsoft online doc, but is quoted in numerous coding examples
- e.g., https://social.msdn.microsoft.com/Forums/en-US/6acc3b21-23a4-4a00-90b4-968a43e1ccc8/capture-screen-with-high-dpi?forum=vbgeneral
- It is necessary for the computation of the scaling factor at runtime as done here.
- */
- #endif
- int dhr = GetDeviceCaps(hdc, DESKTOPHORZRES); // true number of pixels on display
- ReleaseDC(NULL, hdc);
- float scaling = dhr/float(hr);
- scaling = int(scaling * 100 + 0.5)/100.; // round to 2 digits after decimal point
- return scaling;
- }
- #endif // ! FLTK_HIDPI_SUPPORT
- void Fl_WinAPI_Screen_Driver::offscreen_size(Fl_Offscreen off, int &width, int &height)
- {
- BITMAP bitmap;
- if ( GetObject(off, sizeof(BITMAP), &bitmap) ) {
- width = bitmap.bmWidth;
- height = bitmap.bmHeight;
- }
- }
- //NOTICE: returns -1 if x,y is not in any screen
- int Fl_WinAPI_Screen_Driver::screen_num_unscaled(int x, int y)
- {
- int screen = -1;
- if (num_screens < 0) init();
- for (int i = 0; i < num_screens; i ++) {
- if (x >= screens[i].left && x < screens[i].right &&
- y >= screens[i].top && y < screens[i].bottom) {
- screen = i;
- break;
- }
- }
- return screen;
- }
- //
- // End of "$Id: Fl_WinAPI_Screen_Driver.cxx 12628 2018-01-09 07:26:49Z manolo $".
- //
|