twitchapon-anim

Basic Twitchapon Receiver/Visuals
git clone git://bsandro.tech/twitchapon-anim
Log | Files | Refs | README | LICENSE

ui_windows.go (4962B)


      1 // Copyright 2016 Hajime Hoshi
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package glfw
     16 
     17 import (
     18 	"fmt"
     19 	"unsafe"
     20 
     21 	"golang.org/x/sys/windows"
     22 
     23 	"github.com/hajimehoshi/ebiten/v2/internal/glfw"
     24 )
     25 
     26 const (
     27 	smCyCaption             = 4
     28 	monitorDefaultToNearest = 2
     29 )
     30 
     31 type rect struct {
     32 	left   int32
     33 	top    int32
     34 	right  int32
     35 	bottom int32
     36 }
     37 
     38 type monitorInfo struct {
     39 	cbSize    uint32
     40 	rcMonitor rect
     41 	rcWork    rect
     42 	dwFlags   uint32
     43 }
     44 
     45 var (
     46 	// user32 is defined at hideconsole_windows.go
     47 	procGetSystemMetrics    = user32.NewProc("GetSystemMetrics")
     48 	procGetActiveWindow     = user32.NewProc("GetActiveWindow")
     49 	procGetForegroundWindow = user32.NewProc("GetForegroundWindow")
     50 	procMonitorFromWindow   = user32.NewProc("MonitorFromWindow")
     51 	procGetMonitorInfoW     = user32.NewProc("GetMonitorInfoW")
     52 )
     53 
     54 func getSystemMetrics(nIndex int) (int, error) {
     55 	r, _, e := procGetSystemMetrics.Call(uintptr(nIndex))
     56 	if e != nil && e.(windows.Errno) != 0 {
     57 		return 0, fmt.Errorf("ui: GetSystemMetrics failed: error code: %d", e)
     58 	}
     59 	return int(r), nil
     60 }
     61 
     62 func getActiveWindow() (uintptr, error) {
     63 	r, _, e := procGetActiveWindow.Call()
     64 	if e != nil && e.(windows.Errno) != 0 {
     65 		return 0, fmt.Errorf("ui: GetActiveWindow failed: error code: %d", e)
     66 	}
     67 	return r, nil
     68 }
     69 
     70 func getForegroundWindow() (uintptr, error) {
     71 	r, _, e := procGetForegroundWindow.Call()
     72 	if e != nil && e.(windows.Errno) != 0 {
     73 		return 0, fmt.Errorf("ui: GetForegroundWindow failed: error code: %d", e)
     74 	}
     75 	return r, nil
     76 }
     77 
     78 func monitorFromWindow(hwnd uintptr, dwFlags uint32) (uintptr, error) {
     79 	r, _, e := procMonitorFromWindow.Call(hwnd, uintptr(dwFlags))
     80 	if e != nil && e.(windows.Errno) != 0 {
     81 		return 0, fmt.Errorf("ui: MonitorFromWindow failed: error code: %d", e)
     82 	}
     83 	if r == 0 {
     84 		return 0, fmt.Errorf("ui: MonitorFromWindow failed: returned value: %d", r)
     85 	}
     86 	return r, nil
     87 }
     88 
     89 func getMonitorInfoW(hMonitor uintptr, lpmi *monitorInfo) error {
     90 	r, _, e := procGetMonitorInfoW.Call(hMonitor, uintptr(unsafe.Pointer(lpmi)))
     91 	if e != nil && e.(windows.Errno) != 0 {
     92 		return fmt.Errorf("ui: GetMonitorInfoW failed: error code: %d", e)
     93 	}
     94 	if r == 0 {
     95 		return fmt.Errorf("ui: GetMonitorInfoW failed: returned value: %d", r)
     96 	}
     97 	return nil
     98 }
     99 
    100 // fromGLFWMonitorPixel must be called from the main thread.
    101 func (u *UserInterface) fromGLFWMonitorPixel(x float64) float64 {
    102 	return x / u.deviceScaleFactor()
    103 }
    104 
    105 // fromGLFWPixel must be called from the main thread.
    106 func (u *UserInterface) fromGLFWPixel(x float64) float64 {
    107 	return x / u.deviceScaleFactor()
    108 }
    109 
    110 // toGLFWPixel must be called from the main thread.
    111 func (u *UserInterface) toGLFWPixel(x float64) float64 {
    112 	return x * u.deviceScaleFactor()
    113 }
    114 
    115 // toFramebufferPixel must be called from the main thread.
    116 func (u *UserInterface) toFramebufferPixel(x float64) float64 {
    117 	return x
    118 }
    119 
    120 func (u *UserInterface) adjustWindowPosition(x, y int) (int, int) {
    121 	mx, my := currentMonitor(u.window).GetPos()
    122 	// As the video width/height might be wrong,
    123 	// adjust x/y at least to enable to handle the window (#328)
    124 	if x < mx {
    125 		x = mx
    126 	}
    127 	t, err := getSystemMetrics(smCyCaption)
    128 	if err != nil {
    129 		panic(err)
    130 	}
    131 	if y < my+t {
    132 		y = my + t
    133 	}
    134 	return x, y
    135 }
    136 
    137 func currentMonitorByOS(_ *glfw.Window) *glfw.Monitor {
    138 	// TODO: Should we return nil here?
    139 	w, err := getActiveWindow()
    140 	if err != nil {
    141 		panic(err)
    142 	}
    143 
    144 	if w == 0 {
    145 		// The active window doesn't exist when launching, or the application is runnable on unfocused.
    146 		// Get the foreground window, that is common among multiple processes.
    147 		w, err = getForegroundWindow()
    148 		if err != nil {
    149 			panic(err)
    150 		}
    151 		if w == 0 {
    152 			// GetForegroundWindow can return null according to the document.
    153 			return nil
    154 		}
    155 	}
    156 
    157 	// Get the current monitor by the window handle instead of the window position. It is because the window
    158 	// position is not relaiable in some cases e.g. when the window is put across multiple monitors.
    159 
    160 	m, err := monitorFromWindow(w, monitorDefaultToNearest)
    161 	if err != nil {
    162 		// monitorFromWindow can return error on Wine. Ignore this.
    163 		return nil
    164 	}
    165 
    166 	mi := monitorInfo{}
    167 	mi.cbSize = uint32(unsafe.Sizeof(mi))
    168 	if err := getMonitorInfoW(m, &mi); err != nil {
    169 		panic(err)
    170 	}
    171 
    172 	x, y := int(mi.rcMonitor.left), int(mi.rcMonitor.top)
    173 	for _, m := range glfw.GetMonitors() {
    174 		mx, my := m.GetPos()
    175 		if mx == x && my == y {
    176 			return m
    177 		}
    178 	}
    179 	return nil
    180 }
    181 
    182 func (u *UserInterface) nativeWindow() uintptr {
    183 	return u.window.GetWin32Window()
    184 }