From 8dccfc88386561782d9b78900b283cedad2e59bb Mon Sep 17 00:00:00 2001 From: Manolo Gouy Date: Mon, 3 Jul 2017 17:31:57 +0000 Subject: [PATCH] HiDPI support under WIN32 platform: completed. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12285 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- FL/Fl_Screen_Driver.H | 2 +- FL/Fl_Window_Driver.H | 2 + src/Fl_Screen_Driver.cxx | 36 +++++------- src/Fl_Window_Driver.cxx | 17 ++++++ src/Fl_win32.cxx | 57 ++++++++++++------- src/Fl_x.cxx | 2 +- src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H | 19 +++++-- .../WinAPI/Fl_WinAPI_Screen_Driver.cxx | 10 +++- src/drivers/WinAPI/Fl_WinAPI_Window_Driver.H | 8 ++- .../WinAPI/Fl_WinAPI_Window_Driver.cxx | 20 +++++++ 10 files changed, 121 insertions(+), 52 deletions(-) diff --git a/FL/Fl_Screen_Driver.H b/FL/Fl_Screen_Driver.H index 9d016043d..7f229e22b 100644 --- a/FL/Fl_Screen_Driver.H +++ b/FL/Fl_Screen_Driver.H @@ -167,7 +167,7 @@ public: static int scale_handler(int event); virtual void init_workarea() {} virtual float desktop_scale_factor() {return 1;} - float default_scale_factor(); + void use_startup_scale_factor(); enum APP_SCALING_CAPABILITY { NO_APP_SCALING = 0, ///< The platform does not support rescaling. SYSTEMWIDE_APP_SCALING, ///< The platform supports rescaling with the same factor for all screens. diff --git a/FL/Fl_Window_Driver.H b/FL/Fl_Window_Driver.H index 20e3503fc..9a588a46e 100644 --- a/FL/Fl_Window_Driver.H +++ b/FL/Fl_Window_Driver.H @@ -108,6 +108,8 @@ public: void overlay(Fl_Window *o) { if (pWindow->as_overlay_window()) pWindow->as_overlay_window()->overlay_ = o; } + + void resize_after_scale_change(int ns, float old_f, float new_f); // --- window data virtual int decorated_w() = 0; diff --git a/src/Fl_Screen_Driver.cxx b/src/Fl_Screen_Driver.cxx index 0332f59b3..41cffff03 100644 --- a/src/Fl_Screen_Driver.cxx +++ b/src/Fl_Screen_Driver.cxx @@ -364,18 +364,7 @@ void Fl_Screen_Driver::rescale_all_windows_from_screen(int screen, float f) } for (i = count - 1; i >= 0; i--) { // rescale all top-level windows, finishing with front one win = win_array[i]; - int oldx = win->x(), oldy = win->y(); - fl_uintptr_t current = win->driver()->current_cursor(); - win->hide(); - win->driver()->screen_num(screen); - win->position(oldx*old_f/f, oldy*old_f/f); - win->driver()->force_position(1); - if (win->fullscreen_active()) { - win->size(win->w() * old_f/f, win->h() * old_f/f); - } - win->show(); - win->driver()->reuse_cursor(current); - win->driver()->reuse_icons(); + win->driver()->resize_after_scale_change(screen, old_f, f); win->wait_for_expose(); } delete[] win_array; @@ -469,21 +458,23 @@ int Fl_Screen_Driver::scale_handler(int event) } -// determine the scaling value used at startup time (helps supporting HiDPI displays) -float Fl_Screen_Driver::default_scale_factor() +// use the startup time scaling value +void Fl_Screen_Driver::use_startup_scale_factor() { - float factor = 1; + float factor; char *p = 0; if ((p = fl_getenv("FLTK_SCALING_FACTOR"))) { sscanf(p, "%f", &factor); + // checks to prevent potential crash (factor <= 0) or very large factors + if (factor < 0.25) factor = 0.25; + else if (factor > 10.0) factor = 10.0; } else { factor = desktop_scale_factor(); } - // checks to prevent potential crash (factor <= 0) or very large factors - if (factor < 0.25) factor = 0.25; - else if (factor > 10.0) factor = 10.0; - return factor; + if (factor) { + for (int i = 0; i < screen_count(); i++) scale(i, factor); + } } @@ -495,10 +486,11 @@ void Fl_Screen_Driver::open_display() been_here = true; int ns = screen_count(); if (rescalable()) { - float factor = default_scale_factor(); - for (int i = 0; i < ns; i++) scale(i, factor); + use_startup_scale_factor(); Fl::add_handler(Fl_Screen_Driver::scale_handler); - Fl_Graphics_Driver::default_driver().scale(factor); + int mx, my; + int ns = Fl::screen_driver()->get_mouse(mx, my); + Fl_Graphics_Driver::default_driver().scale(scale(ns)); } } } diff --git a/src/Fl_Window_Driver.cxx b/src/Fl_Window_Driver.cxx index b750b1ff7..2ec0cfaff 100644 --- a/src/Fl_Window_Driver.cxx +++ b/src/Fl_Window_Driver.cxx @@ -260,6 +260,23 @@ int Fl_Window_Driver::screen_num() { return Fl::screen_num(x(), y(), w(), h()); } +void Fl_Window_Driver::resize_after_scale_change(int ns, float old_f, float new_f) { + int oldx = pWindow->x(), oldy = pWindow->y(); + fl_uintptr_t current = current_cursor(); + pWindow->hide(); + screen_num(ns); + pWindow->position(oldx*old_f/new_f, oldy*old_f/new_f); + force_position(1); + if (pWindow->fullscreen_active()) { + pWindow->size(pWindow->w() * old_f/new_f, pWindow->h() * old_f/new_f); + } + Fl_Graphics_Driver::default_driver().scale(new_f); + pWindow->show(); + reuse_cursor(current); + reuse_icons(); +//extern FILE*LOG;fprintf(LOG,"ns=%d old_f%.2f new_f=%.2f\n",ns,old_f,new_f);fflush(LOG); +} + // // End of "$Id$". // diff --git a/src/Fl_win32.cxx b/src/Fl_win32.cxx index 0366178bc..92a02dd3f 100644 --- a/src/Fl_win32.cxx +++ b/src/Fl_win32.cxx @@ -515,24 +515,24 @@ void Fl_WinAPI_Screen_Driver::open_display_platform() { } -float Fl_WinAPI_Screen_Driver::desktop_scale_factor() { - float f = 1; #ifdef FLTK_HIDPI_SUPPORT +void Fl_WinAPI_Screen_Driver::init_screen_scale_factors() { typedef HRESULT (WINAPI* GetDpiForMonitor_type)(HMONITOR, int, UINT*, UINT*); HMODULE hMod = LoadLibrary("Shcore.DLL"); GetDpiForMonitor_type fl_GetDpiForMonitor = NULL; if (hMod) fl_GetDpiForMonitor = (GetDpiForMonitor_type)GetProcAddress(hMod, "GetDpiForMonitor"); if (fl_GetDpiForMonitor) { - RECT rect = {0, 0, 0, 0}; - HMONITOR hm = MonitorFromRect(&rect, MONITOR_DEFAULTTOPRIMARY); - UINT dpiX, dpiY; - HRESULT r = fl_GetDpiForMonitor(hm, 0, &dpiX, &dpiY); - if (r == S_OK) f = dpiX/96.; -//fprintf(LOG, "result=%d dpiX=%d dpiY=%d factor=%.2f\n", r, dpiX, dpiY, f);fflush(LOG); + for (int ns = 0; ns < screen_count(); ns++) { + HMONITOR hm = MonitorFromRect(&screens[ns], MONITOR_DEFAULTTONEAREST); + UINT dpiX, dpiY; + HRESULT r = fl_GetDpiForMonitor(hm, 0, &dpiX, &dpiY); + float f = (r == S_OK ? dpiX/96. : 1); + scale(ns, f); +//fprintf(LOG, "desktop_scale_factor ns=%d factor=%.2f\n", ns, f);fflush(LOG); + } } -#endif // FLTK_HIDPI_SUPPORT - return f; } +#endif // FLTK_HIDPI_SUPPORT class Fl_Win32_At_Exit { @@ -1111,14 +1111,14 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar #ifdef FLTK_HIDPI_SUPPORT case 0x02E0: { // WM_DPICHANGED: - float f = HIWORD(wParam)/96.; - //for now, same scale factor for each screen - for (int i = 0; i < Fl::screen_count(); i++) Fl::screen_driver()->scale(i, f); - Fl_Graphics_Driver::default_driver().scale(f); -//fprintf(LOG,"WM_DPICHANGED f=%.2f\n", f);fflush(LOG); - if (!window->parent()) { - window->hide(); - window->show(); + if (!Fl_WinAPI_Window_Driver::data_for_resize_window_between_screens_.busy) { + RECT r; + float f = HIWORD(wParam)/96.; + GetClientRect(hWnd, &r); + float old_f = float(r.right)/window->w(); + int ns = window->driver()->screen_num(); + Fl::screen_driver()->scale(ns, f); + window->driver()->resize_after_scale_change(ns, old_f, f); } } return 0; @@ -1446,16 +1446,24 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar if (nx & 0x8000) nx -= 65536; if (ny & 0x8000) ny -= 65536; //fprintf(LOG,"WM_MOVE position(%d,%d) s=%.2f\n",int(nx/scale),int(ny/scale),scale); - window->position(nx/scale, ny/scale); // detect when window changes screen Fl_WinAPI_Screen_Driver *sd = (Fl_WinAPI_Screen_Driver*)Fl::screen_driver(); - int news = sd->screen_num_unscaled(nx + window->w()*scale, ny + window->h()*scale); + int news = sd->screen_num_unscaled(nx + window->w()*scale/2, ny + window->h()*scale/2); Fl_WinAPI_Window_Driver *wd = Fl_WinAPI_Window_Driver::driver(window); int olds = wd->screen_num(); + float s = sd->scale(news); +//fprintf(LOG,"WM_MOVE olds=%d(%.2f) news=%d(%.2f) busy=%d\n",olds, sd->scale(olds),news, s, Fl_WinAPI_Window_Driver::data_for_resize_window_between_screens_.busy);fflush(LOG); if (olds != news) { - wd->screen_num(news); -//fprintf(LOG,"olds=%d news=%d\n",olds,news); + if (s != sd->scale(olds) && + !Fl_WinAPI_Window_Driver::data_for_resize_window_between_screens_.busy && + window->user_data() != &Fl_WinAPI_Screen_Driver::transient_scale_display) { + Fl_WinAPI_Window_Driver::data_for_resize_window_between_screens_.busy = true; + Fl_WinAPI_Window_Driver::data_for_resize_window_between_screens_.screen = news; + Fl::add_timeout(1, Fl_WinAPI_Window_Driver::resize_after_screen_change, window); + } + else if(!Fl_WinAPI_Window_Driver::data_for_resize_window_between_screens_.busy) wd->screen_num(news); } + window->position(nx/scale, ny/scale); } break; @@ -1822,8 +1830,12 @@ Fl_X* Fl_WinAPI_Window_Driver::makeWindow() { Fl_Window *hint = Fl::first_window(); if (hint) { nscreen = hint->top_window()->driver()->screen_num(); + } else { + int mx, my; + nscreen = Fl::screen_driver()->get_mouse(mx, my); } } + w->driver()->screen_num(nscreen); float s = Fl::screen_driver()->scale(nscreen); int xp = w->x() * s; // these are in graphical units int yp = w->y() * s; @@ -2340,6 +2352,7 @@ int Fl_WinAPI_Window_Driver::set_cursor(const Fl_RGB_Image *image, int hotx, int } void Fl_WinAPI_Window_Driver::reuse_cursor(fl_uintptr_t c) { + cursor = (HCURSOR)c; SetCursor((HCURSOR)c); } diff --git a/src/Fl_x.cxx b/src/Fl_x.cxx index 71d9d95a6..f81ceff9f 100644 --- a/src/Fl_x.cxx +++ b/src/Fl_x.cxx @@ -1252,7 +1252,7 @@ int fl_handle(const XEvent& thisevent) XRRUpdateConfiguration_f(&xevent); Fl::call_screen_init(); #if USE_XFT - float factor = Fl::screen_driver()->default_scale_factor(); + float factor = Fl::screen_driver()->desktop_scale_factor(); for (int screen = 0; screen <= Fl::screen_count(); screen++) Fl::screen_driver()->rescale_all_windows_from_screen(screen, factor); #endif // USE_XFT diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H index 6dbfa7848..682afca25 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.H @@ -42,9 +42,14 @@ protected: static BOOL CALLBACK screen_cb(HMONITOR mon, HDC, LPRECT r, LPARAM); BOOL screen_cb(HMONITOR mon, HDC, LPRECT r); int get_mouse_unscaled(int &mx, int &my); +#ifdef FLTK_HIDPI_SUPPORT + void init_screen_scale_factors(); +#endif public: - Fl_WinAPI_Screen_Driver() : Fl_Screen_Driver() { } + Fl_WinAPI_Screen_Driver() : Fl_Screen_Driver() { + for (int i = 0; i < MAX_SCREENS; i++) scale_of_screen[i] = 1; + } // --- display management virtual int visual(int flags); // --- screen configuration @@ -85,11 +90,17 @@ public: virtual void offscreen_size(Fl_Offscreen off, int &width, int &height); #if defined(FLTK_HIDPI_SUPPORT) virtual APP_SCALING_CAPABILITY rescalable() { - return SYSTEMWIDE_APP_SCALING; + return PER_SCREEN_APP_SCALING; + } +#endif +#if defined(FLTK_HIDPI_SUPPORT) + virtual float scale(int n) { + return scale_of_screen[n]; + } + virtual void scale(int n, float f) { + scale_of_screen[n] = f; } #endif - virtual float scale(int n) {return scale_of_screen[n];} - virtual void scale(int n, float f) { scale_of_screen[n] = f;} virtual float desktop_scale_factor(); }; diff --git a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx index 236a33288..5951ba193 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx +++ b/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx @@ -100,7 +100,7 @@ BOOL Fl_WinAPI_Screen_Driver::screen_cb(HMONITOR mon, HDC, LPRECT r) 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; - scale_of_screen[num_screens] = 1; +//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); @@ -141,6 +141,9 @@ void Fl_WinAPI_Screen_Driver::init() // 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); +#ifdef FLTK_HIDPI_SUPPORT + init_screen_scale_factors(); +#endif return; } } @@ -157,6 +160,11 @@ void Fl_WinAPI_Screen_Driver::init() } +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(); diff --git a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.H b/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.H index 7f548c58b..29b20aefc 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.H +++ b/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.H @@ -71,12 +71,17 @@ public: static inline Fl_WinAPI_Window_Driver* driver(Fl_Window *w) {return (Fl_WinAPI_Window_Driver*)w->driver();} HDC private_dc; // used for OpenGL RECT border_width_title_bar_height(int &bx, int &by, int &bt); - virtual void screen_num(int n) { screen_num_ = n; } + virtual void screen_num(int n); virtual int screen_num(); struct icon_data *icon_; HCURSOR cursor; int custom_cursor; + struct type_for_resize_window_between_screens { + int screen; + bool busy; + }; + static type_for_resize_window_between_screens data_for_resize_window_between_screens_; void set_minmax(LPMINMAXINFO minmax); int fake_X_wm(int &X, int &Y, int &bt,int &bx,int &by); void make_fullscreen(int X, int Y, int W, int H); @@ -117,6 +122,7 @@ public: virtual void capture_titlebar_and_borders(Fl_Shared_Image*& top, Fl_Shared_Image*& left, Fl_Shared_Image*& bottom, Fl_Shared_Image*& right); virtual int scroll(int src_x, int src_y, int src_w, int src_h, int dest_x, int dest_y, void (*draw_area)(void*, int,int,int,int), void* data); + static void resize_after_screen_change(void *data); }; diff --git a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx b/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx index 079ca743d..a5621de6a 100644 --- a/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx +++ b/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx @@ -68,6 +68,13 @@ int Fl_WinAPI_Window_Driver::screen_num() { return screen_num_ >= 0 ? screen_num_ : 0; } +//FILE*LOG=fopen("log.log","w"); + +void Fl_WinAPI_Window_Driver::screen_num(int n) { +//fprintf(LOG, "screen_num setter old=%d new=%d\n",screen_num_, n);fflush(LOG); + screen_num_ = n; +} + RECT // frame of the decorated window in screen coordinates Fl_WinAPI_Window_Driver::border_width_title_bar_height( @@ -669,6 +676,19 @@ int Fl_WinAPI_Window_Driver::scroll(int src_x, int src_y, int src_w, int src_h, return 0; } +Fl_WinAPI_Window_Driver::type_for_resize_window_between_screens Fl_WinAPI_Window_Driver::data_for_resize_window_between_screens_ = {0, false}; + +void Fl_WinAPI_Window_Driver::resize_after_screen_change(void *data) { + Fl_Window *win = (Fl_Window*)data; + RECT r; + GetClientRect(fl_xid(win), &r); + float old_f = float(r.right)/win->w(); + int ns = data_for_resize_window_between_screens_.screen; + win->driver()->resize_after_scale_change(ns, old_f, Fl::screen_driver()->scale(ns)); + win->wait_for_expose(); + data_for_resize_window_between_screens_.busy = false; +} + // // End of "$Id$". //