diff --git a/indra/llwindow/llwindow.h b/indra/llwindow/llwindow.h index 0d53f5951..d0cb3802d 100644 --- a/indra/llwindow/llwindow.h +++ b/indra/llwindow/llwindow.h @@ -65,6 +65,7 @@ public: // currently unused }; public: + virtual void postInitialized() {} virtual void show() = 0; virtual void hide() = 0; virtual void close() = 0; diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index 9712ae1d9..5b2e2f795 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -185,6 +185,11 @@ void LLWindowCallbacks::handleResumeWatchdog(LLWindow *window) } +bool LLWindowCallbacks::handleDPIScaleChange(LLWindow *window, float xDPIScale, float yDPIScale, U32 width, U32 height) +{ + return false; +} + std::string LLWindowCallbacks::translateString(const char* tag) { return std::string(); diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 7da595970..aa349d29f 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -79,7 +79,8 @@ public: DND_LINK // Drop accepted would result in a "link" operation }; virtual DragNDropResult handleDragNDrop(LLWindow *window, LLCoordGL pos, MASK mask, DragNDropAction action, std::string data); - + virtual bool handleDPIScaleChange(LLWindow *window, float xDPIScale, float yDPIScale, U32 width = 0, U32 height = 0); + virtual void handlePingWatchdog(LLWindow *window, const char * msg); virtual void handlePauseWatchdog(LLWindow *window); virtual void handleResumeWatchdog(LLWindow *window); diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index 3a6580145..14a2729fb 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -53,6 +53,7 @@ #include #include #include +#include // Require DirectInput version 8 #define DIRECTINPUT_VERSION 0x0800 @@ -395,6 +396,8 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, mKeyVirtualKey = 0; mhDC = NULL; mhRC = NULL; + mUser32Lib = nullptr; + mSHCoreLib = nullptr; LL_INFOS() << "Desired FSAA Samples = " << mFSAASamples << LL_ENDL; @@ -659,6 +662,8 @@ LLWindowWin32::LLWindowWin32(LLWindowCallbacks* callbacks, // Initialize (boot strap) the Language text input management, // based on the system's (or user's) default settings. allowLanguageTextInput(NULL, FALSE); + + initDPIAwareness(); } @@ -674,6 +679,16 @@ LLWindowWin32::~LLWindowWin32() delete [] mWindowClassName; mWindowClassName = NULL; + + FreeLibrary(mUser32Lib); + FreeLibrary(mSHCoreLib); +} + +void LLWindowWin32::postInitialized() +{ + float xDPIScale, yDPIScale; + getDPIScales(xDPIScale, yDPIScale); + mCallbacks->handleDPIScaleChange(this, xDPIScale, yDPIScale); } void LLWindowWin32::show() @@ -1774,7 +1789,50 @@ void LLWindowWin32::initCursors() } } +void LLWindowWin32::initDPIAwareness() +{ + mUser32Lib = LoadLibrary(L"user32.dll"); + mSHCoreLib = LoadLibrary(L"Shcore.dll"); + + if (mUser32Lib && mSHCoreLib) + { + MonitorFromWindowFn = reinterpret_cast(GetProcAddress(mUser32Lib, "MonitorFromWindow")); + GetDpiForMonitorFn = reinterpret_cast(GetProcAddress(mSHCoreLib, "GetDpiForMonitor")); + if (MonitorFromWindowFn && GetDpiForMonitorFn) + { + HRESULT(WINAPI* SetProcessDpiAwareness)(PROCESS_DPI_AWARENESS); + SetProcessDpiAwareness = reinterpret_cast(GetProcAddress(mSHCoreLib, "SetProcessDpiAwareness")); + if (SetProcessDpiAwareness && SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE) == S_OK) + return; + + BOOL(WINAPI* SetProcessDPIAware)(void); + SetProcessDPIAware = reinterpret_cast(GetProcAddress(mUser32Lib, "SetProcessDPIAware")); + if (SetProcessDPIAware && SetProcessDPIAware()) + return; + } + } + + FreeLibrary(mUser32Lib); + FreeLibrary(mSHCoreLib); + mUser32Lib = nullptr; + mSHCoreLib = nullptr; +} + +void LLWindowWin32::getDPIScales(float &xDPIScale, float& yDPIScale) +{ + xDPIScale = yDPIScale = 1.f; + if (mUser32Lib) + { + uint32_t xDPI, yDPI; + auto window = MonitorFromWindowFn(mWindowHandle, MONITOR_DEFAULTTONEAREST); + if (GetDpiForMonitorFn(window, MDT_EFFECTIVE_DPI, &xDPI, &yDPI) == S_OK) + { + xDPIScale = (float)xDPI / (float)USER_DEFAULT_SCREEN_DPI; + yDPIScale = (float)yDPI / (float)USER_DEFAULT_SCREEN_DPI; + } + } +} void LLWindowWin32::updateCursor() { @@ -2657,6 +2715,26 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ }; return 0; + case WM_DPICHANGED: + { + window_imp->mCallbacks->handlePingWatchdog(window_imp, "Main:WM_DPICHANGED"); + if (gDebugWindowProc) + { + LL_INFOS("Window") << "WM_DPICHANGED " << LOWORD(w_param) << " " << HIWORD(w_param) << LL_ENDL; + } + LPRECT rect = (LPRECT)l_param; + S32 width = ((LPRECT)l_param)->right - ((LPRECT)l_param)->left; + S32 height = ((LPRECT)l_param)->bottom - ((LPRECT)l_param)->top; + LL_INFOS() << "rect: " << width << "x" << height << LL_ENDL; + if(window_imp->mCallbacks->handleDPIScaleChange(window_imp, + (F32)LOWORD(w_param) / (F32)USER_DEFAULT_SCREEN_DPI, + (F32)HIWORD(w_param) / (F32)USER_DEFAULT_SCREEN_DPI, + width, + height)) + SetWindowPos(h_wnd, HWND_TOP, rect->left, rect->top, rect->right - rect->left, rect->bottom - rect->top, SWP_NOZORDER | SWP_NOACTIVATE); + } + return 0; + break; } diff --git a/indra/llwindow/llwindowwin32.h b/indra/llwindow/llwindowwin32.h index 3412dcd9a..6b100fd9a 100644 --- a/indra/llwindow/llwindowwin32.h +++ b/indra/llwindow/llwindowwin32.h @@ -43,6 +43,7 @@ typedef void (*LLW32MsgCallback)(const MSG &msg); class LLWindowWin32 : public LLWindow { public: + /*virtual*/ void postInitialized(); /*virtual*/ void show(); /*virtual*/ void hide(); /*virtual*/ void close(); @@ -129,6 +130,8 @@ protected: void initCursors(); void initInputDevices(); + void initDPIAwareness(); + void getDPIScales(float& xDPIScale, float& yDPIScale); HCURSOR loadColorCursor(LPCTSTR name); BOOL isValid(); void moveWindow(const LLCoordScreen& position,const LLCoordScreen& size); @@ -219,6 +222,11 @@ protected: U32 mRawWParam; U32 mRawLParam; + HMODULE mUser32Lib; + HMODULE mSHCoreLib; + HMONITOR(WINAPI *MonitorFromWindowFn)(HWND, DWORD); + HRESULT(WINAPI *GetDpiForMonitorFn)(HMONITOR, INT, UINT *, UINT *); + friend class LLWindowManager; }; diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 83cee3ec1..d678e11ad 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1569,6 +1569,22 @@ BOOL LLViewerWindow::handleDeviceChange(LLWindow *window) return FALSE; } +bool LLViewerWindow::handleDPIScaleChange(LLWindow *window, float xDPIScale, float yDPIScale, U32 width, U32 height) +{ + LL_INFOS() << "handleDPIScaleChange" << LL_ENDL; + if (mDPIScaleX != xDPIScale || mDPIScaleY != yDPIScale) + { + LL_INFOS() << "handleDPIScaleChange APPLY" << LL_ENDL; + mDPIScaleX = xDPIScale; + mDPIScaleY = yDPIScale; + if (!mWindow->getFullscreen()) { + reshape(width ? width : getWindowWidthRaw(), height ? height : getWindowHeightRaw()); + return true; + } + } + return false; +} + void LLViewerWindow::handlePingWatchdog(LLWindow *window, const char * msg) { LLAppViewer::instance()->pingMainloopTimeout(msg); @@ -1637,7 +1653,9 @@ LLViewerWindow::LLViewerWindow( //mStatesDirty(false), //Singu Note: No longer needed. State update is now in restoreGL. mIsFullscreenChecked(false), mCurrResolutionIndex(0), - mProgressView(NULL) + mProgressView(NULL), + mDPIScaleX(1.f), + mDPIScaleY(1.f) { LLNotificationChannel::buildChannel("VW_alerts", "Visible", LLNotificationFilters::filterBy(&LLNotification::getType, "alert")); LLNotificationChannel::buildChannel("VW_alertmodal", "Visible", LLNotificationFilters::filterBy(&LLNotification::getType, "alertmodal")); @@ -1706,10 +1724,9 @@ LLViewerWindow::LLViewerWindow( // Get the real window rect the window was created with (since there are various OS-dependent reasons why // the size of a window or fullscreen context may have been adjusted slightly...) - F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor"); - mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f)); - mDisplayScale *= ui_scale_factor; + mDisplayScale.scaleVec(getUIScale()); + LLUI::setScaleFactor(mDisplayScale); { @@ -1799,6 +1816,8 @@ LLViewerWindow::LLViewerWindow( mDebugText = new LLDebugText(this); + mWindow->postInitialized(); + } void LLViewerWindow::initGLDefaults() @@ -5730,17 +5749,17 @@ F32 LLViewerWindow::getDisplayAspectRatio() const void LLViewerWindow::calcDisplayScale() { - F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor"); + LLVector2 ui_scale_factor = getUIScale(); LLVector2 display_scale; display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f)); if(mWindow->getFullscreen()) { F32 height_normalization = gSavedSettings.getBOOL("UIAutoScale") ? ((F32)mWindowRectRaw.getHeight() / display_scale.mV[VY]) / 768.f : 1.f; - display_scale *= (ui_scale_factor * height_normalization); + display_scale.scaleVec(ui_scale_factor * height_normalization); } else { - display_scale *= ui_scale_factor; + display_scale.scaleVec(ui_scale_factor); } // limit minimum display scale @@ -5765,6 +5784,20 @@ void LLViewerWindow::calcDisplayScale() } } +LLVector2 LLViewerWindow::getUIScale() const +{ + LL_INFOS() << "getUIScale" << LL_ENDL; + static LLCachedControl ui_scale_factor("UIScaleFactor"); + if (mWindow->getFullscreen()) + { + return LLVector2(ui_scale_factor, ui_scale_factor); + } + else + { + return LLVector2(mDPIScaleX * ui_scale_factor, mDPIScaleY * ui_scale_factor); + } +} + S32 LLViewerWindow::getChatConsoleBottomPad() { static const LLCachedControl user_offset("ConsoleBottomOffset"); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 437dd874b..cdc65f4b6 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -181,6 +181,7 @@ public: /*virtual*/ void handleDataCopy(LLWindow *window, S32 data_type, void *data); /*virtual*/ BOOL handleTimerEvent(LLWindow *window); /*virtual*/ BOOL handleDeviceChange(LLWindow *window); + /*virtual*/ bool handleDPIScaleChange(LLWindow *window, float xDPIScale, float yDPIScale, U32 width = 0, U32 height = 0); /*virtual*/ void handlePingWatchdog(LLWindow *window, const char * msg); /*virtual*/ void handlePauseWatchdog(LLWindow *window); @@ -393,6 +394,8 @@ public: const LLVector2& getDisplayScale() const { return mDisplayScale; } void calcDisplayScale(); + LLVector2 getUIScale() const; + private: bool shouldShowToolTipFor(LLMouseHandler *mh); static bool onAlert(const LLSD& notify); @@ -464,6 +467,9 @@ protected: bool mIsFullscreenChecked; // Did the user check the fullscreen checkbox in the display settings U32 mCurrResolutionIndex; + float mDPIScaleX; + float mDPIScaleY; + protected: static std::string sSnapshotBaseName; static std::string sSnapshotDir; diff --git a/indra/newview/llworldmapview.cpp b/indra/newview/llworldmapview.cpp index 8064b537b..d9f85ec9b 100644 --- a/indra/newview/llworldmapview.cpp +++ b/indra/newview/llworldmapview.cpp @@ -1250,9 +1250,9 @@ void LLWorldMapView::drawFrustum() F32 half_width_pixels = half_width_meters * meters_to_pixels; // Compute the frustum coordinates. Take the UI scale into account. - static LLCachedControl ui_scale_factor("UIScaleFactor"); - F32 ctr_x = (getLocalRect().getWidth() * 0.5f + sPanX) * ui_scale_factor; - F32 ctr_y = (getLocalRect().getHeight() * 0.5f + sPanY) * ui_scale_factor; + LLVector2 ui_scale_factor = gViewerWindow->getUIScale(); + F32 ctr_x = (getLocalRect().getWidth() * 0.5f + sPanX) * ui_scale_factor.mV[VX]; + F32 ctr_y = (getLocalRect().getHeight() * 0.5f + sPanY) * ui_scale_factor.mV[VY]; gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);