ebiten: add SetWindowMousePassthrough and IsWindowMousePassthrough

Closes #2511
This commit is contained in:
Hajime Hoshi 2023-09-18 17:48:07 +09:00
parent c8d38f7f25
commit 14f2ee198e
6 changed files with 128 additions and 24 deletions

View File

@ -142,6 +142,7 @@ func main() {
ebiten.SetWindowDecorated(false)
ebiten.SetWindowFloating(true)
ebiten.SetWindowSize(width, height)
ebiten.SetWindowMousePassthrough(true)
op := &ebiten.RunGameOptions{}
op.ScreenTransparent = true

View File

@ -147,6 +147,7 @@ func (g *game) Update() error {
floating := ebiten.IsWindowFloating()
resizingMode := ebiten.WindowResizingMode()
screenCleared := ebiten.IsScreenClearedEveryFrame()
mousePassthrough := ebiten.IsWindowMousePassthrough()
const d = 16
toUpdateWindowSize := false
@ -267,6 +268,9 @@ func (g *game) Update() error {
restore = inpututil.IsKeyJustPressed(ebiten.KeyE)
}
}
if inpututil.IsKeyJustPressed(ebiten.KeyP) {
mousePassthrough = !mousePassthrough
}
if toUpdateWindowSize {
g.width = screenWidth
@ -304,6 +308,8 @@ func (g *game) Update() error {
ebiten.SetWindowIcon([]image.Image{createRandomIconImage()})
}
ebiten.SetWindowMousePassthrough(mousePassthrough)
g.count++
return nil
}
@ -357,6 +363,7 @@ func (g *game) Draw(screen *ebiten.Image) {
[D] Switch the window decoration (only for desktops)
[L] Switch the window floating state (only for desktops)
[W] Switch whether to skip clearing the screen
[P] Switch whether a mouse cursor passthroughs the window (only for desktops)
%s
IsFocused?: %s
Window Position: (%d, %d)

View File

@ -94,6 +94,7 @@ type userInterfaceImpl struct {
initWindowHeightInDIP int
initWindowFloating bool
initWindowMaximized bool
initWindowMousePassthrough bool
// bufferOnceSwapped must be accessed from the main thread.
bufferOnceSwapped bool
@ -525,6 +526,18 @@ func (u *userInterfaceImpl) setInitWindowMaximized(maximized bool) {
u.m.Unlock()
}
func (u *userInterfaceImpl) isInitWindowMousePassthrough() bool {
u.m.RLock()
defer u.m.RUnlock()
return u.initWindowMousePassthrough
}
func (u *userInterfaceImpl) setInitWindowMousePassthrough(enabled bool) {
u.m.Lock()
defer u.m.Unlock()
u.initWindowMousePassthrough = enabled
}
func (u *userInterfaceImpl) isWindowClosingHandled() bool {
u.m.RLock()
v := u.windowClosingHandled
@ -984,6 +997,12 @@ func (u *userInterfaceImpl) initOnMainThread(options *RunOptions) error {
}
glfw.WindowHint(glfw.FocusOnShow, focused)
mousePassthrough := glfw.False
if u.isInitWindowMousePassthrough() {
mousePassthrough = glfw.True
}
glfw.WindowHint(glfw.MousePassthrough, mousePassthrough)
// Set the window visible explicitly or the application freezes on Wayland (#974).
if os.Getenv("WAYLAND_DISPLAY") != "" {
glfw.WindowHint(glfw.Visible, glfw.True)
@ -1717,6 +1736,19 @@ func (u *userInterfaceImpl) setOrigWindowPos(x, y int) {
u.origWindowPosY = y
}
// setWindowMousePassthrough must be called from the main thread.
func (u *userInterfaceImpl) setWindowMousePassthrough(enabled bool) {
if microsoftgdk.IsXbox() {
return
}
v := glfw.False
if enabled {
v = glfw.True
}
u.window.SetAttrib(glfw.MousePassthrough, v)
}
func IsScreenTransparentAvailable() bool {
return true
}

View File

@ -41,6 +41,8 @@ type Window interface {
Restore()
SetClosingHandled(handled bool)
IsClosingHandled() bool
SetMousePassthrough(enabled bool)
IsMousePassthrough() bool
}
type nullWindow struct{}
@ -119,3 +121,10 @@ func (*nullWindow) SetClosingHandled(handled bool) {
func (*nullWindow) IsClosingHandled() bool {
return false
}
func (*nullWindow) SetMousePassthrough(enabled bool) {
}
func (*nullWindow) IsMousePassthrough() bool {
return false
}

View File

@ -387,3 +387,36 @@ func (w *glfwWindow) SetClosingHandled(handled bool) {
func (w *glfwWindow) IsClosingHandled() bool {
return w.ui.isWindowClosingHandled()
}
func (w *glfwWindow) SetMousePassthrough(enabled bool) {
if w.ui.isTerminated() {
return
}
if !w.ui.isRunning() {
w.ui.setInitWindowMousePassthrough(enabled)
return
}
w.ui.mainThread.Call(func() {
if w.ui.isTerminated() {
return
}
w.ui.setWindowMousePassthrough(enabled)
})
}
func (w *glfwWindow) IsMousePassthrough() bool {
if w.ui.isTerminated() {
return false
}
if !w.ui.isRunning() {
return w.ui.isInitWindowMousePassthrough()
}
var v bool
w.ui.mainThread.Call(func() {
if w.ui.isTerminated() {
return
}
v = w.ui.window.GetAttrib(glfw.MousePassthrough) == glfw.True
})
return v
}

View File

@ -54,7 +54,7 @@ func IsWindowDecorated() bool {
// The window is decorated by default.
//
// SetWindowDecorated works only on desktops.
// SetWindowDecorated does nothing on other platforms.
// SetWindowDecorated does nothing if the platform is not a desktop.
//
// SetWindowDecorated is concurrent-safe.
func SetWindowDecorated(decorated bool) {
@ -99,7 +99,7 @@ func SetWindowResizable(resizable bool) {
// SetWindowTitle sets the title of the window.
//
// SetWindowTitle does nothing on browsers or mobiles.
// SetWindowTitle does nothing if the platform is not a desktop.
//
// SetWindowTitle is concurrent-safe.
func SetWindowTitle(title string) {
@ -123,7 +123,7 @@ func SetWindowTitle(title string) {
//
// As macOS windows don't have icons, SetWindowIcon doesn't work on macOS.
//
// SetWindowIcon doesn't work on browsers or mobiles.
// SetWindowIcon doesn't work if the platform is not a desktop.
//
// SetWindowIcon is concurrent-safe.
func SetWindowIcon(iconImages []image.Image) {
@ -138,7 +138,7 @@ func SetWindowIcon(iconImages []image.Image) {
//
// WindowPosition returns the original window position in fullscreen mode.
//
// WindowPosition returns (0, 0) on browsers and mobiles.
// WindowPosition returns (0, 0) if the platform is not a desktop.
//
// WindowPosition is concurrent-safe.
func WindowPosition() (x, y int) {
@ -151,7 +151,7 @@ func WindowPosition() (x, y int) {
//
// SetWindowPosition sets the original window position in fullscreen mode.
//
// SetWindowPosition does nothing on browsers and mobiles.
// SetWindowPosition does nothing if the platform is not a desktop.
//
// SetWindowPosition is concurrent-safe.
func SetWindowPosition(x, y int) {
@ -215,7 +215,7 @@ func SetWindowSizeLimits(minw, minh, maxw, maxh int) {
// IsWindowFloating reports whether the window is always shown above all the other windows.
//
// IsWindowFloating returns false on browsers and mobiles.
// IsWindowFloating returns false if the platform is not a desktop.
//
// IsWindowFloating is concurrent-safe.
func IsWindowFloating() bool {
@ -224,7 +224,7 @@ func IsWindowFloating() bool {
// SetWindowFloating sets the state whether the window is always shown above all the other windows.
//
// SetWindowFloating does nothing on browsers or mobiles.
// SetWindowFloating does nothing if the platform is not a desktop.
//
// SetWindowFloating is concurrent-safe.
func SetWindowFloating(float bool) {
@ -235,7 +235,7 @@ func SetWindowFloating(float bool) {
//
// MaximizeWindow does nothing when the window is not resizable (WindowResizingModeEnabled).
//
// MaximizeWindow does nothing on browsers or mobiles.
// MaximizeWindow does nothing if the platform is not a desktop.
//
// MaximizeWindow is concurrent-safe.
func MaximizeWindow() {
@ -246,7 +246,7 @@ func MaximizeWindow() {
//
// IsWindowMaximized returns false when the window is not resizable (WindowResizingModeEnabled).
//
// IsWindowMaximized always returns false on browsers and mobiles.
// IsWindowMaximized always returns false if the platform is not a desktop.
//
// IsWindowMaximized is concurrent-safe.
func IsWindowMaximized() bool {
@ -257,7 +257,7 @@ func IsWindowMaximized() bool {
//
// If the main loop does not start yet, MinimizeWindow does nothing.
//
// MinimizeWindow does nothing on browsers or mobiles.
// MinimizeWindow does nothing if the platform is not a desktop.
//
// MinimizeWindow is concurrent-safe.
func MinimizeWindow() {
@ -266,7 +266,7 @@ func MinimizeWindow() {
// IsWindowMinimized reports whether the window is minimized or not.
//
// IsWindowMinimized always returns false on browsers and mobiles.
// IsWindowMinimized always returns false if the platform is not a desktop.
//
// IsWindowMinimized is concurrent-safe.
func IsWindowMinimized() bool {
@ -289,7 +289,7 @@ func RestoreWindow() {
// As the window is closed immediately by default,
// you might want to call SetWindowClosingHandled(true) to prevent the window is automatically closed.
//
// IsWindowBeingClosed always returns false on other platforms.
// IsWindowBeingClosed always returns false if the platform is not a desktop.
//
// IsWindowBeingClosed is concurrent-safe.
func IsWindowBeingClosed() bool {
@ -304,7 +304,7 @@ func IsWindowBeingClosed() bool {
// To end the game, you have to return an error value at the Game's Update function.
//
// SetWindowClosingHandled works only on desktops.
// SetWindowClosingHandled does nothing on other platforms.
// SetWindowClosingHandled does nothing if the platform is not a desktop.
//
// SetWindowClosingHandled is concurrent-safe.
func SetWindowClosingHandled(handled bool) {
@ -313,9 +313,31 @@ func SetWindowClosingHandled(handled bool) {
// IsWindowClosingHandled reports whether the window closing is handled or not on desktops by SetWindowClosingHandled.
//
// IsWindowClosingHandled always returns false on other platforms.
// IsWindowClosingHandled always returns false if the platform is not a desktop.
//
// IsWindowClosingHandled is concurrent-safe.
func IsWindowClosingHandled() bool {
return ui.Get().Window().IsClosingHandled()
}
// SetWindowMousePassthrough sets whether a mouse cursor passthroughs the window or not on desktops. The default state is false.
//
// Even if this is set true, some platforms might requrie a window to be undecorated
// in order to make the mouse cursor passthrough the window.
//
// SetWindowMousePassthrough works only on desktops.
// SetWindowMousePassthrough does nothing if the platform is not a desktop.
//
// SetWindowMousePassthrough is concurrent-safe.
func SetWindowMousePassthrough(enabled bool) {
ui.Get().Window().SetMousePassthrough(enabled)
}
// IsWindowMousePassthrough reports whether a mouse cursor passthroughs the window or not on desktops.
//
// IsWindowMousePassthrough alaywas returns false if the platform is not a desktop.
//
// IsWindowMousePassthrough is concurrent-safe.
func IsWindowMousePassthrough() bool {
return ui.Get().Window().IsMousePassthrough()
}