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

@ -84,16 +84,17 @@ type userInterfaceImpl struct {
initFullscreenWidthInDIP int
initFullscreenHeightInDIP int
initFullscreen bool
initCursorMode CursorMode
initWindowDecorated bool
initWindowMonitor int
initWindowPositionXInDIP int
initWindowPositionYInDIP int
initWindowWidthInDIP int
initWindowHeightInDIP int
initWindowFloating bool
initWindowMaximized bool
initFullscreen bool
initCursorMode CursorMode
initWindowDecorated bool
initWindowMonitor int
initWindowPositionXInDIP int
initWindowPositionYInDIP int
initWindowWidthInDIP int
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()
}