refactor(ax): expose live window visibility state
Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
parent
53a4114224
commit
762806d316
11 changed files with 121 additions and 26 deletions
|
|
@ -46,23 +46,23 @@ Returns:
|
|||
|
||||
```go
|
||||
type WindowInfo struct {
|
||||
Name string
|
||||
Title string
|
||||
X int
|
||||
Y int
|
||||
Width int
|
||||
Height int
|
||||
IsVisible bool
|
||||
IsFocused bool
|
||||
IsMaximized bool
|
||||
IsMinimized bool
|
||||
Name string
|
||||
Title string
|
||||
X int
|
||||
Y int
|
||||
Width int
|
||||
Height int
|
||||
Visible bool
|
||||
Minimized bool
|
||||
Maximized bool
|
||||
Focused bool
|
||||
}
|
||||
```
|
||||
|
||||
### ListWindowInfos
|
||||
|
||||
```go
|
||||
func (s *Service) ListWindowInfos() []*WindowInfo
|
||||
func (s *Service) ListWindowInfos() []WindowInfo
|
||||
```
|
||||
|
||||
### Window Position & Size
|
||||
|
|
|
|||
|
|
@ -177,6 +177,8 @@ func TestOpenWindow_Defaults_Good(t *testing.T) {
|
|||
assert.Equal(t, "Core", info.Title)
|
||||
assert.Greater(t, info.Width, 0)
|
||||
assert.Greater(t, info.Height, 0)
|
||||
assert.True(t, info.Visible)
|
||||
assert.False(t, info.Minimized)
|
||||
}
|
||||
|
||||
func TestGetWindowInfo_Good(t *testing.T) {
|
||||
|
|
@ -279,6 +281,18 @@ func TestMaximizeWindow_Good(t *testing.T) {
|
|||
assert.True(t, info.Maximized)
|
||||
}
|
||||
|
||||
func TestMinimizeWindow_Good(t *testing.T) {
|
||||
c := newTestConclave(t)
|
||||
svc := core.MustServiceFor[*Service](c, "display")
|
||||
_ = svc.OpenWindow(window.Window{Name: "min-win"})
|
||||
|
||||
err := svc.MinimizeWindow("min-win")
|
||||
assert.NoError(t, err)
|
||||
|
||||
info, _ := svc.GetWindowInfo("min-win")
|
||||
assert.True(t, info.Minimized)
|
||||
}
|
||||
|
||||
func TestRestoreWindow_Good(t *testing.T) {
|
||||
c := newTestConclave(t)
|
||||
svc := core.MustServiceFor[*Service](c, "display")
|
||||
|
|
@ -325,8 +339,16 @@ func TestSetWindowVisibility_Good(t *testing.T) {
|
|||
err := svc.SetWindowVisibility("vis-win", false)
|
||||
assert.NoError(t, err)
|
||||
|
||||
info, err := svc.GetWindowInfo("vis-win")
|
||||
require.NoError(t, err)
|
||||
assert.False(t, info.Visible)
|
||||
|
||||
err = svc.SetWindowVisibility("vis-win", true)
|
||||
assert.NoError(t, err)
|
||||
|
||||
info, err = svc.GetWindowInfo("vis-win")
|
||||
require.NoError(t, err)
|
||||
assert.True(t, info.Visible)
|
||||
}
|
||||
|
||||
func TestSetWindowAlwaysOnTop_Good(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ The `Service` struct is the main entry point for the display logic.
|
|||
- **Window Management:**
|
||||
- `OpenWindow(spec window.Window) error`: Opens the default window using manager defaults.
|
||||
- `CreateWindow(spec window.Window) (*window.WindowInfo, error)`: Opens a named window and returns its info.
|
||||
- `GetWindowInfo(name string) (*window.WindowInfo, error)`: Queries a single window.
|
||||
- `ListWindowInfos() []window.WindowInfo`: Queries all tracked windows.
|
||||
- `GetWindowInfo(name string) (*window.WindowInfo, error)`: Queries a single window, including visibility, minimization, focus, and maximized state.
|
||||
- `ListWindowInfos() []window.WindowInfo`: Queries all tracked windows with the same live state fields.
|
||||
- `SetWindowBounds(name string, x, y, width, height int) error` - preferred when position and size change together.
|
||||
- `SetWindowPosition(name string, x, y int) error`
|
||||
- `SetWindowSize(name string, width, height int) error`
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ type WindowInfo struct {
|
|||
Y int `json:"y"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Visible bool `json:"visible"`
|
||||
Minimized bool `json:"minimized"`
|
||||
Maximized bool `json:"maximized"`
|
||||
Focused bool `json:"focused"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ func (m *MockPlatform) CreateWindow(options PlatformWindowOptions) PlatformWindo
|
|||
name: options.Name, title: options.Title, url: options.URL,
|
||||
width: options.Width, height: options.Height,
|
||||
x: options.X, y: options.Y,
|
||||
visible: !options.Hidden,
|
||||
}
|
||||
m.Windows = append(m.Windows, w)
|
||||
return w
|
||||
|
|
@ -31,7 +32,8 @@ func (m *MockPlatform) GetWindows() []PlatformWindow {
|
|||
type MockWindow struct {
|
||||
name, title, url string
|
||||
width, height, x, y int
|
||||
maximised, focused bool
|
||||
maximised, minimised bool
|
||||
focused bool
|
||||
visible, alwaysOnTop bool
|
||||
backgroundColour [4]uint8
|
||||
closed bool
|
||||
|
|
@ -44,6 +46,8 @@ func (w *MockWindow) Title() string { return w.title }
|
|||
func (w *MockWindow) Position() (int, int) { return w.x, w.y }
|
||||
func (w *MockWindow) Size() (int, int) { return w.width, w.height }
|
||||
func (w *MockWindow) IsMaximised() bool { return w.maximised }
|
||||
func (w *MockWindow) IsMinimised() bool { return w.minimised }
|
||||
func (w *MockWindow) IsVisible() bool { return w.visible }
|
||||
func (w *MockWindow) IsFocused() bool { return w.focused }
|
||||
func (w *MockWindow) SetTitle(title string) { w.title = title }
|
||||
func (w *MockWindow) SetBounds(x, y, width, height int) {
|
||||
|
|
@ -54,9 +58,9 @@ func (w *MockWindow) SetSize(width, height int) { w.width = width; w.
|
|||
func (w *MockWindow) SetBackgroundColour(r, g, b, a uint8) { w.backgroundColour = [4]uint8{r, g, b, a} }
|
||||
func (w *MockWindow) SetVisibility(visible bool) { w.visible = visible }
|
||||
func (w *MockWindow) SetAlwaysOnTop(alwaysOnTop bool) { w.alwaysOnTop = alwaysOnTop }
|
||||
func (w *MockWindow) Maximise() { w.maximised = true }
|
||||
func (w *MockWindow) Restore() { w.maximised = false }
|
||||
func (w *MockWindow) Minimise() {}
|
||||
func (w *MockWindow) Maximise() { w.maximised = true; w.minimised = false }
|
||||
func (w *MockWindow) Restore() { w.maximised = false; w.minimised = false }
|
||||
func (w *MockWindow) Minimise() { w.maximised = false; w.minimised = true }
|
||||
func (w *MockWindow) Focus() { w.focused = true }
|
||||
func (w *MockWindow) Close() {
|
||||
w.closed = true
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ func (m *mockPlatform) CreateWindow(options PlatformWindowOptions) PlatformWindo
|
|||
name: options.Name, title: options.Title, url: options.URL,
|
||||
width: options.Width, height: options.Height,
|
||||
x: options.X, y: options.Y,
|
||||
visible: !options.Hidden,
|
||||
}
|
||||
m.windows = append(m.windows, w)
|
||||
return w
|
||||
|
|
@ -29,11 +30,11 @@ func (m *mockPlatform) GetWindows() []PlatformWindow {
|
|||
type mockWindow struct {
|
||||
name, title, url string
|
||||
width, height, x, y int
|
||||
maximised, focused bool
|
||||
maximised, minimised bool
|
||||
focused bool
|
||||
visible, alwaysOnTop bool
|
||||
backgroundColour [4]uint8
|
||||
closed bool
|
||||
minimised bool
|
||||
fullscreened bool
|
||||
eventHandlers []func(WindowEvent)
|
||||
fileDropHandlers []func(paths []string, targetID string)
|
||||
|
|
@ -44,6 +45,8 @@ func (w *mockWindow) Title() string { return w.title }
|
|||
func (w *mockWindow) Position() (int, int) { return w.x, w.y }
|
||||
func (w *mockWindow) Size() (int, int) { return w.width, w.height }
|
||||
func (w *mockWindow) IsMaximised() bool { return w.maximised }
|
||||
func (w *mockWindow) IsMinimised() bool { return w.minimised }
|
||||
func (w *mockWindow) IsVisible() bool { return w.visible }
|
||||
func (w *mockWindow) IsFocused() bool { return w.focused }
|
||||
func (w *mockWindow) SetTitle(title string) { w.title = title }
|
||||
func (w *mockWindow) SetBounds(x, y, width, height int) {
|
||||
|
|
@ -54,9 +57,9 @@ func (w *mockWindow) SetSize(width, height int) { w.width = width; w.
|
|||
func (w *mockWindow) SetBackgroundColour(r, g, b, a uint8) { w.backgroundColour = [4]uint8{r, g, b, a} }
|
||||
func (w *mockWindow) SetVisibility(visible bool) { w.visible = visible }
|
||||
func (w *mockWindow) SetAlwaysOnTop(alwaysOnTop bool) { w.alwaysOnTop = alwaysOnTop }
|
||||
func (w *mockWindow) Maximise() { w.maximised = true }
|
||||
func (w *mockWindow) Restore() { w.maximised = false }
|
||||
func (w *mockWindow) Minimise() { w.minimised = true }
|
||||
func (w *mockWindow) Maximise() { w.maximised = true; w.minimised = false }
|
||||
func (w *mockWindow) Restore() { w.maximised = false; w.minimised = false }
|
||||
func (w *mockWindow) Minimise() { w.maximised = false; w.minimised = true }
|
||||
func (w *mockWindow) Focus() { w.focused = true }
|
||||
func (w *mockWindow) Close() {
|
||||
w.closed = true
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ type PlatformWindow interface {
|
|||
Position() (int, int)
|
||||
Size() (int, int)
|
||||
IsMaximised() bool
|
||||
IsMinimised() bool
|
||||
IsVisible() bool
|
||||
IsFocused() bool
|
||||
|
||||
// Mutations
|
||||
|
|
|
|||
|
|
@ -90,7 +90,14 @@ func (s *Service) queryWindowList() []WindowInfo {
|
|||
x, y := platformWindow.Position()
|
||||
width, height := platformWindow.Size()
|
||||
result = append(result, WindowInfo{
|
||||
Name: name, Title: platformWindow.Title(), X: x, Y: y, Width: width, Height: height,
|
||||
Name: name,
|
||||
Title: platformWindow.Title(),
|
||||
X: x,
|
||||
Y: y,
|
||||
Width: width,
|
||||
Height: height,
|
||||
Visible: platformWindow.IsVisible(),
|
||||
Minimized: platformWindow.IsMinimised(),
|
||||
Maximized: platformWindow.IsMaximised(),
|
||||
Focused: platformWindow.IsFocused(),
|
||||
})
|
||||
|
|
@ -107,7 +114,14 @@ func (s *Service) queryWindowByName(name string) *WindowInfo {
|
|||
x, y := platformWindow.Position()
|
||||
width, height := platformWindow.Size()
|
||||
return &WindowInfo{
|
||||
Name: name, Title: platformWindow.Title(), X: x, Y: y, Width: width, Height: height,
|
||||
Name: name,
|
||||
Title: platformWindow.Title(),
|
||||
X: x,
|
||||
Y: y,
|
||||
Width: width,
|
||||
Height: height,
|
||||
Visible: platformWindow.IsVisible(),
|
||||
Minimized: platformWindow.IsMinimised(),
|
||||
Maximized: platformWindow.IsMaximised(),
|
||||
Focused: platformWindow.IsFocused(),
|
||||
}
|
||||
|
|
@ -219,7 +233,18 @@ func (s *Service) taskOpenWindow(t TaskOpenWindow) (any, bool, error) {
|
|||
}
|
||||
x, y := platformWindow.Position()
|
||||
width, height := platformWindow.Size()
|
||||
info := WindowInfo{Name: platformWindow.Name(), Title: platformWindow.Title(), X: x, Y: y, Width: width, Height: height}
|
||||
info := WindowInfo{
|
||||
Name: platformWindow.Name(),
|
||||
Title: platformWindow.Title(),
|
||||
X: x,
|
||||
Y: y,
|
||||
Width: width,
|
||||
Height: height,
|
||||
Visible: platformWindow.IsVisible(),
|
||||
Minimized: platformWindow.IsMinimised(),
|
||||
Maximized: platformWindow.IsMaximised(),
|
||||
Focused: platformWindow.IsFocused(),
|
||||
}
|
||||
|
||||
// Attach platform event listeners that convert to IPC actions
|
||||
s.trackWindow(platformWindow)
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ func TestTaskOpenWindow_Good(t *testing.T) {
|
|||
assert.True(t, handled)
|
||||
info := result.(WindowInfo)
|
||||
assert.Equal(t, "test", info.Name)
|
||||
assert.True(t, info.Visible)
|
||||
assert.False(t, info.Minimized)
|
||||
}
|
||||
|
||||
func TestTaskOpenWindow_Declarative_Good(t *testing.T) {
|
||||
|
|
@ -322,6 +324,11 @@ func TestTaskMinimize_Good(t *testing.T) {
|
|||
require.True(t, ok)
|
||||
mw := pw.(*mockWindow)
|
||||
assert.True(t, mw.minimised)
|
||||
|
||||
result, _, err := c.QUERY(QueryWindowByName{Name: "test"})
|
||||
require.NoError(t, err)
|
||||
info := result.(*WindowInfo)
|
||||
assert.True(t, info.Minimized)
|
||||
}
|
||||
|
||||
func TestTaskMinimize_Bad(t *testing.T) {
|
||||
|
|
@ -470,11 +477,21 @@ func TestTaskSetVisibility_Good(t *testing.T) {
|
|||
mw := pw.(*mockWindow)
|
||||
assert.True(t, mw.visible)
|
||||
|
||||
result, _, err := c.QUERY(QueryWindowByName{Name: "test"})
|
||||
require.NoError(t, err)
|
||||
info := result.(*WindowInfo)
|
||||
assert.True(t, info.Visible)
|
||||
|
||||
// Now hide it
|
||||
_, handled, err = c.PERFORM(TaskSetVisibility{Name: "test", Visible: false})
|
||||
require.NoError(t, err)
|
||||
assert.True(t, handled)
|
||||
assert.False(t, mw.visible)
|
||||
|
||||
result, _, err = c.QUERY(QueryWindowByName{Name: "test"})
|
||||
require.NoError(t, err)
|
||||
info = result.(*WindowInfo)
|
||||
assert.False(t, info.Visible)
|
||||
}
|
||||
|
||||
func TestTaskSetVisibility_Bad(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,8 @@ func (windowHandle *wailsWindow) Title() string { return windowHandle.tit
|
|||
func (windowHandle *wailsWindow) Position() (int, int) { return windowHandle.w.Position() }
|
||||
func (windowHandle *wailsWindow) Size() (int, int) { return windowHandle.w.Size() }
|
||||
func (windowHandle *wailsWindow) IsMaximised() bool { return windowHandle.w.IsMaximised() }
|
||||
func (windowHandle *wailsWindow) IsMinimised() bool { return windowHandle.w.IsMinimised() }
|
||||
func (windowHandle *wailsWindow) IsVisible() bool { return windowHandle.w.IsVisible() }
|
||||
func (windowHandle *wailsWindow) IsFocused() bool { return windowHandle.w.IsFocused() }
|
||||
func (windowHandle *wailsWindow) SetTitle(title string) {
|
||||
windowHandle.title = title
|
||||
|
|
|
|||
|
|
@ -189,6 +189,7 @@ type WebviewWindow struct {
|
|||
x, y int
|
||||
width, height int
|
||||
maximised bool
|
||||
minimised bool
|
||||
focused bool
|
||||
visible bool
|
||||
alwaysOnTop bool
|
||||
|
|
@ -232,6 +233,16 @@ func (w *WebviewWindow) IsMaximised() bool {
|
|||
defer w.mu.RUnlock()
|
||||
return w.maximised
|
||||
}
|
||||
func (w *WebviewWindow) IsMinimised() bool {
|
||||
w.mu.RLock()
|
||||
defer w.mu.RUnlock()
|
||||
return w.minimised
|
||||
}
|
||||
func (w *WebviewWindow) IsVisible() bool {
|
||||
w.mu.RLock()
|
||||
defer w.mu.RUnlock()
|
||||
return w.visible
|
||||
}
|
||||
func (w *WebviewWindow) IsFocused() bool {
|
||||
w.mu.RLock()
|
||||
defer w.mu.RUnlock()
|
||||
|
|
@ -269,17 +280,24 @@ func (w *WebviewWindow) SetAlwaysOnTop(alwaysOnTop bool) {
|
|||
func (w *WebviewWindow) Maximise() {
|
||||
w.mu.Lock()
|
||||
w.maximised = true
|
||||
w.minimised = false
|
||||
w.mu.Unlock()
|
||||
}
|
||||
|
||||
func (w *WebviewWindow) Restore() {
|
||||
w.mu.Lock()
|
||||
w.maximised = false
|
||||
w.minimised = false
|
||||
w.fullscreen = false
|
||||
w.mu.Unlock()
|
||||
}
|
||||
|
||||
func (w *WebviewWindow) Minimise() {}
|
||||
func (w *WebviewWindow) Minimise() {
|
||||
w.mu.Lock()
|
||||
w.maximised = false
|
||||
w.minimised = true
|
||||
w.mu.Unlock()
|
||||
}
|
||||
|
||||
func (w *WebviewWindow) Focus() {
|
||||
w.mu.Lock()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue