Add screen support

Co-authored-by: Oleg Gulevskyy <43781031+oleggulevskyy@users.noreply.github.com>
This commit is contained in:
Lea Anthony 2022-12-28 14:07:13 +11:00
commit ad1d104d85
No known key found for this signature in database
GPG key ID: 33DAF7BB90A58405
6 changed files with 229 additions and 1 deletions

View file

@ -2,6 +2,7 @@ package main
import (
_ "embed"
"fmt"
"log"
"math/rand"
"strconv"
@ -169,7 +170,37 @@ func main() {
w.SetURL("https://wails.io")
})
})
stateMenu.Add("Get Primary Screen").OnClick(func(ctx *application.Context) {
screen, err := app.GetPrimaryScreen()
if err != nil {
app.NewErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
return
}
msg := fmt.Sprintf("Screen: %+v", screen)
app.NewInfoDialog().SetTitle("Primary Screen").SetMessage(msg).Show()
})
stateMenu.Add("Get Screens").OnClick(func(ctx *application.Context) {
screens, err := app.GetScreens()
if err != nil {
app.NewErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
return
}
for _, screen := range screens {
msg := fmt.Sprintf("Screen: %+v", screen)
app.NewInfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show()
}
})
stateMenu.Add("Get Screen for Window").OnClick(func(ctx *application.Context) {
currentWindow(func(w *application.Window) {
screen, err := w.GetScreen()
if err != nil {
app.NewErrorDialog().SetTitle("Error").SetMessage(err.Error()).Show()
return
}
msg := fmt.Sprintf("Screen: %+v", screen)
app.NewInfoDialog().SetTitle(fmt.Sprintf("Screen %s", screen.ID)).SetMessage(msg).Show()
})
})
app.NewWindow()
app.SetMenu(menu)

View file

@ -362,6 +362,14 @@ func (a *App) NewSaveFileDialog() *SaveFileDialog {
return newSaveFileDialog()
}
func (a *App) GetPrimaryScreen() (*Screen, error) {
return getPrimaryScreen()
}
func (a *App) GetScreens() ([]*Screen, error) {
return getScreens()
}
func (a *App) Clipboard() *Clipboard {
if a.clipboard == nil {
a.clipboard = newClipboard()

View file

@ -0,0 +1,26 @@
package application
type Screen struct {
ID string // A unique identifier for the display
Name string // The name of the display
Scale float32 // The scale factor of the display
X int // The x-coordinate of the top-left corner of the rectangle
Y int // The y-coordinate of the top-left corner of the rectangle
Size Size // The size of the display
Bounds Rect // The bounds of the display
WorkArea Rect // The work area of the display
IsPrimary bool // Whether this is the primary display
Rotation float32 // The rotation of the display
}
type Rect struct {
X int
Y int
Width int
Height int
}
type Size struct {
Width int
Height int
}

View file

@ -0,0 +1,151 @@
//go:build darwin
package application
/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation -framework Cocoa -framework WebKit -framework AppKit
#import <Foundation/Foundation.h>
#import <CoreGraphics/CoreGraphics.h>
#import <Cocoa/Cocoa.h>
#import <AppKit/AppKit.h>
#include <stdlib.h>
typedef struct Screen {
const char* id;
const char* name;
int p_width;
int p_height;
int width;
int height;
int x;
int y;
int w_width;
int w_height;
int w_x;
int w_y;
float scale;
double rotation;
bool isPrimary;
} Screen;
int GetNumScreens(){
return [[NSScreen screens] count];
}
Screen processScreen(NSScreen* screen){
Screen returnScreen;
returnScreen.scale = screen.backingScaleFactor;
// screen bounds
returnScreen.height = screen.frame.size.height;
returnScreen.width = screen.frame.size.width;
returnScreen.x = screen.frame.origin.x;
returnScreen.y = screen.frame.origin.y;
// work area
NSRect workArea = [screen visibleFrame];
returnScreen.w_height = workArea.size.height;
returnScreen.w_width = workArea.size.width;
returnScreen.w_x = workArea.origin.x;
returnScreen.w_y = workArea.origin.y;
// adapted from https://stackoverflow.com/a/1237490/4188138
NSDictionary* screenDictionary = [screen deviceDescription];
NSNumber* screenID = [screenDictionary objectForKey:@"NSScreenNumber"];
CGDirectDisplayID displayID = [screenID unsignedIntValue];
returnScreen.id = [[NSString stringWithFormat:@"%d", displayID] UTF8String];
// Get physical monitor size
NSValue *sizeValue = [screenDictionary objectForKey:@"NSDeviceSize"];
NSSize physicalSize = sizeValue.sizeValue;
returnScreen.p_height = physicalSize.height;
returnScreen.p_width = physicalSize.width;
// Get the rotation
double rotation = CGDisplayRotation(displayID);
returnScreen.rotation = rotation;
if( @available(macOS 10.15, *) ){
returnScreen.name = [screen.localizedName UTF8String];
}
return returnScreen;
}
// Get primary screen
Screen GetPrimaryScreen(){
// Get primary screen
NSScreen *mainScreen = [NSScreen mainScreen];
return processScreen(mainScreen);
}
Screen* getAllScreens() {
NSArray<NSScreen *> *screens = [NSScreen screens];
Screen* returnScreens = malloc(sizeof(Screen) * screens.count);
for (int i = 0; i < screens.count; i++) {
NSScreen* screen = [screens objectAtIndex:i];
returnScreens[i] = processScreen(screen);
}
return returnScreens;
}
Screen getScreenForWindow(void* window){
NSScreen* screen = ((NSWindow*)window).screen;
return processScreen(screen);
}
*/
import "C"
import "unsafe"
func cScreenToScreen(screen C.Screen) *Screen {
return &Screen{
Size: Size{
Width: int(screen.p_width),
Height: int(screen.p_height),
},
Bounds: Rect{
X: int(screen.x),
Y: int(screen.y),
Height: int(screen.height),
Width: int(screen.width),
},
WorkArea: Rect{
X: int(screen.w_x),
Y: int(screen.w_y),
Height: int(screen.w_height),
Width: int(screen.w_width),
},
Scale: float32(screen.scale),
ID: C.GoString(screen.id),
Name: C.GoString(screen.name),
IsPrimary: bool(screen.isPrimary),
Rotation: float32(screen.rotation),
}
}
func getPrimaryScreen() (*Screen, error) {
cScreen := C.GetPrimaryScreen()
return cScreenToScreen(cScreen), nil
}
func getScreens() ([]*Screen, error) {
cScreens := C.getAllScreens()
defer C.free(unsafe.Pointer(cScreens))
numScreens := int(C.GetNumScreens())
displays := make([]*Screen, numScreens)
cScreenHeaders := (*[1 << 30]C.Screen)(unsafe.Pointer(cScreens))[:numScreens:numScreens]
for i := 0; i < numScreens; i++ {
displays[i] = cScreenToScreen(cScreenHeaders[i])
}
return displays, nil
}
func getScreenForWindow(window *macosWindow) (*Screen, error) {
cScreen := C.getScreenForWindow(window.nsWindow)
return cScreenToScreen(cScreen), nil
}

View file

@ -52,6 +52,7 @@ type (
setFullscreenButtonEnabled(enabled bool)
show()
hide()
getScreen() (*Screen, error)
}
)
@ -545,3 +546,10 @@ func (w *Window) enableSizeConstraints() {
w.SetMinSize(w.options.MinWidth, w.options.MinHeight)
w.SetMaxSize(w.options.MaxWidth, w.options.MaxHeight)
}
func (w *Window) GetScreen() (*Screen, error) {
if w.impl == nil {
return nil, nil
}
return w.impl.getScreen()
}

View file

@ -691,6 +691,10 @@ type macosWindow struct {
parent *Window
}
func (w *macosWindow) getScreen() (*Screen, error) {
return getScreenForWindow(w)
}
func (w *macosWindow) show() {
C.windowShow(w.nsWindow)
}