app/internal/wm: use Option method to initialize windows

Added (*w.window).Option methods to the backends and use them for setting the initial options passed into NewWindow.

Signed-off-by: pierre <pierre.curto@gmail.com>
This commit is contained in:
pierre
2021-04-02 19:23:17 +02:00
committed by Elias Naur
parent b77c1628f3
commit ce7f0da06e
10 changed files with 207 additions and 110 deletions
+16 -1
View File
@@ -271,6 +271,7 @@ var (
_LoadImage = user32.NewProc("LoadImageW")
_MonitorFromPoint = user32.NewProc("MonitorFromPoint")
_MonitorFromWindow = user32.NewProc("MonitorFromWindow")
_MoveWindow = user32.NewProc("MoveWindow")
_MsgWaitForMultipleObjectsEx = user32.NewProc("MsgWaitForMultipleObjectsEx")
_OpenClipboard = user32.NewProc("OpenClipboard")
_PeekMessage = user32.NewProc("PeekMessageW")
@@ -289,8 +290,9 @@ var (
_SetProcessDPIAware = user32.NewProc("SetProcessDPIAware")
_SetTimer = user32.NewProc("SetTimer")
_SetWindowLong = user32.NewProc("SetWindowLongPtrW")
_SetWindowPos = user32.NewProc("SetWindowPos")
_SetWindowPlacement = user32.NewProc("SetWindowPlacement")
_SetWindowPos = user32.NewProc("SetWindowPos")
_SetWindowText = user32.NewProc("SetWindowTextW")
_TranslateMessage = user32.NewProc("TranslateMessage")
_UnregisterClass = user32.NewProc("UnregisterClassW")
_UpdateWindow = user32.NewProc("UpdateWindow")
@@ -486,6 +488,11 @@ func SetWindowPos(hwnd syscall.Handle, hwndInsertAfter uint32, x, y, dx, dy int3
)
}
func SetWindowText(hwnd syscall.Handle, title string) {
wname := syscall.StringToUTF16Ptr(title)
_SetWindowText.Call(uintptr(hwnd), uintptr(unsafe.Pointer(wname)))
}
func GlobalAlloc(size int) (syscall.Handle, error) {
r, _, err := _GlobalAlloc.Call(GHND, uintptr(size))
if r == 0 {
@@ -534,6 +541,14 @@ func LoadImage(hInst syscall.Handle, res uint32, typ uint32, cx, cy int, fuload
return syscall.Handle(h), nil
}
func MoveWindow(hwnd syscall.Handle, x, y, width, height int32, repaint bool) {
var paint uintptr
if repaint {
paint = TRUE
}
_MoveWindow.Call(uintptr(hwnd), uintptr(x), uintptr(y), uintptr(width), uintptr(height), paint)
}
func monitorFromPoint(pt Point, flags uint32) syscall.Handle {
r, _, _ := _MonitorFromPoint.Call(uintptr(pt.X), uintptr(pt.Y), uintptr(flags))
return syscall.Handle(r)
+2
View File
@@ -676,6 +676,8 @@ func (w *window) ReadClipboard() {
})
}
func (w *window) Option(opts *Options) {}
func (w *window) SetCursor(name pointer.CursorName) {
w.setState(func(state *windowState) {
state.cursor = &name
+2
View File
@@ -239,6 +239,8 @@ func (w *window) WriteClipboard(s string) {
})
}
func (w *window) Option(opts *Options) {}
func (w *window) SetAnimating(anim bool) {
v := w.view
if v == 0 {
+7 -3
View File
@@ -82,9 +82,7 @@ func NewWindow(win Callbacks, opts *Options) error {
})
w.addEventListeners()
w.addHistory()
if o := opts.WindowMode; o != nil {
w.windowMode(*o)
}
w.Option(opts)
w.w = win
go func() {
@@ -476,6 +474,12 @@ func (w *window) WriteClipboard(s string) {
w.clipboard.Call("writeText", s)
}
func (w *window) Option(opts *Options) {
if o := opts.WindowMode; o != nil {
w.windowMode(*o)
}
}
func (w *window) SetCursor(name pointer.CursorName) {
style := w.cnv.Get("style")
style.Set("cursor", string(name))
+55 -35
View File
@@ -46,6 +46,10 @@ __attribute__ ((visibility ("hidden"))) CFTypeRef gio_createWindow(CFTypeRef vie
__attribute__ ((visibility ("hidden"))) void gio_makeKeyAndOrderFront(CFTypeRef windowRef);
__attribute__ ((visibility ("hidden"))) NSPoint gio_cascadeTopLeftFromPoint(CFTypeRef windowRef, NSPoint topLeft);
__attribute__ ((visibility ("hidden"))) void gio_close(CFTypeRef windowRef);
__attribute__ ((visibility ("hidden"))) void gio_setSize(CFTypeRef windowRef, CGFloat width, CGFloat height);
__attribute__ ((visibility ("hidden"))) void gio_setMinSize(CFTypeRef windowRef, CGFloat width, CGFloat height);
__attribute__ ((visibility ("hidden"))) void gio_setMaxSize(CFTypeRef windowRef, CGFloat width, CGFloat height);
__attribute__ ((visibility ("hidden"))) void gio_setTitle(CFTypeRef windowRef, const char *title);
*/
import "C"
@@ -126,6 +130,45 @@ func (w *window) WriteClipboard(s string) {
})
}
func (w *window) Option(opts *Options) {
w.runOnMain(func() {
screenScale := float32(C.gio_getScreenBackingScale())
cfg := configFor(screenScale)
val := func(v unit.Value) float32 {
return float32(cfg.Px(v)) / screenScale
}
if o := opts.Size; o != nil {
width := val(o.Width)
height := val(o.Height)
if width > 0 || height > 0 {
C.gio_setSize(w.window, C.CGFloat(width), C.CGFloat(height))
}
}
if o := opts.MinSize; o != nil {
width := val(o.Width)
height := val(o.Height)
if width > 0 || height > 0 {
C.gio_setMinSize(w.window, C.CGFloat(width), C.CGFloat(height))
}
}
if o := opts.MaxSize; o != nil {
width := val(o.Width)
height := val(o.Height)
if width > 0 || height > 0 {
C.gio_setMaxSize(w.window, C.CGFloat(width), C.CGFloat(height))
}
}
if o := opts.Title; o != nil {
title := C.CString(*o)
defer C.free(unsafe.Pointer(title))
C.gio_setTitle(w.window, title)
}
if o := opts.WindowMode; o != nil {
w.SetWindowMode(*o)
}
})
}
func (w *window) SetWindowMode(mode WindowMode) {
switch mode {
case w.mode:
@@ -150,16 +193,22 @@ func (w *window) SetAnimating(anim bool) {
}
}
func (w *window) Close() {
func (w *window) runOnMain(f func()) {
runOnMain(func() {
// Make sure the view is still valid. The window might've been closed
// during the switch to the main thread.
if w.view != 0 {
C.gio_close(w.window)
f()
}
})
}
func (w *window) Close() {
w.runOnMain(func() {
C.gio_close(w.window)
})
}
func (w *window) setStage(stage system.Stage) {
if stage == w.stage {
return
@@ -336,35 +385,11 @@ func NewWindow(win Callbacks, opts *Options) error {
errch <- err
return
}
screenScale := float32(C.gio_getScreenBackingScale())
cfg := configFor(screenScale)
// Window sizes is in unscaled screen coordinates, not device pixels.
var width, height int
if o := opts.Size; o != nil {
width = int(float32(cfg.Px(o.Width)) / screenScale)
height = int(float32(cfg.Px(o.Height)) / screenScale)
}
var minWidth, minHeight int
if o := opts.MinSize; o != nil {
minWidth = int(float32(cfg.Px(o.Width)) / screenScale)
minHeight = int(float32(cfg.Px(o.Height)) / screenScale)
}
var maxWidth, maxHeight int
if o := opts.MaxSize; o != nil {
maxWidth = int(float32(cfg.Px(o.Width)) / screenScale)
maxHeight = int(float32(cfg.Px(o.Height)) / screenScale)
}
var title string
if o := opts.Title; o != nil {
title = *o
}
ctitle := C.CString(title)
defer C.free(unsafe.Pointer(ctitle))
errch <- nil
win.SetDriver(w)
w.w = win
w.window = C.gio_createWindow(w.view, ctitle, C.CGFloat(width), C.CGFloat(height),
C.CGFloat(minWidth), C.CGFloat(minHeight), C.CGFloat(maxWidth), C.CGFloat(maxHeight))
w.window = C.gio_createWindow(w.view, nil, 0, 0, 0, 0, 0, 0)
w.Option(opts)
if nextTopLeft.x == 0 && nextTopLeft.y == 0 {
// cascadeTopLeftFromPoint treats (0, 0) as a no-op,
// and just returns the offset we need for the first window.
@@ -372,9 +397,6 @@ func NewWindow(win Callbacks, opts *Options) error {
}
nextTopLeft = C.gio_cascadeTopLeftFromPoint(w.window, nextTopLeft)
C.gio_makeKeyAndOrderFront(w.window)
if o := opts.WindowMode; o != nil {
w.SetWindowMode(*o)
}
})
return <-errch
}
@@ -390,10 +412,8 @@ func newWindow(opts *Options) (*window, error) {
scale: scale,
}
dl, err := NewDisplayLink(func() {
runOnMain(func() {
if w.view != 0 {
C.gio_setNeedsDisplay(w.view)
}
w.runOnMain(func() {
C.gio_setNeedsDisplay(w.view)
})
})
w.displayLink = dl
+24 -1
View File
@@ -191,7 +191,9 @@ CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width,
window.contentMaxSize = NSMakeSize(maxWidth, maxHeight);
}
[window setAcceptsMouseMovedEvents:YES];
window.title = [NSString stringWithUTF8String: title];
if (title != nil) {
window.title = [NSString stringWithUTF8String: title];
}
NSView *view = (__bridge NSView *)viewRef;
[window setContentView:view];
[window makeFirstResponder:view];
@@ -206,6 +208,27 @@ void gio_close(CFTypeRef windowRef) {
[window performClose:nil];
}
void gio_setSize(CFTypeRef windowRef, CGFloat width, CGFloat height) {
NSWindow* window = (__bridge NSWindow *)windowRef;
NSSize size = NSMakeSize(width, height);
[window setContentSize:size];
}
void gio_setMinSize(CFTypeRef windowRef, CGFloat width, CGFloat height) {
NSWindow* window = (__bridge NSWindow *)windowRef;
window.contentMinSize = NSMakeSize(width, height);
}
void gio_setMaxSize(CFTypeRef windowRef, CGFloat width, CGFloat height) {
NSWindow* window = (__bridge NSWindow *)windowRef;
window.contentMaxSize = NSMakeSize(width, height);
}
void gio_setTitle(CFTypeRef windowRef, const char *title) {
NSWindow* window = (__bridge NSWindow *)windowRef;
window.title = [NSString stringWithUTF8String: title];
}
@implementation GioAppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
+14 -10
View File
@@ -357,17 +357,8 @@ func (d *wlDisplay) createNativeWindow(opts *Options) (*window, error) {
C.xdg_surface_add_listener(w.wmSurf, &C.gio_xdg_surface_listener, unsafe.Pointer(w.surf))
C.xdg_toplevel_add_listener(w.topLvl, &C.gio_xdg_toplevel_listener, unsafe.Pointer(w.surf))
if o := opts.Title; o != nil {
title := C.CString(*o)
C.xdg_toplevel_set_title(w.topLvl, title)
C.free(unsafe.Pointer(title))
}
w.Option(opts)
_, _, cfg := w.config()
if o := opts.Size; o != nil {
w.width = cfg.Px(o.Width)
w.height = cfg.Px(o.Height)
}
if d.decor != nil {
// Request server side decorations.
w.decor = C.zxdg_decoration_manager_v1_get_toplevel_decoration(d.decor, w.topLvl)
@@ -918,6 +909,19 @@ func (w *window) WriteClipboard(s string) {
w.disp.wakeup()
}
func (w *window) Option(opts *Options) {
_, _, cfg := w.config()
if o := opts.Size; o != nil {
w.width = cfg.Px(o.Width)
w.height = cfg.Px(o.Height)
}
if o := opts.Title; o != nil {
title := C.CString(*o)
C.xdg_toplevel_set_title(w.topLvl, title)
C.free(unsafe.Pointer(title))
}
}
func (w *window) SetCursor(name pointer.CursorName) {
if name == pointer.CursorNone {
C.wl_pointer_set_cursor(w.disp.seat.pointer, w.serial, nil, 0, 0)
+42 -24
View File
@@ -116,15 +116,13 @@ func NewWindow(window Callbacks, opts *Options) error {
w.w = window
w.w.SetDriver(w)
defer w.w.Event(system.DestroyEvent{})
w.Option(opts)
windows.ShowWindow(w.hwnd, windows.SW_SHOWDEFAULT)
windows.SetForegroundWindow(w.hwnd)
windows.SetFocus(w.hwnd)
// Since the window class for the cursor is null,
// set it here to show the cursor.
w.SetCursor(pointer.CursorDefault)
if o := opts.WindowMode; o != nil {
w.SetWindowMode(*o)
}
if err := w.loop(); err != nil {
panic(err)
}
@@ -185,33 +183,15 @@ func createNativeWindow(opts *Options) (*window, error) {
}
dpi := windows.GetSystemDPI()
cfg := configForDPI(dpi)
var wr windows.Rect
if o := opts.Size; o != nil {
wr.Right = int32(cfg.Px(o.Width))
wr.Bottom = int32(cfg.Px(o.Height))
}
dwStyle := uint32(windows.WS_OVERLAPPEDWINDOW)
dwExStyle := uint32(windows.WS_EX_APPWINDOW | windows.WS_EX_WINDOWEDGE)
deltas := winDeltas{
width: wr.Right,
height: wr.Bottom,
}
windows.AdjustWindowRectEx(&wr, dwStyle, 0, dwExStyle)
deltas.width = wr.Right - wr.Left - deltas.width
deltas.height = wr.Bottom - wr.Top - deltas.height
var title string
if o := opts.Title; o != nil {
title = *o
}
hwnd, err := windows.CreateWindowEx(dwExStyle,
resources.class,
title,
"",
dwStyle|windows.WS_CLIPSIBLINGS|windows.WS_CLIPCHILDREN,
windows.CW_USEDEFAULT, windows.CW_USEDEFAULT,
wr.Right-wr.Left,
wr.Bottom-wr.Top,
windows.CW_USEDEFAULT, windows.CW_USEDEFAULT,
0,
0,
resources.handle,
@@ -222,7 +202,6 @@ func createNativeWindow(opts *Options) (*window, error) {
w := &window{
hwnd: hwnd,
minmax: getWindowConstraints(cfg, opts),
deltas: deltas,
opts: opts,
}
w.hdc, err = windows.GetDC(hwnd)
@@ -540,6 +519,45 @@ func (w *window) readClipboard() error {
return nil
}
func (w *window) Option(opts *Options) {
if o := opts.Size; o != nil {
dpi := windows.GetSystemDPI()
cfg := configForDPI(dpi)
width := int32(cfg.Px(o.Width))
height := int32(cfg.Px(o.Height))
// Include the window decorations.
wr := windows.Rect{
Right: width,
Bottom: height,
}
dwStyle := uint32(windows.WS_OVERLAPPEDWINDOW)
dwExStyle := uint32(windows.WS_EX_APPWINDOW | windows.WS_EX_WINDOWEDGE)
windows.AdjustWindowRectEx(&wr, dwStyle, 0, dwExStyle)
dw, dh := width, height
width = wr.Right - wr.Left
height = wr.Bottom - wr.Top
w.deltas.width = width - dw
w.deltas.height = height - dh
w.opts.Size = o
windows.MoveWindow(w.hwnd, 0, 0, width, height, true)
}
if o := opts.MinSize; o != nil {
w.opts.MinSize = o
}
if o := opts.MaxSize; o != nil {
w.opts.MaxSize = o
}
if o := opts.Title; o != nil {
windows.SetWindowText(w.hwnd, *opts.Title)
}
if o := opts.WindowMode; o != nil {
w.SetWindowMode(*o)
}
}
func (w *window) SetWindowMode(mode WindowMode) {
// https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353
switch mode {
+42 -36
View File
@@ -123,6 +123,47 @@ func (w *x11Window) WriteClipboard(s string) {
w.wakeup()
}
func (w *x11Window) Option(opts *Options) {
dpy := w.x
win := w.xw
cfg := w.cfg
var shints C.XSizeHints
if o := opts.MinSize; o != nil {
shints.min_width = C.int(cfg.Px(o.Width))
shints.min_height = C.int(cfg.Px(o.Height))
shints.flags = C.PMinSize
}
if o := opts.MaxSize; o != nil {
shints.max_width = C.int(cfg.Px(o.Width))
shints.max_height = C.int(cfg.Px(o.Height))
shints.flags = shints.flags | C.PMaxSize
}
if shints.flags != 0 {
C.XSetWMNormalHints(dpy, win, &shints)
}
var title string
if o := opts.Title; o != nil {
title = *o
}
ctitle := C.CString(title)
defer C.free(unsafe.Pointer(ctitle))
C.XStoreName(dpy, win, ctitle)
// set _NET_WM_NAME as well for UTF-8 support in window title.
C.XSetTextProperty(dpy, win,
&C.XTextProperty{
value: (*C.uchar)(unsafe.Pointer(ctitle)),
encoding: w.atoms.utf8string,
format: 8,
nitems: C.ulong(len(title)),
},
w.atoms.wmName)
if o := opts.WindowMode; o != nil {
w.SetWindowMode(*o)
}
}
func (w *x11Window) SetCursor(name pointer.CursorName) {
switch name {
case pointer.CursorNone:
@@ -607,21 +648,6 @@ func newX11Window(gioWin Callbacks, opts *Options) error {
hints.flags = C.InputHint
C.XSetWMHints(dpy, win, &hints)
var shints C.XSizeHints
if o := opts.MinSize; o != nil && (o.Width.V != 0 || o.Height.V != 0) {
shints.min_width = C.int(cfg.Px(o.Width))
shints.min_height = C.int(cfg.Px(o.Height))
shints.flags = C.PMinSize
}
if o := opts.MaxSize; o != nil && (o.Width.V != 0 || o.Height.V != 0) {
shints.max_width = C.int(cfg.Px(o.Width))
shints.max_height = C.int(cfg.Px(o.Height))
shints.flags = shints.flags | C.PMaxSize
}
if shints.flags != 0 {
C.XSetWMNormalHints(dpy, win, &shints)
}
name := C.CString(filepath.Base(os.Args[0]))
defer C.free(unsafe.Pointer(name))
wmhints := C.XClassHint{name, name}
@@ -639,30 +665,10 @@ func newX11Window(gioWin Callbacks, opts *Options) error {
w.atoms.wmState = w.atom("_NET_WM_STATE", false)
w.atoms.wmStateFullscreen = w.atom("_NET_WM_STATE_FULLSCREEN", false)
// set the name
var title string
if o := opts.Title; o != nil {
title = *o
}
ctitle := C.CString(title)
defer C.free(unsafe.Pointer(ctitle))
C.XStoreName(dpy, win, ctitle)
// set _NET_WM_NAME as well for UTF-8 support in window title.
C.XSetTextProperty(dpy, win,
&C.XTextProperty{
value: (*C.uchar)(unsafe.Pointer(ctitle)),
encoding: w.atoms.utf8string,
format: 8,
nitems: C.ulong(len(title)),
},
w.atoms.wmName)
// extensions
C.XSetWMProtocols(dpy, win, &w.atoms.evDelWindow, 1)
if o := opts.WindowMode; o != nil {
w.SetWindowMode(*o)
}
w.Option(opts)
// make the window visible on the screen
C.XMapWindow(dpy, win)
+3
View File
@@ -74,6 +74,9 @@ type Driver interface {
// WriteClipboard requests a clipboard write.
WriteClipboard(s string)
// Option processes option changes.
Option(opts *Options)
// SetCursor updates the current cursor to name.
SetCursor(name pointer.CursorName)