mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-25 19:28:57 +01:00
parent
1dd7c1cce3
commit
0bec1e65fa
@ -145,6 +145,7 @@ func main() {
|
|||||||
|
|
||||||
op := &ebiten.RunGameOptions{}
|
op := &ebiten.RunGameOptions{}
|
||||||
op.ScreenTransparent = true
|
op.ScreenTransparent = true
|
||||||
|
op.SkipTaskbar = true
|
||||||
if err := ebiten.RunGameWithOptions(&mascot{}, op); err != nil {
|
if err := ebiten.RunGameWithOptions(&mascot{}, op); err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
@ -17,15 +17,37 @@
|
|||||||
package ui
|
package ui
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"runtime"
|
||||||
|
"syscall"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"golang.org/x/sys/windows"
|
"golang.org/x/sys/windows"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
_SM_CYCAPTION = 4
|
_CLSCTX_INPROC_SERVER = 0x1
|
||||||
|
_CLSCTX_LOCAL_SERVER = 0x4
|
||||||
|
_CLSCTX_REMOTE_SERVER = 0x10
|
||||||
|
_CLSCTX_SERVER = _CLSCTX_INPROC_SERVER | _CLSCTX_LOCAL_SERVER | _CLSCTX_REMOTE_SERVER
|
||||||
_MONITOR_DEFAULTTONEAREST = 2
|
_MONITOR_DEFAULTTONEAREST = 2
|
||||||
|
_SM_CYCAPTION = 4
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
_CLSID_TaskbarList = windows.GUID{
|
||||||
|
Data1: 0x56FDF344,
|
||||||
|
Data2: 0xFD6D,
|
||||||
|
Data3: 0x11D0,
|
||||||
|
Data4: [...]byte{0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90},
|
||||||
|
}
|
||||||
|
_IID_ITaskbarList = windows.GUID{
|
||||||
|
Data1: 0x56FDF342,
|
||||||
|
Data2: 0xFD6D,
|
||||||
|
Data3: 0x11D0,
|
||||||
|
Data4: [...]byte{0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
type _RECT struct {
|
type _RECT struct {
|
||||||
@ -48,14 +70,28 @@ type _POINT struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
ole32 = windows.NewLazySystemDLL("ole32.dll")
|
||||||
user32 = windows.NewLazySystemDLL("user32.dll")
|
user32 = windows.NewLazySystemDLL("user32.dll")
|
||||||
|
|
||||||
|
procCoCreateInstance = ole32.NewProc("CoCreateInstance")
|
||||||
|
|
||||||
procGetSystemMetrics = user32.NewProc("GetSystemMetrics")
|
procGetSystemMetrics = user32.NewProc("GetSystemMetrics")
|
||||||
procMonitorFromWindow = user32.NewProc("MonitorFromWindow")
|
procMonitorFromWindow = user32.NewProc("MonitorFromWindow")
|
||||||
procGetMonitorInfoW = user32.NewProc("GetMonitorInfoW")
|
procGetMonitorInfoW = user32.NewProc("GetMonitorInfoW")
|
||||||
procGetCursorPos = user32.NewProc("GetCursorPos")
|
procGetCursorPos = user32.NewProc("GetCursorPos")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func _CoCreateInstance(rclsid *windows.GUID, pUnkOuter unsafe.Pointer, dwClsContext uint32, riid *windows.GUID) (unsafe.Pointer, error) {
|
||||||
|
var ptr unsafe.Pointer
|
||||||
|
r, _, _ := procCoCreateInstance.Call(uintptr(unsafe.Pointer(rclsid)), uintptr(pUnkOuter), uintptr(dwClsContext), uintptr(unsafe.Pointer(riid)), uintptr(unsafe.Pointer(&ptr)))
|
||||||
|
runtime.KeepAlive(rclsid)
|
||||||
|
runtime.KeepAlive(riid)
|
||||||
|
if uint32(r) != uint32(windows.S_OK) {
|
||||||
|
return nil, fmt.Errorf("ui: CoCreateInstance failed: error code: HRESULT(%d)", uint32(r))
|
||||||
|
}
|
||||||
|
return ptr, nil
|
||||||
|
}
|
||||||
|
|
||||||
func _GetSystemMetrics(nIndex int) (int32, error) {
|
func _GetSystemMetrics(nIndex int) (int32, error) {
|
||||||
r, _, _ := procGetSystemMetrics.Call(uintptr(nIndex))
|
r, _, _ := procGetSystemMetrics.Call(uintptr(nIndex))
|
||||||
if int32(r) == 0 {
|
if int32(r) == 0 {
|
||||||
@ -77,7 +113,7 @@ func _GetMonitorInfoW(hMonitor uintptr) (_MONITORINFO, error) {
|
|||||||
|
|
||||||
r, _, e := procGetMonitorInfoW.Call(hMonitor, uintptr(unsafe.Pointer(&mi)))
|
r, _, e := procGetMonitorInfoW.Call(hMonitor, uintptr(unsafe.Pointer(&mi)))
|
||||||
if int32(r) == 0 {
|
if int32(r) == 0 {
|
||||||
if e != nil && e != windows.ERROR_SUCCESS {
|
if e != nil && !errors.Is(e, windows.ERROR_SUCCESS) {
|
||||||
return _MONITORINFO{}, fmt.Errorf("ui: GetMonitorInfoW failed: error code: %w", e)
|
return _MONITORINFO{}, fmt.Errorf("ui: GetMonitorInfoW failed: error code: %w", e)
|
||||||
}
|
}
|
||||||
return _MONITORINFO{}, fmt.Errorf("ui: GetMonitorInfoW failed: returned 0")
|
return _MONITORINFO{}, fmt.Errorf("ui: GetMonitorInfoW failed: returned 0")
|
||||||
@ -89,10 +125,38 @@ func _GetCursorPos() (int32, int32, error) {
|
|||||||
var pt _POINT
|
var pt _POINT
|
||||||
r, _, e := procGetCursorPos.Call(uintptr(unsafe.Pointer(&pt)))
|
r, _, e := procGetCursorPos.Call(uintptr(unsafe.Pointer(&pt)))
|
||||||
if int32(r) == 0 {
|
if int32(r) == 0 {
|
||||||
if e != nil && e != windows.ERROR_SUCCESS {
|
if e != nil && !errors.Is(e, windows.ERROR_SUCCESS) {
|
||||||
return 0, 0, fmt.Errorf("ui: GetCursorPos failed: error code: %w", e)
|
return 0, 0, fmt.Errorf("ui: GetCursorPos failed: error code: %w", e)
|
||||||
}
|
}
|
||||||
return 0, 0, fmt.Errorf("ui: GetCursorPos failed: returned 0")
|
return 0, 0, fmt.Errorf("ui: GetCursorPos failed: returned 0")
|
||||||
}
|
}
|
||||||
return pt.x, pt.y, nil
|
return pt.x, pt.y, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type _ITaskbarList struct {
|
||||||
|
vtbl *_ITaskbarList_Vtbl
|
||||||
|
}
|
||||||
|
|
||||||
|
type _ITaskbarList_Vtbl struct {
|
||||||
|
QueryInterface uintptr
|
||||||
|
AddRef uintptr
|
||||||
|
Release uintptr
|
||||||
|
|
||||||
|
HrInit uintptr
|
||||||
|
AddTab uintptr
|
||||||
|
DeleteTab uintptr
|
||||||
|
ActivateTab uintptr
|
||||||
|
SetActiveAlt uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *_ITaskbarList) DeleteTab(hwnd windows.HWND) error {
|
||||||
|
r, _, _ := syscall.Syscall(i.vtbl.DeleteTab, 2, uintptr(unsafe.Pointer(i)), uintptr(hwnd), 0)
|
||||||
|
if uint32(r) != uint32(windows.S_OK) {
|
||||||
|
return fmt.Errorf("ui: ITaskbarList::DeleteTab failed: HRESULT(%d)", uint32(r))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *_ITaskbarList) Release() {
|
||||||
|
syscall.Syscall(i.vtbl.Release, 1, uintptr(unsafe.Pointer(i)), 0, 0)
|
||||||
|
}
|
||||||
|
@ -100,4 +100,5 @@ type RunOptions struct {
|
|||||||
GraphicsLibrary GraphicsLibrary
|
GraphicsLibrary GraphicsLibrary
|
||||||
InitUnfocused bool
|
InitUnfocused bool
|
||||||
ScreenTransparent bool
|
ScreenTransparent bool
|
||||||
|
SkipTaskbar bool
|
||||||
}
|
}
|
||||||
|
@ -940,6 +940,11 @@ func (u *userInterfaceImpl) init(options *RunOptions) error {
|
|||||||
|
|
||||||
u.setWindowResizingModeForOS(u.windowResizingMode)
|
u.setWindowResizingModeForOS(u.windowResizingMode)
|
||||||
|
|
||||||
|
if options.SkipTaskbar {
|
||||||
|
// Ignore the error.
|
||||||
|
_ = u.skipTaskbar()
|
||||||
|
}
|
||||||
|
|
||||||
u.window.Show()
|
u.window.Show()
|
||||||
|
|
||||||
if g, ok := u.graphicsDriver.(interface{ SetWindow(uintptr) }); ok {
|
if g, ok := u.graphicsDriver.(interface{ SetWindow(uintptr) }); ok {
|
||||||
|
@ -385,3 +385,7 @@ func initializeWindowAfterCreation(w *glfw.Window) {
|
|||||||
delegate := objc.ID(class_EbitengineWindowDelegate).Send(objc.RegisterName("alloc")).Send(objc.RegisterName("initWithOrigDelegate:"), nswindow.Send(sel_delegate))
|
delegate := objc.ID(class_EbitengineWindowDelegate).Send(objc.RegisterName("alloc")).Send(objc.RegisterName("initWithOrigDelegate:"), nswindow.Send(sel_delegate))
|
||||||
nswindow.Send(objc.RegisterName("setDelegate:"), delegate)
|
nswindow.Send(objc.RegisterName("setDelegate:"), delegate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *userInterfaceImpl) skipTaskbar() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -229,3 +229,7 @@ func initializeWindowAfterCreation(w *glfw.Window) {
|
|||||||
// Apparently the window state is inconsistent just after the window is created, but we are not sure.
|
// Apparently the window state is inconsistent just after the window is created, but we are not sure.
|
||||||
// For more details, see the discussion in #1829.
|
// For more details, see the discussion in #1829.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *userInterfaceImpl) skipTaskbar() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -185,3 +185,24 @@ func (u *userInterfaceImpl) setWindowResizingModeForOS(mode WindowResizingMode)
|
|||||||
|
|
||||||
func initializeWindowAfterCreation(w *glfw.Window) {
|
func initializeWindowAfterCreation(w *glfw.Window) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (u *userInterfaceImpl) skipTaskbar() error {
|
||||||
|
if err := windows.CoInitializeEx(0, windows.COINIT_MULTITHREADED); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer windows.CoUninitialize()
|
||||||
|
|
||||||
|
ptr, err := _CoCreateInstance(&_CLSID_TaskbarList, nil, _CLSCTX_SERVER, &_IID_ITaskbarList)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
t := (*_ITaskbarList)(ptr)
|
||||||
|
defer t.Release()
|
||||||
|
|
||||||
|
if err := t.DeleteTab(windows.HWND(u.window.GetWin32Window())); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
11
run.go
11
run.go
@ -236,17 +236,23 @@ type RunGameOptions struct {
|
|||||||
// The default (zero) value is GraphicsLibraryAuto, which lets Ebitengine choose the graphics library.
|
// The default (zero) value is GraphicsLibraryAuto, which lets Ebitengine choose the graphics library.
|
||||||
GraphicsLibrary GraphicsLibrary
|
GraphicsLibrary GraphicsLibrary
|
||||||
|
|
||||||
// InitUnfocused represents whether the window is unfocused or not on launching.
|
// InitUnfocused indicates whether the window is unfocused or not on launching.
|
||||||
// InitUnfocused is valid on desktops and browsers.
|
// InitUnfocused is valid on desktops and browsers.
|
||||||
//
|
//
|
||||||
// The default (zero) value is false, which means that the window is focused.
|
// The default (zero) value is false, which means that the window is focused.
|
||||||
InitUnfocused bool
|
InitUnfocused bool
|
||||||
|
|
||||||
// ScreenTransparent represents whether the window is transparent or not.
|
// ScreenTransparent indicates whether the window is transparent or not.
|
||||||
// ScreenTransparent is valid on desktops and browsers.
|
// ScreenTransparent is valid on desktops and browsers.
|
||||||
//
|
//
|
||||||
// The default (zero) value is false, which means that the window is not transparent.
|
// The default (zero) value is false, which means that the window is not transparent.
|
||||||
ScreenTransparent bool
|
ScreenTransparent bool
|
||||||
|
|
||||||
|
// SkipTaskbar indicates whether an application icon is shown on a taskbar or not.
|
||||||
|
// SkipTaskbar is valid only on Windows.
|
||||||
|
//
|
||||||
|
// The default (zero) value is false, which means that an icon is shown on a taskbar.
|
||||||
|
SkipTaskbar bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunGameWithOptions starts the main loop and runs the game with the specified options.
|
// RunGameWithOptions starts the main loop and runs the game with the specified options.
|
||||||
@ -656,5 +662,6 @@ func toUIRunOptions(options *RunGameOptions) *ui.RunOptions {
|
|||||||
GraphicsLibrary: ui.GraphicsLibrary(options.GraphicsLibrary),
|
GraphicsLibrary: ui.GraphicsLibrary(options.GraphicsLibrary),
|
||||||
InitUnfocused: options.InitUnfocused,
|
InitUnfocused: options.InitUnfocused,
|
||||||
ScreenTransparent: options.ScreenTransparent,
|
ScreenTransparent: options.ScreenTransparent,
|
||||||
|
SkipTaskbar: options.SkipTaskbar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user