mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-04 08:55:35 +00:00
app/internal/window: [Windows] support multiple windows
Updates gio#19 Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -26,8 +26,6 @@ import (
|
|||||||
"gioui.org/io/system"
|
"gioui.org/io/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
var winMap = make(map[syscall.Handle]*window)
|
|
||||||
|
|
||||||
type window struct {
|
type window struct {
|
||||||
hwnd syscall.Handle
|
hwnd syscall.Handle
|
||||||
hdc syscall.Handle
|
hdc syscall.Handle
|
||||||
@@ -44,16 +42,34 @@ type window struct {
|
|||||||
|
|
||||||
const _WM_REDRAW = windows.WM_USER + 0
|
const _WM_REDRAW = windows.WM_USER + 0
|
||||||
|
|
||||||
var onceMu sync.Mutex
|
|
||||||
var mainDone = make(chan struct{})
|
var mainDone = make(chan struct{})
|
||||||
|
|
||||||
|
type gpuAPI struct {
|
||||||
|
priority int
|
||||||
|
initializer func(w *window) (Context, error)
|
||||||
|
}
|
||||||
|
|
||||||
// backends is the list of potential Context
|
// backends is the list of potential Context
|
||||||
// implementations.
|
// implementations.
|
||||||
var backends []gpuAPI
|
var backends []gpuAPI
|
||||||
|
|
||||||
type gpuAPI struct {
|
var winMap struct {
|
||||||
priority int
|
mu sync.Mutex
|
||||||
initializer func(w *window) (Context, error)
|
windows map[syscall.Handle]*window
|
||||||
|
}
|
||||||
|
|
||||||
|
var resources struct {
|
||||||
|
once sync.Once
|
||||||
|
// handle is the module handle from GetModuleHandle.
|
||||||
|
handle syscall.Handle
|
||||||
|
// class is the Gio window class from RegisterClassEx.
|
||||||
|
class uint16
|
||||||
|
// cursor is the arrow cursor resource
|
||||||
|
cursor syscall.Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
winMap.windows = make(map[syscall.Handle]*window)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Main() {
|
func Main() {
|
||||||
@@ -61,11 +77,6 @@ func Main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewWindow(window Callbacks, opts *Options) error {
|
func NewWindow(window Callbacks, opts *Options) error {
|
||||||
onceMu.Lock()
|
|
||||||
defer onceMu.Unlock()
|
|
||||||
if len(winMap) > 0 {
|
|
||||||
return errors.New("multiple windows are not supported")
|
|
||||||
}
|
|
||||||
cerr := make(chan error)
|
cerr := make(chan error)
|
||||||
go func() {
|
go func() {
|
||||||
// Call win32 API from a single OS thread.
|
// Call win32 API from a single OS thread.
|
||||||
@@ -77,8 +88,20 @@ func NewWindow(window Callbacks, opts *Options) error {
|
|||||||
}
|
}
|
||||||
defer w.destroy()
|
defer w.destroy()
|
||||||
cerr <- nil
|
cerr <- nil
|
||||||
winMap[w.hwnd] = w
|
winMap.mu.Lock()
|
||||||
defer delete(winMap, w.hwnd)
|
winMap.windows[w.hwnd] = w
|
||||||
|
winMap.mu.Unlock()
|
||||||
|
defer func() {
|
||||||
|
winMap.mu.Lock()
|
||||||
|
defer winMap.mu.Unlock()
|
||||||
|
delete(winMap.windows, w.hwnd)
|
||||||
|
if len(winMap.windows) == 0 {
|
||||||
|
select {
|
||||||
|
case mainDone <- struct{}{}:
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
w.w = window
|
w.w = window
|
||||||
w.w.SetDriver(w)
|
w.w.SetDriver(w)
|
||||||
defer w.w.Event(system.DestroyEvent{})
|
defer w.w.Event(system.DestroyEvent{})
|
||||||
@@ -88,22 +111,23 @@ func NewWindow(window Callbacks, opts *Options) error {
|
|||||||
if err := w.loop(); err != nil {
|
if err := w.loop(); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
close(mainDone)
|
|
||||||
}()
|
}()
|
||||||
return <-cerr
|
return <-cerr
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNativeWindow(opts *Options) (*window, error) {
|
// initResources initializes the resources global.
|
||||||
|
func initResources() error {
|
||||||
windows.SetProcessDPIAware()
|
windows.SetProcessDPIAware()
|
||||||
cfg := configForDC()
|
|
||||||
hInst, err := windows.GetModuleHandle()
|
hInst, err := windows.GetModuleHandle()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
resources.handle = hInst
|
||||||
curs, err := windows.LoadCursor(windows.IDC_ARROW)
|
curs, err := windows.LoadCursor(windows.IDC_ARROW)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
resources.cursor = curs
|
||||||
wcls := windows.WndClassEx{
|
wcls := windows.WndClassEx{
|
||||||
CbSize: uint32(unsafe.Sizeof(windows.WndClassEx{})),
|
CbSize: uint32(unsafe.Sizeof(windows.WndClassEx{})),
|
||||||
Style: windows.CS_HREDRAW | windows.CS_VREDRAW | windows.CS_OWNDC,
|
Style: windows.CS_HREDRAW | windows.CS_VREDRAW | windows.CS_OWNDC,
|
||||||
@@ -114,8 +138,21 @@ func createNativeWindow(opts *Options) (*window, error) {
|
|||||||
}
|
}
|
||||||
cls, err := windows.RegisterClassEx(&wcls)
|
cls, err := windows.RegisterClassEx(&wcls)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return err
|
||||||
}
|
}
|
||||||
|
resources.class = cls
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createNativeWindow(opts *Options) (*window, error) {
|
||||||
|
var resErr error
|
||||||
|
resources.once.Do(func() {
|
||||||
|
resErr = initResources()
|
||||||
|
})
|
||||||
|
if resErr != nil {
|
||||||
|
return nil, resErr
|
||||||
|
}
|
||||||
|
cfg := configForDC()
|
||||||
wr := windows.Rect{
|
wr := windows.Rect{
|
||||||
Right: int32(cfg.Px(opts.Width)),
|
Right: int32(cfg.Px(opts.Width)),
|
||||||
Bottom: int32(cfg.Px(opts.Height)),
|
Bottom: int32(cfg.Px(opts.Height)),
|
||||||
@@ -124,7 +161,7 @@ func createNativeWindow(opts *Options) (*window, error) {
|
|||||||
dwExStyle := uint32(windows.WS_EX_APPWINDOW | windows.WS_EX_WINDOWEDGE)
|
dwExStyle := uint32(windows.WS_EX_APPWINDOW | windows.WS_EX_WINDOWEDGE)
|
||||||
windows.AdjustWindowRectEx(&wr, dwStyle, 0, dwExStyle)
|
windows.AdjustWindowRectEx(&wr, dwStyle, 0, dwExStyle)
|
||||||
hwnd, err := windows.CreateWindowEx(dwExStyle,
|
hwnd, err := windows.CreateWindowEx(dwExStyle,
|
||||||
cls,
|
resources.class,
|
||||||
opts.Title,
|
opts.Title,
|
||||||
dwStyle|windows.WS_CLIPSIBLINGS|windows.WS_CLIPCHILDREN,
|
dwStyle|windows.WS_CLIPSIBLINGS|windows.WS_CLIPCHILDREN,
|
||||||
windows.CW_USEDEFAULT, windows.CW_USEDEFAULT,
|
windows.CW_USEDEFAULT, windows.CW_USEDEFAULT,
|
||||||
@@ -132,7 +169,7 @@ func createNativeWindow(opts *Options) (*window, error) {
|
|||||||
wr.Bottom-wr.Top,
|
wr.Bottom-wr.Top,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
hInst,
|
resources.handle,
|
||||||
0)
|
0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -148,7 +185,9 @@ func createNativeWindow(opts *Options) (*window, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr {
|
func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr {
|
||||||
w := winMap[hwnd]
|
winMap.mu.Lock()
|
||||||
|
w := winMap.windows[hwnd]
|
||||||
|
winMap.mu.Unlock()
|
||||||
switch msg {
|
switch msg {
|
||||||
case windows.WM_UNICHAR:
|
case windows.WM_UNICHAR:
|
||||||
if wParam == windows.UNICODE_NOCHAR {
|
if wParam == windows.UNICODE_NOCHAR {
|
||||||
|
|||||||
Reference in New Issue
Block a user