Add window opacity support
This commit is contained in:
parent
d0e8474785
commit
c9562e5e59
8 changed files with 104 additions and 13 deletions
|
|
@ -442,6 +442,29 @@ func (s *Subsystem) windowAlwaysOnTop(_ context.Context, _ *mcp.CallToolRequest,
|
|||
return nil, WindowAlwaysOnTopOutput{Success: true}, nil
|
||||
}
|
||||
|
||||
// --- window_opacity ---
|
||||
|
||||
type WindowOpacityInput struct {
|
||||
Name string `json:"name"`
|
||||
Opacity float64 `json:"opacity"`
|
||||
}
|
||||
type WindowOpacityOutput struct {
|
||||
Success bool `json:"success"`
|
||||
}
|
||||
|
||||
func (s *Subsystem) windowOpacity(_ context.Context, _ *mcp.CallToolRequest, input WindowOpacityInput) (*mcp.CallToolResult, WindowOpacityOutput, error) {
|
||||
r := s.core.Action("window.setOpacity").Run(context.Background(), core.NewOptions(
|
||||
core.Option{Key: "task", Value: window.TaskSetOpacity{Name: input.Name, Opacity: input.Opacity}},
|
||||
))
|
||||
if !r.OK {
|
||||
if e, ok := r.Value.(error); ok {
|
||||
return nil, WindowOpacityOutput{}, e
|
||||
}
|
||||
return nil, WindowOpacityOutput{}, nil
|
||||
}
|
||||
return nil, WindowOpacityOutput{Success: true}, nil
|
||||
}
|
||||
|
||||
// --- window_background_colour ---
|
||||
|
||||
type WindowBackgroundColourInput struct {
|
||||
|
|
@ -523,6 +546,10 @@ func (s *Subsystem) registerWindowTools(server *mcp.Server) {
|
|||
Description: `Show or hide a window. Example: {"name":"main","visible":false}`,
|
||||
}, s.windowVisibility)
|
||||
addTool(s, server, &mcp.Tool{Name: "window_always_on_top", Description: "Pin a window above others"}, s.windowAlwaysOnTop)
|
||||
addTool(s, server, &mcp.Tool{
|
||||
Name: "window_opacity",
|
||||
Description: `Set a window's opacity. Example: {"name":"main","opacity":0.85}`,
|
||||
}, s.windowOpacity)
|
||||
addTool(s, server, &mcp.Tool{Name: "window_background_colour", Description: "Set a window background colour"}, s.windowBackgroundColour)
|
||||
addTool(s, server, &mcp.Tool{Name: "window_fullscreen", Description: "Set a window to fullscreen mode"}, s.windowFullscreen)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
package window
|
||||
|
||||
type WindowInfo struct {
|
||||
Name string `json:"name"`
|
||||
Title string `json:"title"`
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Maximized bool `json:"maximized"`
|
||||
Focused bool `json:"focused"`
|
||||
Name string `json:"name"`
|
||||
Title string `json:"title"`
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Opacity float64 `json:"opacity"`
|
||||
Maximized bool `json:"maximized"`
|
||||
Focused bool `json:"focused"`
|
||||
}
|
||||
|
||||
type QueryWindowList struct{}
|
||||
|
|
@ -52,6 +53,11 @@ type TaskSetAlwaysOnTop struct {
|
|||
AlwaysOnTop bool
|
||||
}
|
||||
|
||||
type TaskSetOpacity struct {
|
||||
Name string
|
||||
Opacity float64
|
||||
}
|
||||
|
||||
type TaskSetBackgroundColour struct {
|
||||
Name string
|
||||
Red uint8
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ func (m *MockPlatform) CreateWindow(options PlatformWindowOptions) PlatformWindo
|
|||
name: options.Name, title: options.Title, url: options.URL, html: options.HTML,
|
||||
width: options.Width, height: options.Height,
|
||||
x: options.X, y: options.Y,
|
||||
opacity: 1.0,
|
||||
execJSCalls: nil,
|
||||
}
|
||||
if options.JS != "" {
|
||||
|
|
@ -42,6 +43,7 @@ type MockWindow struct {
|
|||
minimised bool
|
||||
fullscreened bool
|
||||
zoom float64
|
||||
opacity float64
|
||||
contentProtection bool
|
||||
flashed bool
|
||||
devToolsOpen bool
|
||||
|
|
@ -66,12 +68,14 @@ func (w *MockWindow) GetZoom() float64 {
|
|||
}
|
||||
return w.zoom
|
||||
}
|
||||
func (w *MockWindow) GetOpacity() float64 { return w.opacity }
|
||||
func (w *MockWindow) SetTitle(title string) { w.title = title }
|
||||
func (w *MockWindow) SetPosition(x, y int) { w.x = x; w.y = y }
|
||||
func (w *MockWindow) SetSize(width, height int) { w.width = width; w.height = height }
|
||||
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) SetOpacity(opacity float64) { w.opacity = opacity }
|
||||
func (w *MockWindow) SetBounds(x, y, width, height int) {
|
||||
w.x = x
|
||||
w.y = y
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ func (m *mockPlatform) CreateWindow(options PlatformWindowOptions) PlatformWindo
|
|||
name: options.Name, title: options.Title, url: options.URL, html: options.HTML,
|
||||
width: options.Width, height: options.Height,
|
||||
x: options.X, y: options.Y,
|
||||
opacity: 1.0,
|
||||
}
|
||||
if options.JS != "" {
|
||||
w.execJSCalls = append(w.execJSCalls, options.JS)
|
||||
|
|
@ -39,6 +40,7 @@ type mockWindow struct {
|
|||
minimised bool
|
||||
fullscreened bool
|
||||
zoom float64
|
||||
opacity float64
|
||||
contentProtection bool
|
||||
flashed bool
|
||||
devToolsOpen bool
|
||||
|
|
@ -63,12 +65,14 @@ func (w *mockWindow) GetZoom() float64 {
|
|||
}
|
||||
return w.zoom
|
||||
}
|
||||
func (w *mockWindow) GetOpacity() float64 { return w.opacity }
|
||||
func (w *mockWindow) SetTitle(title string) { w.title = title }
|
||||
func (w *mockWindow) SetPosition(x, y int) { w.x = x; w.y = y }
|
||||
func (w *mockWindow) SetSize(width, height int) { w.width = width; w.height = height }
|
||||
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) SetOpacity(opacity float64) { w.opacity = opacity }
|
||||
func (w *mockWindow) SetBounds(x, y, width, height int) {
|
||||
w.x = x
|
||||
w.y = y
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ type PlatformWindow interface {
|
|||
IsMinimised() bool
|
||||
GetBounds() (x, y, width, height int)
|
||||
GetZoom() float64
|
||||
GetOpacity() float64
|
||||
|
||||
// Mutations
|
||||
SetTitle(title string)
|
||||
|
|
@ -54,6 +55,7 @@ type PlatformWindow interface {
|
|||
SetURL(url string)
|
||||
SetHTML(html string)
|
||||
SetZoom(magnification float64)
|
||||
SetOpacity(opacity float64)
|
||||
SetContentProtection(protection bool)
|
||||
|
||||
// Window state
|
||||
|
|
|
|||
|
|
@ -86,6 +86,7 @@ func (s *Service) queryWindowList() []WindowInfo {
|
|||
w, h := pw.Size()
|
||||
result = append(result, WindowInfo{
|
||||
Name: name, Title: pw.Title(), X: x, Y: y, Width: w, Height: h,
|
||||
Opacity: pw.GetOpacity(),
|
||||
Maximized: pw.IsMaximised(),
|
||||
Focused: pw.IsFocused(),
|
||||
})
|
||||
|
|
@ -103,6 +104,7 @@ func (s *Service) queryWindowByName(name string) *WindowInfo {
|
|||
w, h := pw.Size()
|
||||
return &WindowInfo{
|
||||
Name: name, Title: pw.Title(), X: x, Y: y, Width: w, Height: h,
|
||||
Opacity: pw.GetOpacity(),
|
||||
Maximized: pw.IsMaximised(),
|
||||
Focused: pw.IsFocused(),
|
||||
}
|
||||
|
|
@ -153,6 +155,10 @@ func (s *Service) registerTaskActions() {
|
|||
t, _ := opts.Get("task").Value.(TaskSetAlwaysOnTop)
|
||||
return core.Result{Value: nil, OK: true}.New(s.taskSetAlwaysOnTop(t.Name, t.AlwaysOnTop))
|
||||
})
|
||||
c.Action("window.setOpacity", func(_ context.Context, opts core.Options) core.Result {
|
||||
t, _ := opts.Get("task").Value.(TaskSetOpacity)
|
||||
return core.Result{Value: nil, OK: true}.New(s.taskSetOpacity(t.Name, t.Opacity))
|
||||
})
|
||||
c.Action("window.setBackgroundColour", func(_ context.Context, opts core.Options) core.Result {
|
||||
t, _ := opts.Get("task").Value.(TaskSetBackgroundColour)
|
||||
return core.Result{Value: nil, OK: true}.New(s.taskSetBackgroundColour(t.Name, t.Red, t.Green, t.Blue, t.Alpha))
|
||||
|
|
@ -314,7 +320,7 @@ func (s *Service) taskOpenWindow(t TaskOpenWindow) core.Result {
|
|||
}
|
||||
x, y := pw.Position()
|
||||
w, h := pw.Size()
|
||||
info := WindowInfo{Name: pw.Name(), Title: pw.Title(), X: x, Y: y, Width: w, Height: h}
|
||||
info := WindowInfo{Name: pw.Name(), Title: pw.Title(), X: x, Y: y, Width: w, Height: h, Opacity: pw.GetOpacity()}
|
||||
|
||||
// Attach platform event listeners that convert to IPC actions
|
||||
s.trackWindow(pw)
|
||||
|
|
@ -446,6 +452,21 @@ func (s *Service) taskSetAlwaysOnTop(name string, alwaysOnTop bool) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) taskSetOpacity(name string, opacity float64) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
return coreerr.E("window.taskSetOpacity", "window not found: "+name, nil)
|
||||
}
|
||||
if opacity < 0 {
|
||||
opacity = 0
|
||||
}
|
||||
if opacity > 1 {
|
||||
opacity = 1
|
||||
}
|
||||
pw.SetOpacity(opacity)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) taskSetBackgroundColour(name string, red, green, blue, alpha uint8) error {
|
||||
pw, ok := s.manager.Get(name)
|
||||
if !ok {
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ func (wp *WailsPlatform) CreateWindow(options PlatformWindowOptions) PlatformWin
|
|||
BackgroundColour: application.NewRGBA(options.BackgroundColour[0], options.BackgroundColour[1], options.BackgroundColour[2], options.BackgroundColour[3]),
|
||||
}
|
||||
w := wp.app.Window.NewWithOptions(wOpts)
|
||||
return &wailsWindow{w: w, title: options.Title}
|
||||
return &wailsWindow{w: w, title: options.Title, opacity: 1.0}
|
||||
}
|
||||
|
||||
func (wp *WailsPlatform) GetWindows() []PlatformWindow {
|
||||
|
|
@ -54,10 +54,11 @@ func (wp *WailsPlatform) GetWindows() []PlatformWindow {
|
|||
}
|
||||
|
||||
// wailsWindow wraps *application.WebviewWindow to implement PlatformWindow.
|
||||
// It stores the title locally because Wails v3 does not expose a title getter.
|
||||
// It stores the title and opacity locally because Wails v3 does not expose getters for both.
|
||||
type wailsWindow struct {
|
||||
w *application.WebviewWindow
|
||||
title string
|
||||
w *application.WebviewWindow
|
||||
title string
|
||||
opacity float64
|
||||
}
|
||||
|
||||
func (ww *wailsWindow) Name() string { return ww.w.Name() }
|
||||
|
|
@ -74,6 +75,7 @@ func (ww *wailsWindow) GetBounds() (int, int, int, int) {
|
|||
return r.X, r.Y, r.Width, r.Height
|
||||
}
|
||||
func (ww *wailsWindow) GetZoom() float64 { return ww.w.GetZoom() }
|
||||
func (ww *wailsWindow) GetOpacity() float64 { return ww.opacity }
|
||||
func (ww *wailsWindow) SetTitle(title string) { ww.title = title; ww.w.SetTitle(title) }
|
||||
func (ww *wailsWindow) SetPosition(x, y int) { ww.w.SetPosition(x, y) }
|
||||
func (ww *wailsWindow) SetSize(width, height int) { ww.w.SetSize(width, height) }
|
||||
|
|
@ -88,6 +90,10 @@ func (ww *wailsWindow) SetVisibility(visible bool) {
|
|||
}
|
||||
}
|
||||
func (ww *wailsWindow) SetAlwaysOnTop(alwaysOnTop bool) { ww.w.SetAlwaysOnTop(alwaysOnTop) }
|
||||
func (ww *wailsWindow) SetOpacity(opacity float64) {
|
||||
ww.opacity = opacity
|
||||
ww.w.SetOpacity(opacity)
|
||||
}
|
||||
func (ww *wailsWindow) SetBounds(x, y, width, height int) {
|
||||
ww.w.SetBounds(application.Rect{X: x, Y: y, Width: width, Height: height})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ type WebviewWindow struct {
|
|||
focused bool
|
||||
visible bool
|
||||
alwaysOnTop bool
|
||||
opacity float64
|
||||
fullscreen bool
|
||||
closed bool
|
||||
execJSCalls []string
|
||||
|
|
@ -215,6 +216,7 @@ func newWebviewWindow(options WebviewWindowOptions) *WebviewWindow {
|
|||
height: options.Height,
|
||||
visible: !options.Hidden,
|
||||
alwaysOnTop: options.AlwaysOnTop,
|
||||
opacity: 1.0,
|
||||
eventHandlers: make(map[events.WindowEventType][]func(*WindowEvent)),
|
||||
}
|
||||
if options.JS != "" {
|
||||
|
|
@ -281,6 +283,16 @@ func (w *WebviewWindow) SetAlwaysOnTop(alwaysOnTop bool) Window {
|
|||
return w
|
||||
}
|
||||
|
||||
// SetOpacity sets the whole-window opacity.
|
||||
//
|
||||
// w.SetOpacity(0.85)
|
||||
func (w *WebviewWindow) SetOpacity(opacity float64) Window {
|
||||
w.mu.Lock()
|
||||
w.opacity = opacity
|
||||
w.mu.Unlock()
|
||||
return w
|
||||
}
|
||||
|
||||
func (w *WebviewWindow) Maximise() Window {
|
||||
w.mu.Lock()
|
||||
w.maximised = true
|
||||
|
|
@ -596,6 +608,15 @@ func (w *WebviewWindow) ZoomReset() Window { return w }
|
|||
// z := w.GetZoom()
|
||||
func (w *WebviewWindow) GetZoom() float64 { return 1.0 }
|
||||
|
||||
// GetOpacity returns the current window opacity.
|
||||
//
|
||||
// alpha := w.GetOpacity()
|
||||
func (w *WebviewWindow) GetOpacity() float64 {
|
||||
w.mu.RLock()
|
||||
defer w.mu.RUnlock()
|
||||
return w.opacity
|
||||
}
|
||||
|
||||
// SetZoom sets the zoom magnification factor.
|
||||
//
|
||||
// w.SetZoom(1.5)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue