HiDPI support under WIN32 platform: completed.

git-svn-id: file:///fltk/svn/fltk/branches/branch-1.4@12285 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
Manolo Gouy 2017-07-03 17:31:57 +00:00
parent ba10af9edb
commit 8dccfc8838
10 changed files with 121 additions and 52 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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));
}
}
}

View File

@ -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$".
//

View File

@ -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);
}

View File

@ -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

View File

@ -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();
};

View File

@ -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();

View File

@ -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);
};

View File

@ -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$".
//