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:
parent
ba10af9edb
commit
8dccfc8838
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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$".
|
||||
//
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
||||
|
@ -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$".
|
||||
//
|
||||
|
Loading…
Reference in New Issue
Block a user