github.com/rajveermalviya/gamen@v0.1.2-0.20220930195403-9be15877c1aa/internal/wayland/pointer.go (about) 1 //go:build linux && !android 2 3 package wayland 4 5 /* 6 7 #include <stdlib.h> 8 #include "wayland-util.h" 9 #include "wayland-cursor.h" 10 11 */ 12 import "C" 13 14 import ( 15 "runtime/cgo" 16 "sync" 17 "time" 18 "unsafe" 19 20 "github.com/rajveermalviya/gamen/events" 21 ) 22 23 type Pointer struct { 24 d *Display 25 mu sync.Mutex 26 27 pointer *C.struct_wl_pointer 28 29 serial uint32 30 focus *C.struct_wl_surface 31 32 pixelDeltaVertical float64 33 pixelDeltaHorizontal float64 34 35 lineDeltaVertical float64 36 lineDeltaHorizontal float64 37 38 currentCursor *C.struct_wl_cursor 39 currentCursorAnimationStartTime time.Time 40 cursorThemes map[uint32]*C.struct_wl_cursor_theme 41 cursorSurface *C.struct_wl_surface 42 cursorSurfaceFrameCallback *C.struct_wl_callback 43 } 44 45 func (p *Pointer) destroy() { 46 if p.currentCursor != nil { 47 p.currentCursor = nil 48 } 49 50 if p.cursorSurfaceFrameCallback != nil { 51 p.d.l.wl_callback_destroy(p.cursorSurfaceFrameCallback) 52 p.cursorSurfaceFrameCallback = nil 53 } 54 55 if p.cursorSurface != nil { 56 p.d.l.wl_surface_destroy(p.cursorSurface) 57 p.cursorSurface = nil 58 } 59 60 if p.cursorThemes != nil { 61 for _, theme := range p.cursorThemes { 62 p.d.l.wl_cursor_theme_destroy(theme) 63 } 64 p.cursorThemes = nil 65 } 66 67 if p.pointer != nil { 68 p.d.l.wl_pointer_destroy(p.pointer) 69 p.pointer = nil 70 } 71 } 72 73 func (p *Pointer) loadCursor(name string, size uint32, scaleFactor float64) *C.struct_wl_cursor { 74 p.mu.Lock() 75 defer p.mu.Unlock() 76 77 size = size * uint32(scaleFactor) 78 79 theme, ok := p.cursorThemes[size] 80 if !ok { 81 theme = p.d.l.wl_cursor_theme_load(nil, C.int(size), p.d.shm) 82 p.cursorThemes[size] = theme 83 } 84 85 nameStr := C.CString(name) 86 defer C.free(unsafe.Pointer(nameStr)) 87 88 cursor := p.d.l.wl_cursor_theme_get_cursor(theme, nameStr) 89 if cursor == nil { 90 return nil 91 } 92 if cursor.image_count == 0 { 93 return nil 94 } 95 96 return cursor 97 } 98 99 func (p *Pointer) setCursor(cursor *C.struct_wl_cursor, name string, scaleFactor float64) { 100 p.mu.Lock() 101 defer p.mu.Unlock() 102 103 // hide cursor 104 if cursor == nil { 105 p.d.l.wl_pointer_set_cursor(p.pointer, C.uint32_t(p.serial), nil, 0, 0) 106 p.currentCursor = nil 107 return 108 } 109 110 if p.cursorSurfaceFrameCallback != nil { 111 p.d.l.wl_callback_destroy(p.cursorSurfaceFrameCallback) 112 p.cursorSurfaceFrameCallback = nil 113 } 114 115 imageSlice := unsafe.Slice(cursor.images, cursor.image_count) 116 image := imageSlice[0] 117 cursorBuffer := p.d.l.wl_cursor_image_get_buffer(image) 118 119 if p.cursorSurface == nil { 120 p.cursorSurface = p.d.l.wl_compositor_create_surface(p.d.compositor) 121 } 122 123 p.d.l.wl_surface_set_buffer_scale(p.cursorSurface, C.int32_t(scaleFactor)) 124 p.d.l.wl_surface_attach(p.cursorSurface, cursorBuffer, 0, 0) 125 p.d.l.wl_surface_damage_buffer(p.cursorSurface, 0, 0, C.int32_t(image.width), C.int32_t(image.height)) 126 p.d.l.wl_surface_commit(p.cursorSurface) 127 128 p.d.l.wl_pointer_set_cursor( 129 p.pointer, 130 C.uint32_t(p.serial), 131 p.cursorSurface, 132 C.int32_t(float64(image.hotspot_x)/scaleFactor), 133 C.int32_t(float64(image.hotspot_y)/scaleFactor), 134 ) 135 p.currentCursor = cursor 136 137 if cursor.image_count > 1 { 138 p.currentCursorAnimationStartTime = time.Now() 139 p.startAnimatingCursor() 140 } 141 } 142 143 func (p *Pointer) startAnimatingCursor() { 144 var fn func() 145 fn = func() { 146 p.mu.Lock() 147 defer p.mu.Unlock() 148 149 if p.cursorSurfaceFrameCallback != nil { 150 p.d.l.wl_callback_destroy(p.cursorSurfaceFrameCallback) 151 p.cursorSurfaceFrameCallback = nil 152 } 153 154 if p.currentCursor == nil { 155 return 156 } 157 158 imageIdx := p.d.l.wl_cursor_frame_and_duration( 159 p.currentCursor, 160 C.uint32_t(p.currentCursorAnimationStartTime.UnixMilli()), 161 nil, 162 ) 163 164 imageSlice := unsafe.Slice(p.currentCursor.images, p.currentCursor.image_count) 165 image := imageSlice[imageIdx] 166 cursorBuffer := p.d.l.wl_cursor_image_get_buffer(image) 167 168 p.d.l.wl_surface_attach(p.cursorSurface, cursorBuffer, 0, 0) 169 p.d.l.wl_surface_damage_buffer(p.cursorSurface, 0, 0, C.int32_t(image.width), C.int32_t(image.height)) 170 171 p.cursorSurfaceFrameCallback = p.d.l.wl_surface_frame(p.cursorSurface) 172 p.d.setCallbackListener(p.cursorSurfaceFrameCallback, fn) 173 p.d.l.wl_surface_commit(p.cursorSurface) 174 175 p.currentCursorAnimationStartTime = time.Now() 176 } 177 178 p.cursorSurfaceFrameCallback = p.d.l.wl_surface_frame(p.cursorSurface) 179 p.d.setCallbackListener(p.cursorSurfaceFrameCallback, fn) 180 p.d.l.wl_surface_commit(p.cursorSurface) 181 } 182 183 //export pointerHandleEnter 184 func pointerHandleEnter(data unsafe.Pointer, wl_pointer *C.struct_wl_pointer, serial C.uint32_t, surface *C.struct_wl_surface, surface_x C.wl_fixed_t, surface_y C.wl_fixed_t) { 185 if surface == nil { 186 return 187 } 188 189 d, ok := (*cgo.Handle)(data).Value().(*Display) 190 if !ok { 191 return 192 } 193 194 d.pointer.mu.Lock() 195 d.pointer.serial = uint32(serial) 196 d.pointer.focus = surface 197 d.pointer.mu.Unlock() 198 199 w, ok := d.windows[surface] 200 if !ok { 201 return 202 } 203 204 w.mu.Lock() 205 currentCursorIcon := w.currentCursorIcon 206 scaleFactor := w.scaleFactor 207 w.mu.Unlock() 208 209 // user can call window.SetCursor when window is not in focus 210 // so we just store the state so when pointer enters window 211 // we set cursor to how the window's state requires it 212 if currentCursorIcon == "" { 213 d.pointer.setCursor(nil, "", 0) 214 } else { 215 cursor := d.pointer.loadCursor(currentCursorIcon, 24, scaleFactor) 216 if cursor != nil { 217 d.pointer.setCursor(cursor, currentCursorIcon, scaleFactor) 218 } 219 } 220 221 if cb := w.cursorEnteredCb.Load(); cb != nil { 222 if cb := (*cb); cb != nil { 223 cb() 224 } 225 } 226 } 227 228 //export pointerHandleLeave 229 func pointerHandleLeave(data unsafe.Pointer, wl_pointer *C.struct_wl_pointer, serial C.uint32_t, surface *C.struct_wl_surface) { 230 if surface == nil { 231 return 232 } 233 234 d, ok := (*cgo.Handle)(data).Value().(*Display) 235 if !ok { 236 return 237 } 238 239 d.pointer.mu.Lock() 240 d.pointer.serial = uint32(serial) 241 d.pointer.focus = nil 242 d.pointer.mu.Unlock() 243 244 d.pointer.setCursor(nil, "", 0) 245 246 w, ok := d.windows[surface] 247 if !ok { 248 return 249 } 250 251 if cb := w.cursorLeftCb.Load(); cb != nil { 252 if cb := (*cb); cb != nil { 253 cb() 254 } 255 } 256 } 257 258 //export pointerHandleMotion 259 func pointerHandleMotion(data unsafe.Pointer, wl_pointer *C.struct_wl_pointer, time C.uint32_t, surface_x C.double, surface_y C.double) { 260 d, ok := (*cgo.Handle)(data).Value().(*Display) 261 if !ok { 262 return 263 } 264 265 d.pointer.mu.Lock() 266 focus := d.pointer.focus 267 d.pointer.mu.Unlock() 268 269 if focus == nil { 270 return 271 } 272 273 w, ok := d.windows[focus] 274 if !ok { 275 return 276 } 277 278 if cb := w.cursorMovedCb.Load(); cb != nil { 279 if cb := (*cb); cb != nil { 280 cb(float64(surface_x), float64(surface_y)) 281 } 282 } 283 } 284 285 //export pointerHandleButton 286 func pointerHandleButton(data unsafe.Pointer, wl_pointer *C.struct_wl_pointer, serial C.uint32_t, time C.uint32_t, button C.uint32_t, state enum_wl_pointer_button_state) { 287 const ( 288 BTN_LEFT = 272 289 BTN_RIGHT = 273 290 BTN_MIDDLE = 274 291 ) 292 293 d, ok := (*cgo.Handle)(data).Value().(*Display) 294 if !ok { 295 return 296 } 297 298 d.pointer.mu.Lock() 299 d.pointer.serial = uint32(serial) 300 focus := d.pointer.focus 301 d.pointer.mu.Unlock() 302 303 if focus == nil { 304 return 305 } 306 307 w, ok := d.windows[focus] 308 if !ok { 309 return 310 } 311 312 if cb := w.mouseInputCb.Load(); cb != nil { 313 if cb := (*cb); cb != nil { 314 var s events.ButtonState 315 switch state { 316 case WL_POINTER_BUTTON_STATE_PRESSED: 317 s = events.ButtonStatePressed 318 case WL_POINTER_BUTTON_STATE_RELEASED: 319 s = events.ButtonStateReleased 320 } 321 322 var b events.MouseButton 323 switch button { 324 case BTN_LEFT: 325 b = events.MouseButtonLeft 326 case BTN_RIGHT: 327 b = events.MouseButtonRight 328 case BTN_MIDDLE: 329 b = events.MouseButtonMiddle 330 default: 331 b = events.MouseButton(button) 332 } 333 334 cb(s, b) 335 } 336 } 337 } 338 339 //export pointerHandleAxis 340 func pointerHandleAxis(data unsafe.Pointer, wl_pointer *C.struct_wl_pointer, time C.uint32_t, axis enum_wl_pointer_axis, value C.double) { 341 d, ok := (*cgo.Handle)(data).Value().(*Display) 342 if !ok { 343 return 344 } 345 346 // we call callbacks on frame event 347 switch axis { 348 case WL_POINTER_AXIS_VERTICAL_SCROLL: 349 d.pointer.pixelDeltaVertical -= float64(value) 350 351 case WL_POINTER_AXIS_HORIZONTAL_SCROLL: 352 d.pointer.pixelDeltaHorizontal -= float64(value) 353 } 354 } 355 356 //export pointerHandleAxisDiscrete 357 func pointerHandleAxisDiscrete(data unsafe.Pointer, wl_pointer *C.struct_wl_pointer, axis enum_wl_pointer_axis, discrete C.int32_t) { 358 d, ok := (*cgo.Handle)(data).Value().(*Display) 359 if !ok { 360 return 361 } 362 363 // we call callbacks on frame event 364 switch axis { 365 case WL_POINTER_AXIS_VERTICAL_SCROLL: 366 d.pointer.lineDeltaVertical -= float64(discrete) 367 368 case WL_POINTER_AXIS_HORIZONTAL_SCROLL: 369 d.pointer.lineDeltaHorizontal -= float64(discrete) 370 } 371 } 372 373 //export pointerHandleFrame 374 func pointerHandleFrame(data unsafe.Pointer, wl_pointer *C.struct_wl_pointer) { 375 d, ok := (*cgo.Handle)(data).Value().(*Display) 376 if !ok { 377 return 378 } 379 380 d.pointer.mu.Lock() 381 focus := d.pointer.focus 382 d.pointer.mu.Unlock() 383 384 if focus == nil { 385 return 386 } 387 388 w, ok := d.windows[focus] 389 if !ok || w == nil { 390 return 391 } 392 393 if d.pointer.lineDeltaVertical != 0 { 394 if cb := w.mouseWheelCb.Load(); cb != nil { 395 if cb := (*cb); cb != nil { 396 cb( 397 events.MouseScrollDeltaLine, 398 events.MouseScrollAxisVertical, 399 d.pointer.lineDeltaVertical, 400 ) 401 } 402 } 403 404 d.pointer.lineDeltaVertical = 0 405 } else if d.pointer.pixelDeltaVertical != 0 { 406 if cb := w.mouseWheelCb.Load(); cb != nil { 407 if cb := (*cb); cb != nil { 408 cb( 409 events.MouseScrollDeltaPixel, 410 events.MouseScrollAxisVertical, 411 d.pointer.pixelDeltaVertical, 412 ) 413 } 414 } 415 416 d.pointer.pixelDeltaVertical = 0 417 } else if d.pointer.lineDeltaHorizontal != 0 { 418 if cb := w.mouseWheelCb.Load(); cb != nil { 419 if cb := (*cb); cb != nil { 420 cb( 421 events.MouseScrollDeltaLine, 422 events.MouseScrollAxisHorizontal, 423 d.pointer.lineDeltaHorizontal, 424 ) 425 } 426 } 427 428 d.pointer.lineDeltaHorizontal = 0 429 } else if d.pointer.pixelDeltaHorizontal != 0 { 430 if cb := w.mouseWheelCb.Load(); cb != nil { 431 if cb := (*cb); cb != nil { 432 cb( 433 events.MouseScrollDeltaPixel, 434 events.MouseScrollAxisHorizontal, 435 d.pointer.pixelDeltaHorizontal, 436 ) 437 } 438 } 439 440 d.pointer.pixelDeltaHorizontal = 0 441 } 442 }