From 761efed84d41d7570ee50d32a7b6b0ee34921d59 Mon Sep 17 00:00:00 2001 From: stffabi Date: Sat, 26 Aug 2023 02:11:01 +0200 Subject: [PATCH] [v2] Introduce size and physical size of screens (#2856) --- v2/internal/frontend/desktop/darwin/screen.go | 42 ++++++++++++++++++- v2/internal/frontend/desktop/linux/screen.go | 15 ++++++- .../frontend/desktop/windows/screen.go | 27 +++++++++--- v2/internal/frontend/frontend.go | 17 +++++++- website/src/pages/changelog.mdx | 1 + 5 files changed, 92 insertions(+), 10 deletions(-) diff --git a/v2/internal/frontend/desktop/darwin/screen.go b/v2/internal/frontend/desktop/darwin/screen.go index 7b552065a..a96a8efa7 100644 --- a/v2/internal/frontend/desktop/darwin/screen.go +++ b/v2/internal/frontend/desktop/darwin/screen.go @@ -18,6 +18,8 @@ typedef struct Screen { int isPrimary; int height; int width; + int pHeight; + int pWidth; } Screen; @@ -48,14 +50,42 @@ Screen GetNthScreen(int nth, void *inctx){ returnScreen.isPrimary = nth==0; returnScreen.height = (int) nthScreen.frame.size.height; returnScreen.width = (int) nthScreen.frame.size.width; + + returnScreen.pWidth = 0; + returnScreen.pHeight = 0; + + // https://stackoverflow.com/questions/13859109/how-to-programmatically-determine-native-pixel-resolution-of-retina-macbook-pro + CGDirectDisplayID sid = ((NSNumber *)[nthScreen.deviceDescription + objectForKey:@"NSScreenNumber"]).unsignedIntegerValue; + + CFArrayRef ms = CGDisplayCopyAllDisplayModes(sid, NULL); + CFIndex n = CFArrayGetCount(ms); + for (int i = 0; i < n; i++) { + CGDisplayModeRef m = (CGDisplayModeRef) CFArrayGetValueAtIndex(ms, i); + if (CGDisplayModeGetIOFlags(m) & kDisplayModeNativeFlag) { + // This corresponds with "System Settings" -> General -> About -> Displays + returnScreen.pWidth = CGDisplayModeGetPixelWidth(m); + returnScreen.pHeight = CGDisplayModeGetPixelHeight(m); + break; + } + } + CFRelease(ms); + + if (returnScreen.pWidth == 0 || returnScreen.pHeight == 0) { + // If there was no native resolution take a best fit approach and use the backing pixel size. + NSRect pSize = [nthScreen convertRectToBacking:nthScreen.frame]; + returnScreen.pHeight = (int) pSize.size.height; + returnScreen.pWidth = (int) pSize.size.width; + } return returnScreen; } */ import "C" import ( - "github.com/wailsapp/wails/v2/internal/frontend" "unsafe" + + "github.com/wailsapp/wails/v2/internal/frontend" ) func GetAllScreens(wailsContext unsafe.Pointer) ([]frontend.Screen, error) { @@ -65,11 +95,21 @@ func GetAllScreens(wailsContext unsafe.Pointer) ([]frontend.Screen, error) { for screeNum := 0; screeNum < numScreens; screeNum++ { screenNumC := C.int(screeNum) cScreen := C.GetNthScreen(screenNumC, wailsContext) + screen := frontend.Screen{ Height: int(cScreen.height), Width: int(cScreen.width), IsCurrent: cScreen.isCurrent == C.int(1), IsPrimary: cScreen.isPrimary == C.int(1), + + Size: frontend.ScreenSize{ + Height: int(cScreen.height), + Width: int(cScreen.width), + }, + PhysicalSize: frontend.ScreenSize{ + Height: int(cScreen.pHeight), + Width: int(cScreen.pWidth), + }, } screens = append(screens, screen) } diff --git a/v2/internal/frontend/desktop/linux/screen.go b/v2/internal/frontend/desktop/linux/screen.go index bd186363b..fdda9b055 100644 --- a/v2/internal/frontend/desktop/linux/screen.go +++ b/v2/internal/frontend/desktop/linux/screen.go @@ -16,6 +16,7 @@ typedef struct Screen { int isPrimary; int height; int width; + int scale; } Screen; int GetNMonitors(GtkWindow *window){ @@ -36,14 +37,16 @@ Screen GetNThMonitor(int monitor_num, GtkWindow *window){ screen.isPrimary = gdk_monitor_is_primary(monitor); screen.height = geometry.height; screen.width = geometry.width; + screen.scale = gdk_monitor_get_scale_factor(monitor); return screen; } */ import "C" import ( + "sync" + "github.com/pkg/errors" "github.com/wailsapp/wails/v2/internal/frontend" - "sync" ) type Screen = frontend.Screen @@ -59,11 +62,21 @@ func GetAllScreens(window *C.GtkWindow) ([]Screen, error) { numMonitors := C.GetNMonitors(window) for i := 0; i < int(numMonitors); i++ { cMonitor := C.GetNThMonitor(C.int(i), window) + screen := Screen{ IsCurrent: cMonitor.isCurrent == 1, IsPrimary: cMonitor.isPrimary == 1, Width: int(cMonitor.width), Height: int(cMonitor.height), + + Size: frontend.ScreenSize{ + Width: int(cMonitor.width), + Height: int(cMonitor.height), + }, + PhysicalSize: frontend.ScreenSize{ + Width: int(cMonitor.width * cMonitor.scale), + Height: int(cMonitor.height * cMonitor.scale), + }, } screens = append(screens, screen) } diff --git a/v2/internal/frontend/desktop/windows/screen.go b/v2/internal/frontend/desktop/windows/screen.go index e9e9cd603..f6e12bcce 100644 --- a/v2/internal/frontend/desktop/windows/screen.go +++ b/v2/internal/frontend/desktop/windows/screen.go @@ -5,10 +5,12 @@ package windows import ( "fmt" - "github.com/pkg/errors" - "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" "syscall" "unsafe" + + "github.com/pkg/errors" + "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc" + "github.com/wailsapp/wails/v2/internal/frontend/desktop/windows/winc/w32" ) func MonitorsEqual(first w32.MONITORINFO, second w32.MONITORINFO) bool { @@ -66,13 +68,26 @@ func EnumProc(hMonitor w32.HMONITOR, hdcMonitor w32.HDC, lprcMonitor *w32.RECT, return w32.TRUE } - height := lprcMonitor.Right - lprcMonitor.Left - width := lprcMonitor.Bottom - lprcMonitor.Top + width := lprcMonitor.Right - lprcMonitor.Left + height := lprcMonitor.Bottom - lprcMonitor.Top ourMonitorData.IsPrimary = monInfo.DwFlags&w32.MONITORINFOF_PRIMARY == 1 - ourMonitorData.Height = int(width) - ourMonitorData.Width = int(height) + ourMonitorData.Height = int(height) + ourMonitorData.Width = int(width) ourMonitorData.IsCurrent = MonitorsEqual(*currentMonInfo, *monInfo) + ourMonitorData.PhysicalSize.Width = int(width) + ourMonitorData.PhysicalSize.Height = int(height) + + var dpiX, dpiY uint + w32.GetDPIForMonitor(hMonitor, w32.MDT_EFFECTIVE_DPI, &dpiX, &dpiY) + if dpiX == 0 || dpiY == 0 { + screenContainer.errors = append(screenContainer.errors, fmt.Errorf("unable to get DPI for screen")) + screenContainer.monitors = append(screenContainer.monitors, Screen{}) + return w32.TRUE + } + ourMonitorData.Size.Width = winc.ScaleToDefaultDPI(ourMonitorData.PhysicalSize.Width, dpiX) + ourMonitorData.Size.Height = winc.ScaleToDefaultDPI(ourMonitorData.PhysicalSize.Height, dpiY) + // the reason we need a container is that we have don't know how many times this function will be called // this "append" call could potentially do an allocation and rewrite the pointer to monitors. So we save the pointer in screenContainer.monitors // and retrieve the values after all EnumProc calls diff --git a/v2/internal/frontend/frontend.go b/v2/internal/frontend/frontend.go index 79ee254c2..63807da6b 100644 --- a/v2/internal/frontend/frontend.go +++ b/v2/internal/frontend/frontend.go @@ -48,8 +48,21 @@ const ( type Screen struct { IsCurrent bool `json:"isCurrent"` IsPrimary bool `json:"isPrimary"` - Width int `json:"width"` - Height int `json:"height"` + + // Deprecated: Please use Size and PhysicalSize + Width int `json:"width"` + // Deprecated: Please use Size and PhysicalSize + Height int `json:"height"` + + // Size is the size of the screen in logical pixel space, used when setting sizes in Wails + Size ScreenSize `json:"size"` + // PhysicalSize is the physical size of the screen in pixels + PhysicalSize ScreenSize `json:"physicalSize"` +} + +type ScreenSize struct { + Width int `json:"width"` + Height int `json:"height"` } // MessageDialogOptions contains the options for the Message dialogs, EG Info, Warning, etc runtime methods diff --git a/website/src/pages/changelog.mdx b/website/src/pages/changelog.mdx index b5312d9b9..3d3582e3f 100644 --- a/website/src/pages/changelog.mdx +++ b/website/src/pages/changelog.mdx @@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added sveltekit.mdx guide. Added by @figuerom16 in [PR](https://github.com/wailsapp/wails/pull/2771) - Added ProgramName option to [linux.Options](/docs/reference/options#linux). Added by @lyimmi in [PR](https://github.com/wailsapp/wails/pull/2817) - Added new community tempalte wails-sveltekit-ts. Added by [@haukened](https://github.com/haukened) in [PR](https://github.com/wailsapp/wails/pull/2851) +- Added support for retrieving the logical and physical screen size in the screen api. Added by @stffabi in [PR](https://github.com/wailsapp/wails/pull/2856) ### Changed