glfw_windows.go (12678B)
1 // Copyright 2018 The Ebiten Authors 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 "image" 19 "image/draw" 20 "math/bits" 21 "reflect" 22 "runtime" 23 "sync" 24 "unsafe" 25 26 "golang.org/x/sys/windows" 27 ) 28 29 type glfwImage struct { 30 width int32 31 height int32 32 pixels uintptr 33 } 34 35 type glfwWindows map[uintptr]*Window 36 37 var ( 38 theGLFWWindows = glfwWindows{} 39 glfwWindowsM sync.Mutex 40 ) 41 42 func (w glfwWindows) add(win uintptr) *Window { 43 if win == 0 { 44 return nil 45 } 46 ww := &Window{w: win} 47 glfwWindowsM.Lock() 48 w[win] = ww 49 glfwWindowsM.Unlock() 50 return ww 51 } 52 53 func (w glfwWindows) remove(win uintptr) { 54 glfwWindowsM.Lock() 55 delete(w, win) 56 glfwWindowsM.Unlock() 57 } 58 59 func (w glfwWindows) get(win uintptr) *Window { 60 if win == 0 { 61 return nil 62 } 63 glfwWindowsM.Lock() 64 ww := w[win] 65 glfwWindowsM.Unlock() 66 return ww 67 } 68 69 type Cursor struct { 70 c uintptr 71 } 72 73 func CreateStandardCursor(shape StandardCursor) *Cursor { 74 c := glfwDLL.call("glfwCreateStandardCursor", uintptr(shape)) 75 panicError() 76 return &Cursor{c: c} 77 } 78 79 type Monitor struct { 80 m uintptr 81 } 82 83 func (m *Monitor) GetContentScale() (float32, float32) { 84 var sx, sy float32 85 glfwDLL.call("glfwGetMonitorContentScale", m.m, uintptr(unsafe.Pointer(&sx)), uintptr(unsafe.Pointer(&sy))) 86 panicError() 87 return sx, sy 88 } 89 90 func (m *Monitor) GetPos() (int, int) { 91 var x, y int32 92 glfwDLL.call("glfwGetMonitorPos", m.m, uintptr(unsafe.Pointer(&x)), uintptr(unsafe.Pointer(&y))) 93 panicError() 94 return int(x), int(y) 95 } 96 97 func (m *Monitor) GetVideoMode() *VidMode { 98 v := glfwDLL.call("glfwGetVideoMode", m.m) 99 panicError() 100 var vals []int32 101 h := (*reflect.SliceHeader)(unsafe.Pointer(&vals)) 102 h.Data = v 103 h.Len = 6 104 h.Cap = 6 105 return &VidMode{ 106 Width: int(vals[0]), 107 Height: int(vals[1]), 108 RedBits: int(vals[2]), 109 GreenBits: int(vals[3]), 110 BlueBits: int(vals[4]), 111 RefreshRate: int(vals[5]), 112 } 113 } 114 115 type Window struct { 116 w uintptr 117 118 prevSizeCallback SizeCallback 119 } 120 121 func (w *Window) Destroy() { 122 glfwDLL.call("glfwDestroyWindow", w.w) 123 panicError() 124 theGLFWWindows.remove(w.w) 125 } 126 127 func (w *Window) GetAttrib(attrib Hint) int { 128 r := glfwDLL.call("glfwGetWindowAttrib", w.w, uintptr(attrib)) 129 panicError() 130 return int(r) 131 } 132 133 func (w *Window) SetAttrib(attrib Hint, value int) { 134 glfwDLL.call("glfwSetWindowAttrib", w.w, uintptr(attrib), uintptr(value)) 135 panicError() 136 } 137 138 func (w *Window) GetCursorPos() (x, y float64) { 139 glfwDLL.call("glfwGetCursorPos", w.w, uintptr(unsafe.Pointer(&x)), uintptr(unsafe.Pointer(&y))) 140 panicError() 141 return 142 } 143 144 func (w *Window) GetInputMode(mode InputMode) int { 145 r := glfwDLL.call("glfwGetInputMode", w.w, uintptr(mode)) 146 panicError() 147 return int(r) 148 } 149 150 func (w *Window) GetKey(key Key) Action { 151 r := glfwDLL.call("glfwGetKey", w.w, uintptr(key)) 152 panicError() 153 return Action(r) 154 } 155 156 func (w *Window) GetMonitor() *Monitor { 157 m := glfwDLL.call("glfwGetWindowMonitor", w.w) 158 panicError() 159 if m == 0 { 160 return nil 161 } 162 return &Monitor{m} 163 } 164 165 func (w *Window) GetMouseButton(button MouseButton) Action { 166 r := glfwDLL.call("glfwGetMouseButton", w.w, uintptr(button)) 167 panicError() 168 return Action(r) 169 } 170 171 func (w *Window) GetPos() (int, int) { 172 var x, y int32 173 glfwDLL.call("glfwGetWindowPos", w.w, uintptr(unsafe.Pointer(&x)), uintptr(unsafe.Pointer(&y))) 174 panicError() 175 return int(x), int(y) 176 } 177 178 func (w *Window) GetSize() (int, int) { 179 var width, height int32 180 glfwDLL.call("glfwGetWindowSize", w.w, uintptr(unsafe.Pointer(&width)), uintptr(unsafe.Pointer(&height))) 181 panicError() 182 return int(width), int(height) 183 } 184 185 func (w *Window) Hide() { 186 glfwDLL.call("glfwHideWindow", w.w) 187 panicError() 188 } 189 190 func (w *Window) Iconify() { 191 glfwDLL.call("glfwIconifyWindow", w.w) 192 panicError() 193 } 194 195 func (w *Window) MakeContextCurrent() { 196 glfwDLL.call("glfwMakeContextCurrent", w.w) 197 panicError() 198 } 199 200 func (w *Window) Maximize() { 201 glfwDLL.call("glfwMaximizeWindow", w.w) 202 panicError() 203 } 204 205 func (w *Window) Restore() { 206 glfwDLL.call("glfwRestoreWindow", w.w) 207 panicError() 208 } 209 210 func (w *Window) SetCharModsCallback(cbfun CharModsCallback) (previous CharModsCallback) { 211 glfwDLL.call("glfwSetCharModsCallback", w.w, uintptr(cbfun)) 212 panicError() 213 return ToCharModsCallback(nil) // TODO 214 } 215 216 func (w *Window) SetCloseCallback(cbfun CloseCallback) (previous CloseCallback) { 217 glfwDLL.call("glfwSetWindowCloseCallback", w.w, uintptr(cbfun)) 218 panicError() 219 return ToCloseCallback(nil) // TODO 220 } 221 222 func (w *Window) SetCursor(cursor *Cursor) { 223 var c uintptr 224 if cursor != nil { 225 c = cursor.c 226 } 227 glfwDLL.call("glfwSetCursor", w.w, c) 228 } 229 230 func (w *Window) SetFramebufferSizeCallback(cbfun FramebufferSizeCallback) (previous FramebufferSizeCallback) { 231 glfwDLL.call("glfwSetFramebufferSizeCallback", w.w, uintptr(cbfun)) 232 panicError() 233 return ToFramebufferSizeCallback(nil) // TODO 234 } 235 236 func (w *Window) SetScrollCallback(cbfun ScrollCallback) (previous ScrollCallback) { 237 glfwDLL.call("glfwSetScrollCallback", w.w, uintptr(cbfun)) 238 panicError() 239 return ToScrollCallback(nil) // TODO 240 } 241 242 func (w *Window) SetShouldClose(value bool) { 243 var v uintptr = False 244 if value { 245 v = True 246 } 247 glfwDLL.call("glfwSetWindowShouldClose", w.w, v) 248 panicError() 249 } 250 251 func (w *Window) SetSizeCallback(cbfun SizeCallback) (previous SizeCallback) { 252 glfwDLL.call("glfwSetWindowSizeCallback", w.w, uintptr(cbfun)) 253 panicError() 254 prev := w.prevSizeCallback 255 w.prevSizeCallback = cbfun 256 return prev 257 } 258 259 func (w *Window) SetSizeLimits(minw, minh, maxw, maxh int) { 260 glfwDLL.call("glfwSetWindowSizeLimits", w.w, uintptr(minw), uintptr(minh), uintptr(maxw), uintptr(maxh)) 261 panicError() 262 } 263 264 func (w *Window) SetIcon(images []image.Image) { 265 gimgs := make([]glfwImage, len(images)) 266 defer runtime.KeepAlive(gimgs) 267 268 for i, img := range images { 269 b := img.Bounds() 270 m := image.NewNRGBA(image.Rect(0, 0, b.Dx(), b.Dy())) 271 draw.Draw(m, m.Bounds(), img, b.Min, draw.Src) 272 gimgs[i].width = int32(b.Dx()) 273 gimgs[i].height = int32(b.Dy()) 274 gimgs[i].pixels = uintptr(unsafe.Pointer(&m.Pix[0])) 275 } 276 277 glfwDLL.call("glfwSetWindowIcon", w.w, uintptr(len(gimgs)), uintptr(unsafe.Pointer(&gimgs[0]))) 278 panicError() 279 } 280 281 func (w *Window) SetInputMode(mode InputMode, value int) { 282 glfwDLL.call("glfwSetInputMode", w.w, uintptr(mode), uintptr(value)) 283 panicError() 284 } 285 286 func (w *Window) SetMonitor(monitor *Monitor, xpos, ypos, width, height, refreshRate int) { 287 var m uintptr 288 if monitor != nil { 289 m = monitor.m 290 } 291 glfwDLL.call("glfwSetWindowMonitor", w.w, m, uintptr(xpos), uintptr(ypos), uintptr(width), uintptr(height), uintptr(refreshRate)) 292 panicError() 293 } 294 295 func (w *Window) SetPos(xpos, ypos int) { 296 glfwDLL.call("glfwSetWindowPos", w.w, uintptr(xpos), uintptr(ypos)) 297 panicError() 298 } 299 300 func (w *Window) SetSize(width, height int) { 301 glfwDLL.call("glfwSetWindowSize", w.w, uintptr(width), uintptr(height)) 302 panicError() 303 } 304 305 func (w *Window) SetTitle(title string) { 306 s := []byte(title) 307 s = append(s, 0) 308 defer runtime.KeepAlive(s) 309 glfwDLL.call("glfwSetWindowTitle", w.w, uintptr(unsafe.Pointer(&s[0]))) 310 panicError() 311 } 312 313 func (w *Window) ShouldClose() bool { 314 r := glfwDLL.call("glfwWindowShouldClose", w.w) 315 panicError() 316 return byte(r) == True 317 } 318 319 func (w *Window) Show() { 320 glfwDLL.call("glfwShowWindow", w.w) 321 panicError() 322 } 323 324 func (w *Window) SwapBuffers() { 325 glfwDLL.call("glfwSwapBuffers", w.w) 326 panicError() 327 } 328 329 func CreateWindow(width, height int, title string, monitor *Monitor, share *Window) (*Window, error) { 330 s := []byte(title) 331 s = append(s, 0) 332 defer runtime.KeepAlive(s) 333 334 var gm uintptr 335 if monitor != nil { 336 gm = monitor.m 337 } 338 var gw uintptr 339 if share != nil { 340 gw = share.w 341 } 342 343 w := glfwDLL.call("glfwCreateWindow", uintptr(width), uintptr(height), uintptr(unsafe.Pointer(&s[0])), gm, gw) 344 if w == 0 { 345 return nil, acceptError(APIUnavailable, VersionUnavailable) 346 } 347 return theGLFWWindows.add(w), nil 348 } 349 350 func (j Joystick) GetGUID() string { 351 ptr := glfwDLL.call("glfwGetJoystickGUID", uintptr(j)) 352 panicError() 353 354 // ptr can be nil after disconnecting the joystick. 355 if ptr == 0 { 356 return "" 357 } 358 359 var backed [256]byte 360 as := backed[:0] 361 for i := int32(0); ; i++ { 362 b := *(*byte)(unsafe.Pointer(ptr)) 363 ptr += unsafe.Sizeof(byte(0)) 364 if b == 0 { 365 break 366 } 367 as = append(as, b) 368 } 369 r := string(as) 370 return r 371 } 372 373 func (j Joystick) GetName() string { 374 ptr := glfwDLL.call("glfwGetJoystickName", uintptr(j)) 375 panicError() 376 377 // ptr can be nil after disconnecting the joystick. 378 if ptr == 0 { 379 return "" 380 } 381 382 var backed [256]byte 383 as := backed[:0] 384 for i := int32(0); ; i++ { 385 b := *(*byte)(unsafe.Pointer(ptr)) 386 ptr += unsafe.Sizeof(byte(0)) 387 if b == 0 { 388 break 389 } 390 as = append(as, b) 391 } 392 r := string(as) 393 return r 394 } 395 396 func (j Joystick) GetAxes() []float32 { 397 var l int32 398 ptr := glfwDLL.call("glfwGetJoystickAxes", uintptr(j), uintptr(unsafe.Pointer(&l))) 399 panicError() 400 401 // ptr can be nil after disconnecting the joystick. 402 if ptr == 0 { 403 return nil 404 } 405 406 as := make([]float32, l) 407 for i := int32(0); i < l; i++ { 408 as[i] = *(*float32)(unsafe.Pointer(ptr)) 409 ptr += unsafe.Sizeof(float32(0)) 410 } 411 return as 412 } 413 414 func (j Joystick) GetButtons() []byte { 415 var l int32 416 ptr := glfwDLL.call("glfwGetJoystickButtons", uintptr(j), uintptr(unsafe.Pointer(&l))) 417 panicError() 418 419 // ptr can be nil after disconnecting the joystick. 420 if ptr == 0 { 421 return nil 422 } 423 424 bs := make([]byte, l) 425 for i := int32(0); i < l; i++ { 426 bs[i] = *(*byte)(unsafe.Pointer(ptr)) 427 ptr++ 428 } 429 return bs 430 } 431 432 func (j Joystick) GetHats() []JoystickHatState { 433 var l int32 434 ptr := glfwDLL.call("glfwGetJoystickHats", uintptr(j), uintptr(unsafe.Pointer(&l))) 435 panicError() 436 437 // ptr can be nil after disconnecting the joystick. 438 if ptr == 0 { 439 return nil 440 } 441 442 hats := make([]JoystickHatState, l) 443 for i := int32(0); i < l; i++ { 444 hats[i] = *(*JoystickHatState)(unsafe.Pointer(ptr)) 445 ptr++ 446 } 447 return hats 448 } 449 450 func GetMonitors() []*Monitor { 451 var l int32 452 ptr := glfwDLL.call("glfwGetMonitors", uintptr(unsafe.Pointer(&l))) 453 panicError() 454 ms := make([]*Monitor, l) 455 for i := int32(0); i < l; i++ { 456 m := *(*unsafe.Pointer)(unsafe.Pointer(ptr)) 457 if m != nil { 458 ms[i] = &Monitor{uintptr(m)} 459 } 460 ptr += bits.UintSize / 8 461 } 462 return ms 463 } 464 465 func GetPrimaryMonitor() *Monitor { 466 m := glfwDLL.call("glfwGetPrimaryMonitor") 467 panicError() 468 if m == 0 { 469 return nil 470 } 471 return &Monitor{m} 472 } 473 474 func Init() error { 475 glfwDLL.call("glfwInit") 476 // InvalidValue can happen when specific joysticks are used. This issue 477 // will be fixed in GLFW 3.3.5. As a temporary fix, ignore this error. 478 // See go-gl/glfw#292, go-gl/glfw#324, and glfw/glfw#1763 479 // (#1229). 480 err := acceptError(APIUnavailable, InvalidValue) 481 if e, ok := err.(*glfwError); ok && e.code == InvalidValue { 482 return nil 483 } 484 return err 485 } 486 487 func (j Joystick) Present() bool { 488 r := glfwDLL.call("glfwJoystickPresent", uintptr(j)) 489 panicError() 490 return byte(r) == True 491 } 492 493 func panicErrorExceptForInvalidValue() { 494 // InvalidValue can happen when specific joysticks are used. This issue 495 // will be fixed in GLFW 3.3.5. As a temporary fix, ignore this error. 496 // See go-gl/glfw#292, go-gl/glfw#324, and glfw/glfw#1763 497 // (#1229). 498 err := acceptError(InvalidValue) 499 if e, ok := err.(*glfwError); ok && e.code == InvalidValue { 500 return 501 } 502 if err != nil { 503 panic(err) 504 } 505 } 506 507 func PollEvents() { 508 glfwDLL.call("glfwPollEvents") 509 // This should be used for WaitEvents and WaitEventsTimeout if needed. 510 panicErrorExceptForInvalidValue() 511 } 512 513 func PostEmptyEvent() { 514 glfwDLL.call("glfwPostEmptyEvent") 515 panicError() 516 } 517 518 func SetMonitorCallback(cbfun func(monitor *Monitor, event PeripheralEvent)) { 519 var gcb uintptr 520 if cbfun != nil { 521 gcb = windows.NewCallbackCDecl(func(monitor uintptr, event PeripheralEvent) uintptr { 522 var m *Monitor 523 if monitor != 0 { 524 m = &Monitor{monitor} 525 } 526 cbfun(m, event) 527 return 0 528 }) 529 } 530 glfwDLL.call("glfwSetMonitorCallback", gcb) 531 panicError() 532 } 533 534 func SwapInterval(interval int) { 535 glfwDLL.call("glfwSwapInterval", uintptr(interval)) 536 panicError() 537 } 538 539 func Terminate() { 540 flushErrors() 541 glfwDLL.call("glfwTerminate") 542 if err := glfwDLL.unload(); err != nil { 543 panic(err) 544 } 545 } 546 547 func WaitEvents() { 548 glfwDLL.call("glfwWaitEvents") 549 panicError() 550 } 551 552 func WindowHint(target Hint, hint int) { 553 glfwDLL.call("glfwWindowHint", uintptr(target), uintptr(hint)) 554 panicError() 555 }