diff --git a/v2/internal/ffenestri/ffenestri_windows.cpp b/v2/internal/ffenestri/ffenestri_windows.cpp index 8c8a0418b..5e8767ed3 100644 --- a/v2/internal/ffenestri/ffenestri_windows.cpp +++ b/v2/internal/ffenestri/ffenestri_windows.cpp @@ -2,6 +2,7 @@ // License included in README.md #include "ffenestri_windows.h" +#include "shellscalingapi.h" #include "wv2ComHandler_windows.h" #include #include @@ -42,6 +43,30 @@ char* LPWSTRToCstr(LPWSTR input) { return output; } + +// Credit: https://building.enlyze.com/posts/writing-win32-apps-like-its-2020-part-3/ +typedef int (__cdecl *PGetDpiForMonitor)(HMONITOR, MONITOR_DPI_TYPE,UINT*,UINT*); +void getDPIForWindow(struct Application *app) +{ + HMODULE hShcore = LoadLibraryW(L"shcore"); + if (hShcore) + { + PGetDpiForMonitor pGetDpiForMonitor = reinterpret_cast(GetProcAddress(hShcore, "GetDpiForMonitor")); + if (pGetDpiForMonitor) + { + HMONITOR hMonitor = MonitorFromWindow(app->window, MONITOR_DEFAULTTOPRIMARY); + pGetDpiForMonitor(hMonitor, (MONITOR_DPI_TYPE)0, &app->dpix, &app->dpiy); + } + } else { + // We couldn't get the window's DPI above, so get the DPI of the primary monitor + // using an API that is available in all Windows versions. + HDC hScreenDC = GetDC(0); + app->dpix = GetDeviceCaps(hScreenDC, LOGPIXELSX); + app->dpiy = GetDeviceCaps(hScreenDC, LOGPIXELSY); + ReleaseDC(0, hScreenDC); + } +} + struct Application *NewApplication(const char *title, int width, int height, int resizable, int devtools, int fullscreen, int startHidden, int logLevel, int hideWindowOnClose) { // Create application @@ -88,6 +113,9 @@ struct Application *NewApplication(const char *title, int width, int height, int // Used to remember the window location when going fullscreen result->previousPlacement = { sizeof(result->previousPlacement) }; + // DPI + result->dpix = result->dpiy = 0; + return result; } @@ -179,30 +207,28 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { return 0; } - // get pixel density - HDC hDC = GetDC(NULL); - double DPIScaleX = GetDeviceCaps(hDC, 88)/96.0; - double DPIScaleY = GetDeviceCaps(hDC, 90)/96.0; - ReleaseDC(NULL, hDC); + // update DPI + getDPIForWindow(app); + double DPIScaleX = app->dpix/96.0; + double DPIScaleY = app->dpiy/96.0; - RECT rcClient, rcWind; + RECT rcWind; POINT ptDiff; - GetClientRect(hwnd, &rcClient); GetWindowRect(hwnd, &rcWind); - int widthExtra = (rcWind.right - rcWind.left) - rcClient.right; - int heightExtra = (rcWind.bottom - rcWind.top) - rcClient.bottom; + int widthExtra = (rcWind.right - rcWind.left); + int heightExtra = (rcWind.bottom - rcWind.top); LPMINMAXINFO mmi = (LPMINMAXINFO) lParam; if (app->minWidth > 0 && app->minHeight > 0) { - mmi->ptMinTrackSize.x = app->minWidth * DPIScaleX + widthExtra; - mmi->ptMinTrackSize.y = app->minHeight * DPIScaleY + heightExtra; + mmi->ptMinTrackSize.x = app->minWidth * DPIScaleX; + mmi->ptMinTrackSize.y = app->minHeight * DPIScaleY; } if (app->maxWidth > 0 && app->maxHeight > 0) { - mmi->ptMaxSize.x = app->maxWidth * DPIScaleX + widthExtra; - mmi->ptMaxSize.y = app->maxHeight * DPIScaleY + heightExtra; - mmi->ptMaxTrackSize.x = app->maxWidth * DPIScaleX + widthExtra; - mmi->ptMaxTrackSize.y = app->maxHeight * DPIScaleY + heightExtra; + mmi->ptMaxSize.x = app->maxWidth * DPIScaleX; + mmi->ptMaxSize.y = app->maxHeight * DPIScaleY; + mmi->ptMaxTrackSize.x = app->maxWidth * DPIScaleX; + mmi->ptMaxTrackSize.y = app->maxHeight * DPIScaleY; } return 0; } @@ -392,6 +418,7 @@ bool initWebView2(struct Application *app, int debugEnabled, messageCallback cb) } app->webviewController = controller; app->webview = webview; + // Resize WebView to fit the bounds of the parent window RECT bounds; GetClientRect(app->window, &bounds); @@ -403,7 +430,64 @@ bool initWebView2(struct Application *app, int debugEnabled, messageCallback cb) LPCWSTR html = (LPCWSTR) cstrToLPWSTR((char*)assets[0]); app->webview->Navigate(html); + if( app->webviewIsTranparent ) { + wchar_t szBuff[64]; + ICoreWebView2Controller2 *wc2; + wc2 = nullptr; + app->webviewController->QueryInterface(IID_ICoreWebView2Controller2, (void**)&wc2); + + COREWEBVIEW2_COLOR wvColor; + wvColor.R = app->backgroundColour.R; + wvColor.G = app->backgroundColour.G; + wvColor.B = app->backgroundColour.B; + wvColor.A = app->backgroundColour.A == 0 ? 0 : 255; + if( app->windowBackgroundIsTranslucent ) { + wvColor.A = 0; + } + HRESULT result = wc2->put_DefaultBackgroundColor(wvColor); + if (!SUCCEEDED(result)) + { + switch (result) + { + case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND): + { + MessageBox( + app->window, + L"Couldn't find Edge installation. " + "Do you have a version installed that's compatible with this " + "WebView2 SDK version?", + nullptr, MB_OK); + } + break; + case HRESULT_FROM_WIN32(ERROR_FILE_EXISTS): + { + MessageBox( + app->window, L"User data folder cannot be created because a file with the same name already exists.", nullptr, MB_OK); + } + break; + case E_ACCESSDENIED: + { + MessageBox( + app->window, L"Unable to create user data folder, Access Denied.", nullptr, MB_OK); + } + break; + case E_FAIL: + { + MessageBox( + app->window, L"Edge runtime unable to start", nullptr, MB_OK); + } + break; + default: + { + MessageBox(app->window, L"Failed to create WebView2 environment", nullptr, MB_OK); + } + } + } + + } + messageFromWindowCallback("Ej{\"name\":\"wails:launched\",\"data\":[]}"); + return true; } @@ -500,61 +584,6 @@ void Run(struct Application* app, int argc, char **argv) { // Add webview2 initWebView2(app, debug, initialCallback); - if( app->webviewIsTranparent ) { - wchar_t szBuff[64]; - ICoreWebView2Controller2 *wc2; - wc2 = nullptr; - app->webviewController->QueryInterface(IID_ICoreWebView2Controller2, (void**)&wc2); - - COREWEBVIEW2_COLOR wvColor; - wvColor.R = app->backgroundColour.R; - wvColor.G = app->backgroundColour.G; - wvColor.B = app->backgroundColour.B; - wvColor.A = app->backgroundColour.A == 0 ? 0 : 255; - if( app->windowBackgroundIsTranslucent ) { - wvColor.A = 0; - } - HRESULT result = wc2->put_DefaultBackgroundColor(wvColor); - if (!SUCCEEDED(result)) - { - switch (result) - { - case HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND): - { - MessageBox( - app->window, - L"Couldn't find Edge installation. " - "Do you have a version installed that's compatible with this " - "WebView2 SDK version?", - nullptr, MB_OK); - } - break; - case HRESULT_FROM_WIN32(ERROR_FILE_EXISTS): - { - MessageBox( - app->window, L"User data folder cannot be created because a file with the same name already exists.", nullptr, MB_OK); - } - break; - case E_ACCESSDENIED: - { - MessageBox( - app->window, L"Unable to create user data folder, Access Denied.", nullptr, MB_OK); - } - break; - case E_FAIL: - { - MessageBox( - app->window, L"Edge runtime unable to start", nullptr, MB_OK); - } - break; - default: - { - MessageBox(app->window, L"Failed to create WebView2 environment", nullptr, MB_OK); - } - } - } - - } // Main event loop MSG msg; diff --git a/v2/internal/ffenestri/ffenestri_windows.go b/v2/internal/ffenestri/ffenestri_windows.go index 473f7234d..cfce6ecea 100644 --- a/v2/internal/ffenestri/ffenestri_windows.go +++ b/v2/internal/ffenestri/ffenestri_windows.go @@ -14,6 +14,7 @@ extern void DisableWindowIcon(struct Application* app); */ import "C" import ( + "github.com/ztrue/tracerr" "os" "github.com/wailsapp/wails/v2/pkg/menu" @@ -105,6 +106,7 @@ been sent. func checkFatal(err error) { if err != nil { + tracerr.PrintSourceColor(err) globalRadioGroupCache.Dump() globalRadioGroupMap.Dump() os.Exit(1) @@ -118,15 +120,17 @@ func createApplicationMenu(hwnd uintptr) { return } + var err error + window := win32Window(hwnd) + if globalApplicationMenu != nil { checkFatal(globalApplicationMenu.Destroy()) } - var err error globalApplicationMenu, err = createMenu(applicationMenu, appMenuType) checkFatal(err) - err = setWindowMenu(win32Window(hwnd), globalApplicationMenu.menu) + err = setWindowMenu(window, globalApplicationMenu.menu) checkFatal(err) } diff --git a/v2/internal/ffenestri/ffenestri_windows.h b/v2/internal/ffenestri/ffenestri_windows.h index 35d36feba..294f4cb2f 100644 --- a/v2/internal/ffenestri/ffenestri_windows.h +++ b/v2/internal/ffenestri/ffenestri_windows.h @@ -55,6 +55,10 @@ struct Application{ // placeholders char* bindings; char* initialCode; + + // DPI + UINT dpix; + UINT dpiy; }; #define ON_MAIN_THREAD(code) dispatch( [=]{ code; } ) diff --git a/v2/internal/ffenestri/windows_win32.go b/v2/internal/ffenestri/windows_win32.go index 2f5763c1d..99f5995b9 100644 --- a/v2/internal/ffenestri/windows_win32.go +++ b/v2/internal/ffenestri/windows_win32.go @@ -39,6 +39,16 @@ const MF_UNCHECKED uint32 = 0x00000000 const MF_BYCOMMAND uint32 = 0x00000000 const MF_BYPOSITION uint32 = 0x00000400 +const WM_SIZE = 5 +const WM_GETMINMAXINFO = 36 + +type Win32Rect struct { + Left int32 + Top int32 + Right int32 + Bottom int32 +} + // ------------------- win32 calls ----------------------- func createWin32Menu() (win32Menu, error) { @@ -97,3 +107,23 @@ func selectRadioItem(selectedMenuID, startMenuItemID, endMenuItemID win32MenuIte } return nil } + +// +//func getWindowRect(window win32Window) (*Win32Rect, error) { +// var windowRect Win32Rect +// res, _, err := win32GetWindowRect.Call(uintptr(window), uintptr(unsafe.Pointer(&windowRect))) +// if res == 0 { +// return nil, err +// } +// return &windowRect, nil +//} +// +//func getClientRect(window win32Window) (*Win32Rect, error) { +// var clientRect Win32Rect +// res, _, err := win32GetClientRect.Call(uintptr(window), uintptr(unsafe.Pointer(&clientRect))) +// if res == 0 { +// return nil, err +// } +// return &clientRect, nil +//} +//