os_wayland.go 53 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933
  1. // SPDX-License-Identifier: Unlicense OR MIT
  2. //go:build ((linux && !android) || freebsd) && !nowayland
  3. // +build linux,!android freebsd
  4. // +build !nowayland
  5. package app
  6. import (
  7. "bytes"
  8. "errors"
  9. "fmt"
  10. "image"
  11. "io"
  12. "math"
  13. "os"
  14. "os/exec"
  15. "runtime"
  16. "strconv"
  17. "sync"
  18. "time"
  19. "unsafe"
  20. syscall "golang.org/x/sys/unix"
  21. "gioui.org/app/internal/xkb"
  22. "gioui.org/f32"
  23. "gioui.org/internal/fling"
  24. "gioui.org/io/event"
  25. "gioui.org/io/key"
  26. "gioui.org/io/pointer"
  27. "gioui.org/io/system"
  28. "gioui.org/io/transfer"
  29. "gioui.org/op"
  30. "gioui.org/unit"
  31. )
  32. // Use wayland-scanner to generate glue code for the xdg-shell and xdg-decoration extensions.
  33. //go:generate wayland-scanner client-header /usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml wayland_xdg_shell.h
  34. //go:generate wayland-scanner private-code /usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml wayland_xdg_shell.c
  35. //go:generate wayland-scanner client-header /usr/share/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml wayland_text_input.h
  36. //go:generate wayland-scanner private-code /usr/share/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml wayland_text_input.c
  37. //go:generate wayland-scanner client-header /usr/share/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml wayland_xdg_decoration.h
  38. //go:generate wayland-scanner private-code /usr/share/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml wayland_xdg_decoration.c
  39. //go:generate sed -i "1s;^;//go:build ((linux \\&\\& !android) || freebsd) \\&\\& !nowayland\\n// +build linux,!android freebsd\\n// +build !nowayland\\n\\n;" wayland_xdg_shell.c
  40. //go:generate sed -i "1s;^;//go:build ((linux \\&\\& !android) || freebsd) \\&\\& !nowayland\\n// +build linux,!android freebsd\\n// +build !nowayland\\n\\n;" wayland_xdg_decoration.c
  41. //go:generate sed -i "1s;^;//go:build ((linux \\&\\& !android) || freebsd) \\&\\& !nowayland\\n// +build linux,!android freebsd\\n// +build !nowayland\\n\\n;" wayland_text_input.c
  42. /*
  43. #cgo linux pkg-config: wayland-client wayland-cursor
  44. #cgo freebsd openbsd LDFLAGS: -lwayland-client -lwayland-cursor
  45. #cgo freebsd CFLAGS: -I/usr/local/include
  46. #cgo freebsd LDFLAGS: -L/usr/local/lib
  47. #include <stdlib.h>
  48. #include <wayland-client.h>
  49. #include <wayland-cursor.h>
  50. #include "wayland_text_input.h"
  51. #include "wayland_xdg_shell.h"
  52. #include "wayland_xdg_decoration.h"
  53. extern const struct wl_registry_listener gio_registry_listener;
  54. extern const struct wl_surface_listener gio_surface_listener;
  55. extern const struct xdg_surface_listener gio_xdg_surface_listener;
  56. extern const struct xdg_toplevel_listener gio_xdg_toplevel_listener;
  57. extern const struct zxdg_toplevel_decoration_v1_listener gio_zxdg_toplevel_decoration_v1_listener;
  58. extern const struct xdg_wm_base_listener gio_xdg_wm_base_listener;
  59. extern const struct wl_callback_listener gio_callback_listener;
  60. extern const struct wl_output_listener gio_output_listener;
  61. extern const struct wl_seat_listener gio_seat_listener;
  62. extern const struct wl_pointer_listener gio_pointer_listener;
  63. extern const struct wl_touch_listener gio_touch_listener;
  64. extern const struct wl_keyboard_listener gio_keyboard_listener;
  65. extern const struct zwp_text_input_v3_listener gio_zwp_text_input_v3_listener;
  66. extern const struct wl_data_device_listener gio_data_device_listener;
  67. extern const struct wl_data_offer_listener gio_data_offer_listener;
  68. extern const struct wl_data_source_listener gio_data_source_listener;
  69. */
  70. import "C"
  71. type wlDisplay struct {
  72. disp *C.struct_wl_display
  73. reg *C.struct_wl_registry
  74. compositor *C.struct_wl_compositor
  75. wm *C.struct_xdg_wm_base
  76. imm *C.struct_zwp_text_input_manager_v3
  77. shm *C.struct_wl_shm
  78. dataDeviceManager *C.struct_wl_data_device_manager
  79. decor *C.struct_zxdg_decoration_manager_v1
  80. seat *wlSeat
  81. xkb *xkb.Context
  82. outputMap map[C.uint32_t]*C.struct_wl_output
  83. outputConfig map[*C.struct_wl_output]*wlOutput
  84. // Notification pipe fds.
  85. notify struct {
  86. read, write int
  87. }
  88. repeat repeatState
  89. poller poller
  90. readClipClose chan struct{}
  91. }
  92. type wlSeat struct {
  93. disp *wlDisplay
  94. seat *C.struct_wl_seat
  95. name C.uint32_t
  96. pointer *C.struct_wl_pointer
  97. touch *C.struct_wl_touch
  98. keyboard *C.struct_wl_keyboard
  99. im *C.struct_zwp_text_input_v3
  100. // The most recent input serial.
  101. serial C.uint32_t
  102. pointerFocus *window
  103. keyboardFocus *window
  104. touchFoci map[C.int32_t]*window
  105. // Clipboard support.
  106. dataDev *C.struct_wl_data_device
  107. // offers is a map from active wl_data_offers to
  108. // the list of mime types they support.
  109. offers map[*C.struct_wl_data_offer][]string
  110. // clipboard is the wl_data_offer for the clipboard.
  111. clipboard *C.struct_wl_data_offer
  112. // mimeType is the chosen mime type of clipboard.
  113. mimeType string
  114. // source represents the clipboard content of the most recent
  115. // clipboard write, if any.
  116. source *C.struct_wl_data_source
  117. // content is the data belonging to source.
  118. content []byte
  119. }
  120. type repeatState struct {
  121. rate int
  122. delay time.Duration
  123. key uint32
  124. win *window
  125. stopC chan struct{}
  126. start time.Duration
  127. last time.Duration
  128. mu sync.Mutex
  129. now time.Duration
  130. }
  131. type window struct {
  132. w *callbacks
  133. disp *wlDisplay
  134. seat *wlSeat
  135. surf *C.struct_wl_surface
  136. wmSurf *C.struct_xdg_surface
  137. topLvl *C.struct_xdg_toplevel
  138. decor *C.struct_zxdg_toplevel_decoration_v1
  139. ppdp, ppsp float32
  140. scroll struct {
  141. time time.Duration
  142. steps image.Point
  143. dist f32.Point
  144. }
  145. pointerBtns pointer.Buttons
  146. lastPos f32.Point
  147. lastTouch f32.Point
  148. cursor struct {
  149. theme *C.struct_wl_cursor_theme
  150. cursor *C.struct_wl_cursor
  151. // system is the active cursor for system gestures
  152. // such as border resizes and window moves. It
  153. // is nil if the pointer is not in a system gesture
  154. // area.
  155. system *C.struct_wl_cursor
  156. surf *C.struct_wl_surface
  157. cursors struct {
  158. pointer *C.struct_wl_cursor
  159. resizeNorth *C.struct_wl_cursor
  160. resizeSouth *C.struct_wl_cursor
  161. resizeWest *C.struct_wl_cursor
  162. resizeEast *C.struct_wl_cursor
  163. resizeNorthWest *C.struct_wl_cursor
  164. resizeNorthEast *C.struct_wl_cursor
  165. resizeSouthWest *C.struct_wl_cursor
  166. resizeSouthEast *C.struct_wl_cursor
  167. }
  168. }
  169. fling struct {
  170. yExtrapolation fling.Extrapolation
  171. xExtrapolation fling.Extrapolation
  172. anim fling.Animation
  173. start bool
  174. dir f32.Point
  175. }
  176. configured bool
  177. lastFrameCallback *C.struct_wl_callback
  178. animating bool
  179. // The most recent configure serial waiting to be ack'ed.
  180. serial C.uint32_t
  181. scale int
  182. // size is the unscaled window size (unlike config.Size which is scaled).
  183. size image.Point
  184. config Config
  185. wsize image.Point // window config size before going fullscreen or maximized
  186. inCompositor bool // window is moving or being resized
  187. clipReads chan transfer.DataEvent
  188. wakeups chan struct{}
  189. closing bool
  190. }
  191. type poller struct {
  192. pollfds [2]syscall.PollFd
  193. // buf is scratch space for draining the notification pipe.
  194. buf [100]byte
  195. }
  196. type wlOutput struct {
  197. width int
  198. height int
  199. physWidth int
  200. physHeight int
  201. transform C.int32_t
  202. scale int
  203. windows []*window
  204. }
  205. // callbackMap maps Wayland native handles to corresponding Go
  206. // references. It is necessary because the Wayland client API
  207. // forces the use of callbacks and storing pointers to Go values
  208. // in C is forbidden.
  209. var callbackMap sync.Map
  210. // clipboardMimeTypes is a list of supported clipboard mime types, in
  211. // order of preference.
  212. var clipboardMimeTypes = []string{"text/plain;charset=utf8", "UTF8_STRING", "text/plain", "TEXT", "STRING"}
  213. var (
  214. newWaylandEGLContext func(w *window) (context, error)
  215. newWaylandVulkanContext func(w *window) (context, error)
  216. )
  217. func init() {
  218. wlDriver = newWLWindow
  219. }
  220. func newWLWindow(callbacks *callbacks, options []Option) error {
  221. d, err := newWLDisplay()
  222. if err != nil {
  223. return err
  224. }
  225. w, err := d.createNativeWindow(options)
  226. if err != nil {
  227. d.destroy()
  228. return err
  229. }
  230. w.w = callbacks
  231. w.w.SetDriver(w)
  232. // Finish and commit setup from createNativeWindow.
  233. w.Configure(options)
  234. w.draw(true)
  235. C.wl_surface_commit(w.surf)
  236. w.ProcessEvent(WaylandViewEvent{
  237. Display: unsafe.Pointer(w.display()),
  238. Surface: unsafe.Pointer(w.surf),
  239. })
  240. return nil
  241. }
  242. func (d *wlDisplay) writeClipboard(content []byte) error {
  243. s := d.seat
  244. if s == nil {
  245. return nil
  246. }
  247. // Clear old offer.
  248. if s.source != nil {
  249. C.wl_data_source_destroy(s.source)
  250. s.source = nil
  251. s.content = nil
  252. }
  253. if d.dataDeviceManager == nil || s.dataDev == nil {
  254. return nil
  255. }
  256. s.content = content
  257. s.source = C.wl_data_device_manager_create_data_source(d.dataDeviceManager)
  258. C.wl_data_source_add_listener(s.source, &C.gio_data_source_listener, unsafe.Pointer(s.seat))
  259. for _, mime := range clipboardMimeTypes {
  260. C.wl_data_source_offer(s.source, C.CString(mime))
  261. }
  262. C.wl_data_device_set_selection(s.dataDev, s.source, s.serial)
  263. return nil
  264. }
  265. func (d *wlDisplay) readClipboard() (io.ReadCloser, error) {
  266. s := d.seat
  267. if s == nil {
  268. return nil, nil
  269. }
  270. if s.clipboard == nil {
  271. return nil, nil
  272. }
  273. r, w, err := os.Pipe()
  274. if err != nil {
  275. return nil, err
  276. }
  277. // wl_data_offer_receive performs and implicit dup(2) of the write end
  278. // of the pipe. Close our version.
  279. defer w.Close()
  280. cmimeType := C.CString(s.mimeType)
  281. defer C.free(unsafe.Pointer(cmimeType))
  282. C.wl_data_offer_receive(s.clipboard, cmimeType, C.int(w.Fd()))
  283. return r, nil
  284. }
  285. func (d *wlDisplay) createNativeWindow(options []Option) (*window, error) {
  286. if d.compositor == nil {
  287. return nil, errors.New("wayland: no compositor available")
  288. }
  289. if d.wm == nil {
  290. return nil, errors.New("wayland: no xdg_wm_base available")
  291. }
  292. if d.shm == nil {
  293. return nil, errors.New("wayland: no wl_shm available")
  294. }
  295. if len(d.outputMap) == 0 {
  296. return nil, errors.New("wayland: no outputs available")
  297. }
  298. var scale int
  299. for _, conf := range d.outputConfig {
  300. if s := conf.scale; s > scale {
  301. scale = s
  302. }
  303. }
  304. ppdp := detectUIScale()
  305. w := &window{
  306. disp: d,
  307. scale: scale,
  308. ppdp: ppdp,
  309. ppsp: ppdp,
  310. wakeups: make(chan struct{}, 1),
  311. clipReads: make(chan transfer.DataEvent, 1),
  312. }
  313. w.surf = C.wl_compositor_create_surface(d.compositor)
  314. if w.surf == nil {
  315. w.destroy()
  316. return nil, errors.New("wayland: wl_compositor_create_surface failed")
  317. }
  318. C.wl_surface_set_buffer_scale(w.surf, C.int32_t(w.scale))
  319. callbackStore(unsafe.Pointer(w.surf), w)
  320. w.wmSurf = C.xdg_wm_base_get_xdg_surface(d.wm, w.surf)
  321. if w.wmSurf == nil {
  322. w.destroy()
  323. return nil, errors.New("wayland: xdg_wm_base_get_xdg_surface failed")
  324. }
  325. w.topLvl = C.xdg_surface_get_toplevel(w.wmSurf)
  326. if w.topLvl == nil {
  327. w.destroy()
  328. return nil, errors.New("wayland: xdg_surface_get_toplevel failed")
  329. }
  330. id := C.CString(ID)
  331. defer C.free(unsafe.Pointer(id))
  332. C.xdg_toplevel_set_app_id(w.topLvl, id)
  333. cursorTheme := C.CString(os.Getenv("XCURSOR_THEME"))
  334. defer C.free(unsafe.Pointer(cursorTheme))
  335. cursorSize := 32
  336. if envSize, ok := os.LookupEnv("XCURSOR_SIZE"); ok && envSize != "" {
  337. size, err := strconv.Atoi(envSize)
  338. if err == nil {
  339. cursorSize = size
  340. }
  341. }
  342. w.cursor.theme = C.wl_cursor_theme_load(cursorTheme, C.int(cursorSize*w.scale), d.shm)
  343. if w.cursor.theme == nil {
  344. w.destroy()
  345. return nil, errors.New("wayland: wl_cursor_theme_load failed")
  346. }
  347. w.loadCursors()
  348. w.cursor.cursor = w.cursor.cursors.pointer
  349. if w.cursor.cursor == nil {
  350. w.destroy()
  351. return nil, errors.New("wayland: wl_cursor_theme_get_cursor failed")
  352. }
  353. w.cursor.surf = C.wl_compositor_create_surface(d.compositor)
  354. if w.cursor.surf == nil {
  355. w.destroy()
  356. return nil, errors.New("wayland: wl_compositor_create_surface failed")
  357. }
  358. C.wl_surface_set_buffer_scale(w.cursor.surf, C.int32_t(w.scale))
  359. C.xdg_wm_base_add_listener(d.wm, &C.gio_xdg_wm_base_listener, unsafe.Pointer(w.surf))
  360. C.wl_surface_add_listener(w.surf, &C.gio_surface_listener, unsafe.Pointer(w.surf))
  361. C.xdg_surface_add_listener(w.wmSurf, &C.gio_xdg_surface_listener, unsafe.Pointer(w.surf))
  362. C.xdg_toplevel_add_listener(w.topLvl, &C.gio_xdg_toplevel_listener, unsafe.Pointer(w.surf))
  363. if d.decor != nil {
  364. w.decor = C.zxdg_decoration_manager_v1_get_toplevel_decoration(d.decor, w.topLvl)
  365. C.zxdg_toplevel_decoration_v1_add_listener(w.decor, &C.gio_zxdg_toplevel_decoration_v1_listener, unsafe.Pointer(w.surf))
  366. }
  367. w.updateOpaqueRegion()
  368. return w, nil
  369. }
  370. func (w *window) loadCursors() {
  371. w.cursor.cursors.pointer = w.loadCursor(pointer.CursorDefault)
  372. w.cursor.cursors.resizeNorth = w.loadCursor(pointer.CursorNorthResize)
  373. w.cursor.cursors.resizeSouth = w.loadCursor(pointer.CursorSouthResize)
  374. w.cursor.cursors.resizeWest = w.loadCursor(pointer.CursorWestResize)
  375. w.cursor.cursors.resizeEast = w.loadCursor(pointer.CursorEastResize)
  376. w.cursor.cursors.resizeSouthWest = w.loadCursor(pointer.CursorSouthWestResize)
  377. w.cursor.cursors.resizeSouthEast = w.loadCursor(pointer.CursorSouthEastResize)
  378. w.cursor.cursors.resizeNorthWest = w.loadCursor(pointer.CursorNorthWestResize)
  379. w.cursor.cursors.resizeNorthEast = w.loadCursor(pointer.CursorNorthEastResize)
  380. }
  381. func (w *window) loadCursor(name pointer.Cursor) *C.struct_wl_cursor {
  382. if name == pointer.CursorNone {
  383. return nil
  384. }
  385. xcursor := xCursor[name]
  386. cname := C.CString(xcursor)
  387. defer C.free(unsafe.Pointer(cname))
  388. c := C.wl_cursor_theme_get_cursor(w.cursor.theme, cname)
  389. if c == nil {
  390. // Fall back to default cursor.
  391. c = w.cursor.cursors.pointer
  392. }
  393. return c
  394. }
  395. func callbackDelete(k unsafe.Pointer) {
  396. callbackMap.Delete(k)
  397. }
  398. func callbackStore(k unsafe.Pointer, v interface{}) {
  399. callbackMap.Store(k, v)
  400. }
  401. func callbackLoad(k unsafe.Pointer) interface{} {
  402. v, exists := callbackMap.Load(k)
  403. if !exists {
  404. panic("missing callback entry")
  405. }
  406. return v
  407. }
  408. //export gio_onSeatCapabilities
  409. func gio_onSeatCapabilities(data unsafe.Pointer, seat *C.struct_wl_seat, caps C.uint32_t) {
  410. s := callbackLoad(data).(*wlSeat)
  411. s.updateCaps(caps)
  412. }
  413. // flushOffers remove all wl_data_offers that isn't the clipboard
  414. // content.
  415. func (s *wlSeat) flushOffers() {
  416. for o := range s.offers {
  417. if o == s.clipboard {
  418. continue
  419. }
  420. // We're only interested in clipboard offers.
  421. delete(s.offers, o)
  422. callbackDelete(unsafe.Pointer(o))
  423. C.wl_data_offer_destroy(o)
  424. }
  425. }
  426. func (s *wlSeat) destroy() {
  427. if s.source != nil {
  428. C.wl_data_source_destroy(s.source)
  429. s.source = nil
  430. }
  431. if s.im != nil {
  432. C.zwp_text_input_v3_destroy(s.im)
  433. s.im = nil
  434. }
  435. if s.pointer != nil {
  436. C.wl_pointer_release(s.pointer)
  437. }
  438. if s.touch != nil {
  439. C.wl_touch_release(s.touch)
  440. }
  441. if s.keyboard != nil {
  442. C.wl_keyboard_release(s.keyboard)
  443. }
  444. s.clipboard = nil
  445. s.flushOffers()
  446. if s.dataDev != nil {
  447. C.wl_data_device_release(s.dataDev)
  448. }
  449. if s.seat != nil {
  450. callbackDelete(unsafe.Pointer(s.seat))
  451. C.wl_seat_release(s.seat)
  452. }
  453. }
  454. func (s *wlSeat) updateCaps(caps C.uint32_t) {
  455. if s.im == nil && s.disp.imm != nil {
  456. s.im = C.zwp_text_input_manager_v3_get_text_input(s.disp.imm, s.seat)
  457. C.zwp_text_input_v3_add_listener(s.im, &C.gio_zwp_text_input_v3_listener, unsafe.Pointer(s.seat))
  458. }
  459. switch {
  460. case s.pointer == nil && caps&C.WL_SEAT_CAPABILITY_POINTER != 0:
  461. s.pointer = C.wl_seat_get_pointer(s.seat)
  462. C.wl_pointer_add_listener(s.pointer, &C.gio_pointer_listener, unsafe.Pointer(s.seat))
  463. case s.pointer != nil && caps&C.WL_SEAT_CAPABILITY_POINTER == 0:
  464. C.wl_pointer_release(s.pointer)
  465. s.pointer = nil
  466. }
  467. switch {
  468. case s.touch == nil && caps&C.WL_SEAT_CAPABILITY_TOUCH != 0:
  469. s.touch = C.wl_seat_get_touch(s.seat)
  470. C.wl_touch_add_listener(s.touch, &C.gio_touch_listener, unsafe.Pointer(s.seat))
  471. case s.touch != nil && caps&C.WL_SEAT_CAPABILITY_TOUCH == 0:
  472. C.wl_touch_release(s.touch)
  473. s.touch = nil
  474. }
  475. switch {
  476. case s.keyboard == nil && caps&C.WL_SEAT_CAPABILITY_KEYBOARD != 0:
  477. s.keyboard = C.wl_seat_get_keyboard(s.seat)
  478. C.wl_keyboard_add_listener(s.keyboard, &C.gio_keyboard_listener, unsafe.Pointer(s.seat))
  479. case s.keyboard != nil && caps&C.WL_SEAT_CAPABILITY_KEYBOARD == 0:
  480. C.wl_keyboard_release(s.keyboard)
  481. s.keyboard = nil
  482. }
  483. }
  484. //export gio_onSeatName
  485. func gio_onSeatName(data unsafe.Pointer, seat *C.struct_wl_seat, name *C.char) {
  486. }
  487. //export gio_onXdgSurfaceConfigure
  488. func gio_onXdgSurfaceConfigure(data unsafe.Pointer, wmSurf *C.struct_xdg_surface, serial C.uint32_t) {
  489. w := callbackLoad(data).(*window)
  490. w.serial = serial
  491. C.xdg_surface_ack_configure(wmSurf, serial)
  492. w.configured = true
  493. w.draw(true)
  494. }
  495. //export gio_onToplevelClose
  496. func gio_onToplevelClose(data unsafe.Pointer, topLvl *C.struct_xdg_toplevel) {
  497. w := callbackLoad(data).(*window)
  498. w.closing = true
  499. }
  500. //export gio_onToplevelConfigure
  501. func gio_onToplevelConfigure(data unsafe.Pointer, topLvl *C.struct_xdg_toplevel, width, height C.int32_t, states *C.struct_wl_array) {
  502. w := callbackLoad(data).(*window)
  503. if width != 0 && height != 0 {
  504. w.size = image.Pt(int(width), int(height))
  505. w.updateOpaqueRegion()
  506. }
  507. }
  508. //export gio_onToplevelDecorationConfigure
  509. func gio_onToplevelDecorationConfigure(data unsafe.Pointer, deco *C.struct_zxdg_toplevel_decoration_v1, mode C.uint32_t) {
  510. w := callbackLoad(data).(*window)
  511. decorated := w.config.Decorated
  512. switch mode {
  513. case C.ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE:
  514. w.config.Decorated = false
  515. case C.ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE:
  516. w.config.Decorated = true
  517. }
  518. if decorated != w.config.Decorated {
  519. w.setWindowConstraints()
  520. if w.config.Decorated {
  521. w.size.Y -= int(w.config.decoHeight)
  522. } else {
  523. w.size.Y += int(w.config.decoHeight)
  524. }
  525. w.ProcessEvent(ConfigEvent{Config: w.config})
  526. w.draw(true)
  527. }
  528. }
  529. //export gio_onOutputMode
  530. func gio_onOutputMode(data unsafe.Pointer, output *C.struct_wl_output, flags C.uint32_t, width, height, refresh C.int32_t) {
  531. if flags&C.WL_OUTPUT_MODE_CURRENT == 0 {
  532. return
  533. }
  534. d := callbackLoad(data).(*wlDisplay)
  535. c := d.outputConfig[output]
  536. c.width = int(width)
  537. c.height = int(height)
  538. }
  539. //export gio_onOutputGeometry
  540. func gio_onOutputGeometry(data unsafe.Pointer, output *C.struct_wl_output, x, y, physWidth, physHeight, subpixel C.int32_t, make, model *C.char, transform C.int32_t) {
  541. d := callbackLoad(data).(*wlDisplay)
  542. c := d.outputConfig[output]
  543. c.transform = transform
  544. c.physWidth = int(physWidth)
  545. c.physHeight = int(physHeight)
  546. }
  547. //export gio_onOutputScale
  548. func gio_onOutputScale(data unsafe.Pointer, output *C.struct_wl_output, scale C.int32_t) {
  549. d := callbackLoad(data).(*wlDisplay)
  550. c := d.outputConfig[output]
  551. c.scale = int(scale)
  552. }
  553. //export gio_onOutputDone
  554. func gio_onOutputDone(data unsafe.Pointer, output *C.struct_wl_output) {
  555. d := callbackLoad(data).(*wlDisplay)
  556. conf := d.outputConfig[output]
  557. for _, w := range conf.windows {
  558. w.updateOutputs()
  559. }
  560. }
  561. //export gio_onSurfaceEnter
  562. func gio_onSurfaceEnter(data unsafe.Pointer, surf *C.struct_wl_surface, output *C.struct_wl_output) {
  563. w := callbackLoad(data).(*window)
  564. conf := w.disp.outputConfig[output]
  565. var found bool
  566. for _, w2 := range conf.windows {
  567. if w2 == w {
  568. found = true
  569. break
  570. }
  571. }
  572. if !found {
  573. conf.windows = append(conf.windows, w)
  574. }
  575. w.updateOutputs()
  576. if w.config.Mode == Minimized {
  577. // Minimized window got brought back up: it is no longer so.
  578. w.config.Mode = Windowed
  579. w.ProcessEvent(ConfigEvent{Config: w.config})
  580. }
  581. }
  582. //export gio_onSurfaceLeave
  583. func gio_onSurfaceLeave(data unsafe.Pointer, surf *C.struct_wl_surface, output *C.struct_wl_output) {
  584. w := callbackLoad(data).(*window)
  585. conf := w.disp.outputConfig[output]
  586. for i, w2 := range conf.windows {
  587. if w2 == w {
  588. conf.windows = append(conf.windows[:i], conf.windows[i+1:]...)
  589. break
  590. }
  591. }
  592. w.updateOutputs()
  593. }
  594. //export gio_onRegistryGlobal
  595. func gio_onRegistryGlobal(data unsafe.Pointer, reg *C.struct_wl_registry, name C.uint32_t, cintf *C.char, version C.uint32_t) {
  596. d := callbackLoad(data).(*wlDisplay)
  597. switch C.GoString(cintf) {
  598. case "wl_compositor":
  599. d.compositor = (*C.struct_wl_compositor)(C.wl_registry_bind(reg, name, &C.wl_compositor_interface, 3))
  600. case "wl_output":
  601. output := (*C.struct_wl_output)(C.wl_registry_bind(reg, name, &C.wl_output_interface, 2))
  602. C.wl_output_add_listener(output, &C.gio_output_listener, unsafe.Pointer(d.disp))
  603. d.outputMap[name] = output
  604. d.outputConfig[output] = new(wlOutput)
  605. case "wl_seat":
  606. if d.seat != nil {
  607. break
  608. }
  609. s := (*C.struct_wl_seat)(C.wl_registry_bind(reg, name, &C.wl_seat_interface, 5))
  610. if s == nil {
  611. // No support for v5 protocol.
  612. break
  613. }
  614. d.seat = &wlSeat{
  615. disp: d,
  616. name: name,
  617. seat: s,
  618. offers: make(map[*C.struct_wl_data_offer][]string),
  619. touchFoci: make(map[C.int32_t]*window),
  620. }
  621. callbackStore(unsafe.Pointer(s), d.seat)
  622. C.wl_seat_add_listener(s, &C.gio_seat_listener, unsafe.Pointer(s))
  623. d.bindDataDevice()
  624. case "wl_shm":
  625. d.shm = (*C.struct_wl_shm)(C.wl_registry_bind(reg, name, &C.wl_shm_interface, 1))
  626. case "xdg_wm_base":
  627. d.wm = (*C.struct_xdg_wm_base)(C.wl_registry_bind(reg, name, &C.xdg_wm_base_interface, 1))
  628. case "zxdg_decoration_manager_v1":
  629. d.decor = (*C.struct_zxdg_decoration_manager_v1)(C.wl_registry_bind(reg, name, &C.zxdg_decoration_manager_v1_interface, 1))
  630. // TODO: Implement and test text-input support.
  631. /*case "zwp_text_input_manager_v3":
  632. d.imm = (*C.struct_zwp_text_input_manager_v3)(C.wl_registry_bind(reg, name, &C.zwp_text_input_manager_v3_interface, 1))*/
  633. case "wl_data_device_manager":
  634. d.dataDeviceManager = (*C.struct_wl_data_device_manager)(C.wl_registry_bind(reg, name, &C.wl_data_device_manager_interface, 3))
  635. d.bindDataDevice()
  636. }
  637. }
  638. //export gio_onDataOfferOffer
  639. func gio_onDataOfferOffer(data unsafe.Pointer, offer *C.struct_wl_data_offer, mime *C.char) {
  640. s := callbackLoad(data).(*wlSeat)
  641. s.offers[offer] = append(s.offers[offer], C.GoString(mime))
  642. }
  643. //export gio_onDataOfferSourceActions
  644. func gio_onDataOfferSourceActions(data unsafe.Pointer, offer *C.struct_wl_data_offer, acts C.uint32_t) {
  645. }
  646. //export gio_onDataOfferAction
  647. func gio_onDataOfferAction(data unsafe.Pointer, offer *C.struct_wl_data_offer, act C.uint32_t) {
  648. }
  649. //export gio_onDataDeviceOffer
  650. func gio_onDataDeviceOffer(data unsafe.Pointer, dataDev *C.struct_wl_data_device, id *C.struct_wl_data_offer) {
  651. s := callbackLoad(data).(*wlSeat)
  652. callbackStore(unsafe.Pointer(id), s)
  653. C.wl_data_offer_add_listener(id, &C.gio_data_offer_listener, unsafe.Pointer(id))
  654. s.offers[id] = nil
  655. }
  656. //export gio_onDataDeviceEnter
  657. func gio_onDataDeviceEnter(data unsafe.Pointer, dataDev *C.struct_wl_data_device, serial C.uint32_t, surf *C.struct_wl_surface, x, y C.wl_fixed_t, id *C.struct_wl_data_offer) {
  658. s := callbackLoad(data).(*wlSeat)
  659. s.serial = serial
  660. s.flushOffers()
  661. }
  662. //export gio_onDataDeviceLeave
  663. func gio_onDataDeviceLeave(data unsafe.Pointer, dataDev *C.struct_wl_data_device) {
  664. }
  665. //export gio_onDataDeviceMotion
  666. func gio_onDataDeviceMotion(data unsafe.Pointer, dataDev *C.struct_wl_data_device, t C.uint32_t, x, y C.wl_fixed_t) {
  667. }
  668. //export gio_onDataDeviceDrop
  669. func gio_onDataDeviceDrop(data unsafe.Pointer, dataDev *C.struct_wl_data_device) {
  670. }
  671. //export gio_onDataDeviceSelection
  672. func gio_onDataDeviceSelection(data unsafe.Pointer, dataDev *C.struct_wl_data_device, id *C.struct_wl_data_offer) {
  673. s := callbackLoad(data).(*wlSeat)
  674. defer s.flushOffers()
  675. s.clipboard = nil
  676. loop:
  677. for _, want := range clipboardMimeTypes {
  678. for _, got := range s.offers[id] {
  679. if want != got {
  680. continue
  681. }
  682. s.clipboard = id
  683. s.mimeType = got
  684. break loop
  685. }
  686. }
  687. }
  688. //export gio_onRegistryGlobalRemove
  689. func gio_onRegistryGlobalRemove(data unsafe.Pointer, reg *C.struct_wl_registry, name C.uint32_t) {
  690. d := callbackLoad(data).(*wlDisplay)
  691. if s := d.seat; s != nil && name == s.name {
  692. s.destroy()
  693. d.seat = nil
  694. }
  695. if output, exists := d.outputMap[name]; exists {
  696. C.wl_output_destroy(output)
  697. delete(d.outputMap, name)
  698. delete(d.outputConfig, output)
  699. }
  700. }
  701. //export gio_onTouchDown
  702. func gio_onTouchDown(data unsafe.Pointer, touch *C.struct_wl_touch, serial, t C.uint32_t, surf *C.struct_wl_surface, id C.int32_t, x, y C.wl_fixed_t) {
  703. s := callbackLoad(data).(*wlSeat)
  704. s.serial = serial
  705. w := callbackLoad(unsafe.Pointer(surf)).(*window)
  706. s.touchFoci[id] = w
  707. w.lastTouch = f32.Point{
  708. X: fromFixed(x) * float32(w.scale),
  709. Y: fromFixed(y) * float32(w.scale),
  710. }
  711. w.ProcessEvent(pointer.Event{
  712. Kind: pointer.Press,
  713. Source: pointer.Touch,
  714. Position: w.lastTouch,
  715. PointerID: pointer.ID(id),
  716. Time: time.Duration(t) * time.Millisecond,
  717. Modifiers: w.disp.xkb.Modifiers(),
  718. })
  719. }
  720. //export gio_onTouchUp
  721. func gio_onTouchUp(data unsafe.Pointer, touch *C.struct_wl_touch, serial, t C.uint32_t, id C.int32_t) {
  722. s := callbackLoad(data).(*wlSeat)
  723. s.serial = serial
  724. w := s.touchFoci[id]
  725. delete(s.touchFoci, id)
  726. w.ProcessEvent(pointer.Event{
  727. Kind: pointer.Release,
  728. Source: pointer.Touch,
  729. Position: w.lastTouch,
  730. PointerID: pointer.ID(id),
  731. Time: time.Duration(t) * time.Millisecond,
  732. Modifiers: w.disp.xkb.Modifiers(),
  733. })
  734. }
  735. //export gio_onTouchMotion
  736. func gio_onTouchMotion(data unsafe.Pointer, touch *C.struct_wl_touch, t C.uint32_t, id C.int32_t, x, y C.wl_fixed_t) {
  737. s := callbackLoad(data).(*wlSeat)
  738. w := s.touchFoci[id]
  739. w.lastTouch = f32.Point{
  740. X: fromFixed(x) * float32(w.scale),
  741. Y: fromFixed(y) * float32(w.scale),
  742. }
  743. w.ProcessEvent(pointer.Event{
  744. Kind: pointer.Move,
  745. Position: w.lastTouch,
  746. Source: pointer.Touch,
  747. PointerID: pointer.ID(id),
  748. Time: time.Duration(t) * time.Millisecond,
  749. Modifiers: w.disp.xkb.Modifiers(),
  750. })
  751. }
  752. //export gio_onTouchFrame
  753. func gio_onTouchFrame(data unsafe.Pointer, touch *C.struct_wl_touch) {
  754. }
  755. //export gio_onTouchCancel
  756. func gio_onTouchCancel(data unsafe.Pointer, touch *C.struct_wl_touch) {
  757. s := callbackLoad(data).(*wlSeat)
  758. for id, w := range s.touchFoci {
  759. delete(s.touchFoci, id)
  760. w.ProcessEvent(pointer.Event{
  761. Kind: pointer.Cancel,
  762. Source: pointer.Touch,
  763. })
  764. }
  765. }
  766. //export gio_onPointerEnter
  767. func gio_onPointerEnter(data unsafe.Pointer, pointer *C.struct_wl_pointer, serial C.uint32_t, surf *C.struct_wl_surface, x, y C.wl_fixed_t) {
  768. s := callbackLoad(data).(*wlSeat)
  769. s.serial = serial
  770. w := callbackLoad(unsafe.Pointer(surf)).(*window)
  771. w.seat = s
  772. s.pointerFocus = w
  773. w.setCursor(pointer, serial)
  774. w.lastPos = f32.Point{X: fromFixed(x), Y: fromFixed(y)}
  775. }
  776. //export gio_onPointerLeave
  777. func gio_onPointerLeave(data unsafe.Pointer, p *C.struct_wl_pointer, serial C.uint32_t, surf *C.struct_wl_surface) {
  778. w := callbackLoad(unsafe.Pointer(surf)).(*window)
  779. w.seat = nil
  780. s := callbackLoad(data).(*wlSeat)
  781. s.serial = serial
  782. if w.inCompositor {
  783. w.inCompositor = false
  784. w.ProcessEvent(pointer.Event{Kind: pointer.Cancel})
  785. }
  786. }
  787. //export gio_onPointerMotion
  788. func gio_onPointerMotion(data unsafe.Pointer, p *C.struct_wl_pointer, t C.uint32_t, x, y C.wl_fixed_t) {
  789. s := callbackLoad(data).(*wlSeat)
  790. w := s.pointerFocus
  791. w.resetFling()
  792. w.onPointerMotion(x, y, t)
  793. }
  794. //export gio_onPointerButton
  795. func gio_onPointerButton(data unsafe.Pointer, p *C.struct_wl_pointer, serial, t, wbtn, state C.uint32_t) {
  796. s := callbackLoad(data).(*wlSeat)
  797. s.serial = serial
  798. w := s.pointerFocus
  799. // From linux-event-codes.h.
  800. const (
  801. BTN_LEFT = 0x110
  802. BTN_RIGHT = 0x111
  803. BTN_MIDDLE = 0x112
  804. )
  805. var btn pointer.Buttons
  806. switch wbtn {
  807. case BTN_LEFT:
  808. btn = pointer.ButtonPrimary
  809. case BTN_RIGHT:
  810. btn = pointer.ButtonSecondary
  811. case BTN_MIDDLE:
  812. btn = pointer.ButtonTertiary
  813. default:
  814. return
  815. }
  816. if state == 1 && btn == pointer.ButtonPrimary {
  817. if _, edge := w.systemGesture(); edge != 0 {
  818. w.resize(serial, edge)
  819. return
  820. }
  821. act, ok := w.w.ActionAt(w.lastPos)
  822. if ok && w.config.Mode == Windowed {
  823. switch act {
  824. case system.ActionMove:
  825. w.move(serial)
  826. return
  827. }
  828. }
  829. }
  830. var kind pointer.Kind
  831. switch state {
  832. case 0:
  833. w.pointerBtns &^= btn
  834. kind = pointer.Release
  835. // Move or resize gestures no longer applies.
  836. w.inCompositor = false
  837. case 1:
  838. w.pointerBtns |= btn
  839. kind = pointer.Press
  840. }
  841. w.flushScroll()
  842. w.resetFling()
  843. w.ProcessEvent(pointer.Event{
  844. Kind: kind,
  845. Source: pointer.Mouse,
  846. Buttons: w.pointerBtns,
  847. Position: w.lastPos,
  848. Time: time.Duration(t) * time.Millisecond,
  849. Modifiers: w.disp.xkb.Modifiers(),
  850. })
  851. }
  852. //export gio_onPointerAxis
  853. func gio_onPointerAxis(data unsafe.Pointer, p *C.struct_wl_pointer, t, axis C.uint32_t, value C.wl_fixed_t) {
  854. s := callbackLoad(data).(*wlSeat)
  855. w := s.pointerFocus
  856. v := fromFixed(value)
  857. w.resetFling()
  858. if w.scroll.dist == (f32.Point{}) {
  859. w.scroll.time = time.Duration(t) * time.Millisecond
  860. }
  861. switch axis {
  862. case C.WL_POINTER_AXIS_HORIZONTAL_SCROLL:
  863. w.scroll.dist.X += v
  864. case C.WL_POINTER_AXIS_VERTICAL_SCROLL:
  865. // horizontal scroll if shift + mousewheel(up/down) pressed.
  866. if w.disp.xkb.Modifiers() == key.ModShift {
  867. w.scroll.dist.X += v
  868. } else {
  869. w.scroll.dist.Y += v
  870. }
  871. }
  872. }
  873. //export gio_onPointerFrame
  874. func gio_onPointerFrame(data unsafe.Pointer, p *C.struct_wl_pointer) {
  875. s := callbackLoad(data).(*wlSeat)
  876. w := s.pointerFocus
  877. w.flushScroll()
  878. w.flushFling()
  879. }
  880. func (w *window) flushFling() {
  881. if !w.fling.start {
  882. return
  883. }
  884. w.fling.start = false
  885. estx, esty := w.fling.xExtrapolation.Estimate(), w.fling.yExtrapolation.Estimate()
  886. w.fling.xExtrapolation = fling.Extrapolation{}
  887. w.fling.yExtrapolation = fling.Extrapolation{}
  888. vel := float32(math.Sqrt(float64(estx.Velocity*estx.Velocity + esty.Velocity*esty.Velocity)))
  889. _, c := w.getConfig()
  890. if !w.fling.anim.Start(c, time.Now(), vel) {
  891. return
  892. }
  893. invDist := 1 / vel
  894. w.fling.dir.X = estx.Velocity * invDist
  895. w.fling.dir.Y = esty.Velocity * invDist
  896. }
  897. //export gio_onPointerAxisSource
  898. func gio_onPointerAxisSource(data unsafe.Pointer, pointer *C.struct_wl_pointer, source C.uint32_t) {
  899. }
  900. //export gio_onPointerAxisStop
  901. func gio_onPointerAxisStop(data unsafe.Pointer, p *C.struct_wl_pointer, t, axis C.uint32_t) {
  902. s := callbackLoad(data).(*wlSeat)
  903. w := s.pointerFocus
  904. w.fling.start = true
  905. }
  906. //export gio_onPointerAxisDiscrete
  907. func gio_onPointerAxisDiscrete(data unsafe.Pointer, p *C.struct_wl_pointer, axis C.uint32_t, discrete C.int32_t) {
  908. s := callbackLoad(data).(*wlSeat)
  909. w := s.pointerFocus
  910. w.resetFling()
  911. switch axis {
  912. case C.WL_POINTER_AXIS_HORIZONTAL_SCROLL:
  913. w.scroll.steps.X += int(discrete)
  914. case C.WL_POINTER_AXIS_VERTICAL_SCROLL:
  915. // horizontal scroll if shift + mousewheel(up/down) pressed.
  916. if w.disp.xkb.Modifiers() == key.ModShift {
  917. w.scroll.steps.X += int(discrete)
  918. } else {
  919. w.scroll.steps.Y += int(discrete)
  920. }
  921. }
  922. }
  923. func (w *window) ReadClipboard() {
  924. if w.disp.readClipClose != nil {
  925. return
  926. }
  927. w.disp.readClipClose = make(chan struct{})
  928. r, err := w.disp.readClipboard()
  929. if r == nil || err != nil {
  930. return
  931. }
  932. // Don't let slow clipboard transfers block event loop.
  933. go func() {
  934. defer r.Close()
  935. data, _ := io.ReadAll(r)
  936. e := transfer.DataEvent{
  937. Type: "application/text",
  938. Open: func() io.ReadCloser {
  939. return io.NopCloser(bytes.NewReader(data))
  940. },
  941. }
  942. select {
  943. case w.clipReads <- e:
  944. w.disp.wakeup()
  945. case <-w.disp.readClipClose:
  946. }
  947. }()
  948. }
  949. func (w *window) WriteClipboard(mime string, s []byte) {
  950. w.disp.writeClipboard(s)
  951. }
  952. func (w *window) Configure(options []Option) {
  953. _, cfg := w.getConfig()
  954. prev := w.config
  955. cnf := w.config
  956. cnf.apply(cfg, options)
  957. w.config.decoHeight = cnf.decoHeight
  958. switch cnf.Mode {
  959. case Fullscreen:
  960. switch prev.Mode {
  961. case Minimized, Fullscreen:
  962. default:
  963. w.config.Mode = Fullscreen
  964. w.wsize = w.config.Size
  965. C.xdg_toplevel_set_fullscreen(w.topLvl, nil)
  966. }
  967. case Minimized:
  968. switch prev.Mode {
  969. case Minimized, Fullscreen:
  970. default:
  971. w.config.Mode = Minimized
  972. C.xdg_toplevel_set_minimized(w.topLvl)
  973. }
  974. case Maximized:
  975. switch prev.Mode {
  976. case Minimized, Fullscreen:
  977. default:
  978. w.config.Mode = Maximized
  979. w.wsize = w.config.Size
  980. C.xdg_toplevel_set_maximized(w.topLvl)
  981. w.setTitle(prev, cnf)
  982. }
  983. case Windowed:
  984. switch prev.Mode {
  985. case Fullscreen:
  986. w.config.Mode = Windowed
  987. w.size = w.wsize.Div(w.scale)
  988. C.xdg_toplevel_unset_fullscreen(w.topLvl)
  989. case Minimized:
  990. w.config.Mode = Windowed
  991. case Maximized:
  992. w.config.Mode = Windowed
  993. w.size = w.wsize.Div(w.scale)
  994. C.xdg_toplevel_unset_maximized(w.topLvl)
  995. }
  996. w.setTitle(prev, cnf)
  997. if prev.Size != cnf.Size {
  998. w.config.Size = cnf.Size
  999. w.config.Size.Y += int(w.decoHeight()) * w.scale
  1000. w.size = w.config.Size.Div(w.scale)
  1001. }
  1002. w.config.MinSize = cnf.MinSize
  1003. w.config.MaxSize = cnf.MaxSize
  1004. w.setWindowConstraints()
  1005. }
  1006. w.ProcessEvent(ConfigEvent{Config: w.config})
  1007. }
  1008. func (w *window) setWindowConstraints() {
  1009. decoHeight := w.decoHeight()
  1010. if scaled := w.config.MinSize.Div(w.scale); scaled != (image.Point{}) {
  1011. C.xdg_toplevel_set_min_size(w.topLvl, C.int32_t(scaled.X), C.int32_t(scaled.Y+decoHeight))
  1012. }
  1013. if scaled := w.config.MaxSize.Div(w.scale); scaled != (image.Point{}) {
  1014. C.xdg_toplevel_set_max_size(w.topLvl, C.int32_t(scaled.X), C.int32_t(scaled.Y+decoHeight))
  1015. }
  1016. }
  1017. // decoHeight returns the adjustment for client-side decorations, if applicable.
  1018. // The unit is in surface-local coordinates.
  1019. func (w *window) decoHeight() int {
  1020. if !w.config.Decorated {
  1021. return int(w.config.decoHeight)
  1022. }
  1023. return 0
  1024. }
  1025. func (w *window) setTitle(prev, cnf Config) {
  1026. if prev.Title != cnf.Title {
  1027. w.config.Title = cnf.Title
  1028. title := C.CString(cnf.Title)
  1029. C.xdg_toplevel_set_title(w.topLvl, title)
  1030. C.free(unsafe.Pointer(title))
  1031. }
  1032. }
  1033. func (w *window) Perform(actions system.Action) {
  1034. // NB. there is no way for a minimized window to be unminimized.
  1035. // https://wayland.app/protocols/xdg-shell#xdg_toplevel:request:set_minimized
  1036. walkActions(actions, func(action system.Action) {
  1037. switch action {
  1038. case system.ActionClose:
  1039. w.closing = true
  1040. }
  1041. })
  1042. }
  1043. func (w *window) move(serial C.uint32_t) {
  1044. s := w.seat
  1045. if !w.inCompositor && s != nil {
  1046. w.inCompositor = true
  1047. C.xdg_toplevel_move(w.topLvl, s.seat, serial)
  1048. }
  1049. }
  1050. func (w *window) resize(serial, edge C.uint32_t) {
  1051. s := w.seat
  1052. if w.inCompositor || s == nil {
  1053. return
  1054. }
  1055. w.inCompositor = true
  1056. C.xdg_toplevel_resize(w.topLvl, s.seat, serial, edge)
  1057. }
  1058. func (w *window) SetCursor(cursor pointer.Cursor) {
  1059. w.cursor.cursor = w.loadCursor(cursor)
  1060. w.updateCursor()
  1061. }
  1062. func (w *window) updateCursor() {
  1063. ptr := w.disp.seat.pointer
  1064. if ptr == nil {
  1065. return
  1066. }
  1067. w.setCursor(ptr, w.serial)
  1068. }
  1069. func (w *window) setCursor(pointer *C.struct_wl_pointer, serial C.uint32_t) {
  1070. c := w.cursor.system
  1071. if c == nil {
  1072. c = w.cursor.cursor
  1073. }
  1074. if c == nil {
  1075. C.wl_pointer_set_cursor(pointer, w.serial, nil, 0, 0)
  1076. return
  1077. }
  1078. // Get images[0].
  1079. img := *c.images
  1080. buf := C.wl_cursor_image_get_buffer(img)
  1081. if buf == nil {
  1082. return
  1083. }
  1084. C.wl_pointer_set_cursor(pointer, serial, w.cursor.surf, C.int32_t(img.hotspot_x/C.uint(w.scale)), C.int32_t(img.hotspot_y/C.uint(w.scale)))
  1085. C.wl_surface_attach(w.cursor.surf, buf, 0, 0)
  1086. C.wl_surface_damage(w.cursor.surf, 0, 0, C.int32_t(img.width), C.int32_t(img.height))
  1087. C.wl_surface_commit(w.cursor.surf)
  1088. }
  1089. func (w *window) resetFling() {
  1090. w.fling.start = false
  1091. w.fling.anim = fling.Animation{}
  1092. }
  1093. //export gio_onKeyboardKeymap
  1094. func gio_onKeyboardKeymap(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, format C.uint32_t, fd C.int32_t, size C.uint32_t) {
  1095. defer syscall.Close(int(fd))
  1096. s := callbackLoad(data).(*wlSeat)
  1097. s.disp.repeat.Stop(0)
  1098. s.disp.xkb.DestroyKeymapState()
  1099. if format != C.WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 {
  1100. return
  1101. }
  1102. if err := s.disp.xkb.LoadKeymap(int(format), int(fd), int(size)); err != nil {
  1103. // TODO: Do better.
  1104. panic(err)
  1105. }
  1106. }
  1107. //export gio_onKeyboardEnter
  1108. func gio_onKeyboardEnter(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial C.uint32_t, surf *C.struct_wl_surface, keys *C.struct_wl_array) {
  1109. s := callbackLoad(data).(*wlSeat)
  1110. s.serial = serial
  1111. w := callbackLoad(unsafe.Pointer(surf)).(*window)
  1112. s.keyboardFocus = w
  1113. s.disp.repeat.Stop(0)
  1114. w.config.Focused = true
  1115. w.ProcessEvent(ConfigEvent{Config: w.config})
  1116. }
  1117. //export gio_onKeyboardLeave
  1118. func gio_onKeyboardLeave(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial C.uint32_t, surf *C.struct_wl_surface) {
  1119. s := callbackLoad(data).(*wlSeat)
  1120. s.serial = serial
  1121. s.disp.repeat.Stop(0)
  1122. w := s.keyboardFocus
  1123. w.config.Focused = false
  1124. w.ProcessEvent(ConfigEvent{Config: w.config})
  1125. }
  1126. //export gio_onKeyboardKey
  1127. func gio_onKeyboardKey(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial, timestamp, keyCode, state C.uint32_t) {
  1128. s := callbackLoad(data).(*wlSeat)
  1129. s.serial = serial
  1130. w := s.keyboardFocus
  1131. t := time.Duration(timestamp) * time.Millisecond
  1132. s.disp.repeat.Stop(t)
  1133. w.resetFling()
  1134. kc := mapXKBKeycode(uint32(keyCode))
  1135. ks := mapXKBKeyState(uint32(state))
  1136. for _, e := range w.disp.xkb.DispatchKey(kc, ks) {
  1137. if ee, ok := e.(key.EditEvent); ok {
  1138. // There's no support for IME yet.
  1139. w.w.EditorInsert(ee.Text)
  1140. } else {
  1141. w.ProcessEvent(e)
  1142. }
  1143. }
  1144. if state != C.WL_KEYBOARD_KEY_STATE_PRESSED {
  1145. return
  1146. }
  1147. if w.disp.xkb.IsRepeatKey(kc) {
  1148. w.disp.repeat.Start(w, kc, t)
  1149. }
  1150. }
  1151. func mapXKBKeycode(keyCode uint32) uint32 {
  1152. // According to the xkb_v1 spec: "to determine the xkb keycode, clients must add 8 to the key event keycode."
  1153. return keyCode + 8
  1154. }
  1155. func mapXKBKeyState(state uint32) key.State {
  1156. switch state {
  1157. case C.WL_KEYBOARD_KEY_STATE_RELEASED:
  1158. return key.Release
  1159. default:
  1160. return key.Press
  1161. }
  1162. }
  1163. func (r *repeatState) Start(w *window, keyCode uint32, t time.Duration) {
  1164. if r.rate <= 0 {
  1165. return
  1166. }
  1167. stopC := make(chan struct{})
  1168. r.start = t
  1169. r.last = 0
  1170. r.now = 0
  1171. r.stopC = stopC
  1172. r.key = keyCode
  1173. r.win = w
  1174. rate, delay := r.rate, r.delay
  1175. go func() {
  1176. timer := time.NewTimer(delay)
  1177. for {
  1178. select {
  1179. case <-timer.C:
  1180. case <-stopC:
  1181. close(stopC)
  1182. return
  1183. }
  1184. r.Advance(delay)
  1185. w.disp.wakeup()
  1186. delay = time.Second / time.Duration(rate)
  1187. timer.Reset(delay)
  1188. }
  1189. }()
  1190. }
  1191. func (r *repeatState) Stop(t time.Duration) {
  1192. if r.stopC == nil {
  1193. return
  1194. }
  1195. r.stopC <- struct{}{}
  1196. <-r.stopC
  1197. r.stopC = nil
  1198. t -= r.start
  1199. if r.now > t {
  1200. r.now = t
  1201. }
  1202. }
  1203. func (r *repeatState) Advance(dt time.Duration) {
  1204. r.mu.Lock()
  1205. defer r.mu.Unlock()
  1206. r.now += dt
  1207. }
  1208. func (r *repeatState) Repeat(d *wlDisplay) {
  1209. if r.rate <= 0 {
  1210. return
  1211. }
  1212. r.mu.Lock()
  1213. now := r.now
  1214. r.mu.Unlock()
  1215. for {
  1216. var delay time.Duration
  1217. if r.last < r.delay {
  1218. delay = r.delay
  1219. } else {
  1220. delay = time.Second / time.Duration(r.rate)
  1221. }
  1222. if r.last+delay > now {
  1223. break
  1224. }
  1225. for _, e := range d.xkb.DispatchKey(r.key, key.Press) {
  1226. if ee, ok := e.(key.EditEvent); ok {
  1227. // There's no support for IME yet.
  1228. r.win.w.EditorInsert(ee.Text)
  1229. } else {
  1230. r.win.ProcessEvent(e)
  1231. }
  1232. }
  1233. r.last += delay
  1234. }
  1235. }
  1236. //export gio_onFrameDone
  1237. func gio_onFrameDone(data unsafe.Pointer, callback *C.struct_wl_callback, t C.uint32_t) {
  1238. C.wl_callback_destroy(callback)
  1239. w := callbackLoad(data).(*window)
  1240. if w.lastFrameCallback == callback {
  1241. w.lastFrameCallback = nil
  1242. w.draw(false)
  1243. }
  1244. }
  1245. func (w *window) close(err error) {
  1246. w.ProcessEvent(WaylandViewEvent{})
  1247. w.ProcessEvent(DestroyEvent{Err: err})
  1248. w.destroy()
  1249. w.disp.destroy()
  1250. w.disp = nil
  1251. }
  1252. func (w *window) dispatch() {
  1253. if w.disp == nil {
  1254. <-w.wakeups
  1255. w.w.Invalidate()
  1256. return
  1257. }
  1258. if err := w.disp.dispatch(); err != nil || w.closing {
  1259. w.close(err)
  1260. return
  1261. }
  1262. select {
  1263. case e := <-w.clipReads:
  1264. w.disp.readClipClose = nil
  1265. w.ProcessEvent(e)
  1266. case <-w.wakeups:
  1267. w.w.Invalidate()
  1268. default:
  1269. }
  1270. }
  1271. func (w *window) ProcessEvent(e event.Event) {
  1272. w.w.ProcessEvent(e)
  1273. }
  1274. func (w *window) Event() event.Event {
  1275. for {
  1276. evt, ok := w.w.nextEvent()
  1277. if !ok {
  1278. w.dispatch()
  1279. continue
  1280. }
  1281. return evt
  1282. }
  1283. }
  1284. func (w *window) Invalidate() {
  1285. select {
  1286. case w.wakeups <- struct{}{}:
  1287. default:
  1288. return
  1289. }
  1290. w.disp.wakeup()
  1291. }
  1292. func (w *window) Run(f func()) {
  1293. f()
  1294. }
  1295. func (w *window) Frame(frame *op.Ops) {
  1296. w.w.ProcessFrame(frame, nil)
  1297. }
  1298. // bindDataDevice initializes the dataDev field if and only if both
  1299. // the seat and dataDeviceManager fields are initialized.
  1300. func (d *wlDisplay) bindDataDevice() {
  1301. if d.seat != nil && d.dataDeviceManager != nil {
  1302. d.seat.dataDev = C.wl_data_device_manager_get_data_device(d.dataDeviceManager, d.seat.seat)
  1303. if d.seat.dataDev == nil {
  1304. return
  1305. }
  1306. callbackStore(unsafe.Pointer(d.seat.dataDev), d.seat)
  1307. C.wl_data_device_add_listener(d.seat.dataDev, &C.gio_data_device_listener, unsafe.Pointer(d.seat.dataDev))
  1308. }
  1309. }
  1310. func (d *wlDisplay) dispatch() error {
  1311. // wl_display_prepare_read records the current thread for
  1312. // use in wl_display_read_events or wl_display_cancel_events.
  1313. runtime.LockOSThread()
  1314. defer runtime.UnlockOSThread()
  1315. dispfd := C.wl_display_get_fd(d.disp)
  1316. // Poll for events and notifications.
  1317. pollfds := append(d.poller.pollfds[:0],
  1318. syscall.PollFd{Fd: int32(dispfd), Events: syscall.POLLIN | syscall.POLLERR},
  1319. syscall.PollFd{Fd: int32(d.notify.read), Events: syscall.POLLIN | syscall.POLLERR},
  1320. )
  1321. for C.wl_display_prepare_read(d.disp) != 0 {
  1322. C.wl_display_dispatch_pending(d.disp)
  1323. }
  1324. dispFd := &pollfds[0]
  1325. if ret, err := C.wl_display_flush(d.disp); ret < 0 {
  1326. if err != syscall.EAGAIN {
  1327. return fmt.Errorf("wayland: wl_display_flush failed: %v", err)
  1328. }
  1329. // EAGAIN means the output buffer was full. Poll for
  1330. // POLLOUT to know when we can write again.
  1331. dispFd.Events |= syscall.POLLOUT
  1332. }
  1333. if _, err := syscall.Poll(pollfds, -1); err != nil && err != syscall.EINTR {
  1334. C.wl_display_cancel_read(d.disp)
  1335. return fmt.Errorf("wayland: poll failed: %v", err)
  1336. }
  1337. if dispFd.Revents&(syscall.POLLERR|syscall.POLLHUP) != 0 {
  1338. C.wl_display_cancel_read(d.disp)
  1339. return errors.New("wayland: display file descriptor gone")
  1340. }
  1341. // Handle events.
  1342. if dispFd.Revents&syscall.POLLIN != 0 {
  1343. if ret, err := C.wl_display_read_events(d.disp); ret < 0 {
  1344. return fmt.Errorf("wayland: wl_display_read_events failed: %v", err)
  1345. }
  1346. C.wl_display_dispatch_pending(d.disp)
  1347. } else {
  1348. C.wl_display_cancel_read(d.disp)
  1349. }
  1350. // Clear notifications.
  1351. for {
  1352. _, err := syscall.Read(d.notify.read, d.poller.buf[:])
  1353. if err == syscall.EAGAIN {
  1354. break
  1355. }
  1356. if err != nil {
  1357. return fmt.Errorf("wayland: read from notify pipe failed: %v", err)
  1358. }
  1359. }
  1360. d.repeat.Repeat(d)
  1361. return nil
  1362. }
  1363. func (w *window) SetAnimating(anim bool) {
  1364. w.animating = anim
  1365. if anim {
  1366. w.draw(false)
  1367. }
  1368. }
  1369. // Wakeup wakes up the event loop through the notification pipe.
  1370. func (d *wlDisplay) wakeup() {
  1371. oneByte := make([]byte, 1)
  1372. if _, err := syscall.Write(d.notify.write, oneByte); err != nil && err != syscall.EAGAIN {
  1373. panic(fmt.Errorf("failed to write to pipe: %v", err))
  1374. }
  1375. }
  1376. func (w *window) destroy() {
  1377. if w.lastFrameCallback != nil {
  1378. C.wl_callback_destroy(w.lastFrameCallback)
  1379. w.lastFrameCallback = nil
  1380. }
  1381. if w.cursor.surf != nil {
  1382. C.wl_surface_destroy(w.cursor.surf)
  1383. }
  1384. if w.cursor.theme != nil {
  1385. C.wl_cursor_theme_destroy(w.cursor.theme)
  1386. }
  1387. if w.topLvl != nil {
  1388. C.xdg_toplevel_destroy(w.topLvl)
  1389. }
  1390. if w.surf != nil {
  1391. C.wl_surface_destroy(w.surf)
  1392. }
  1393. if w.wmSurf != nil {
  1394. C.xdg_surface_destroy(w.wmSurf)
  1395. }
  1396. if w.decor != nil {
  1397. C.zxdg_toplevel_decoration_v1_destroy(w.decor)
  1398. }
  1399. callbackDelete(unsafe.Pointer(w.surf))
  1400. }
  1401. //export gio_onKeyboardModifiers
  1402. func gio_onKeyboardModifiers(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, serial, depressed, latched, locked, group C.uint32_t) {
  1403. s := callbackLoad(data).(*wlSeat)
  1404. s.serial = serial
  1405. d := s.disp
  1406. d.repeat.Stop(0)
  1407. if d.xkb == nil {
  1408. return
  1409. }
  1410. d.xkb.UpdateMask(uint32(depressed), uint32(latched), uint32(locked), uint32(group), uint32(group), uint32(group))
  1411. }
  1412. //export gio_onKeyboardRepeatInfo
  1413. func gio_onKeyboardRepeatInfo(data unsafe.Pointer, keyboard *C.struct_wl_keyboard, rate, delay C.int32_t) {
  1414. s := callbackLoad(data).(*wlSeat)
  1415. d := s.disp
  1416. d.repeat.Stop(0)
  1417. d.repeat.rate = int(rate)
  1418. d.repeat.delay = time.Duration(delay) * time.Millisecond
  1419. }
  1420. //export gio_onTextInputEnter
  1421. func gio_onTextInputEnter(data unsafe.Pointer, im *C.struct_zwp_text_input_v3, surf *C.struct_wl_surface) {
  1422. }
  1423. //export gio_onTextInputLeave
  1424. func gio_onTextInputLeave(data unsafe.Pointer, im *C.struct_zwp_text_input_v3, surf *C.struct_wl_surface) {
  1425. }
  1426. //export gio_onTextInputPreeditString
  1427. func gio_onTextInputPreeditString(data unsafe.Pointer, im *C.struct_zwp_text_input_v3, ctxt *C.char, begin, end C.int32_t) {
  1428. }
  1429. //export gio_onTextInputCommitString
  1430. func gio_onTextInputCommitString(data unsafe.Pointer, im *C.struct_zwp_text_input_v3, ctxt *C.char) {
  1431. }
  1432. //export gio_onTextInputDeleteSurroundingText
  1433. func gio_onTextInputDeleteSurroundingText(data unsafe.Pointer, im *C.struct_zwp_text_input_v3, before, after C.uint32_t) {
  1434. }
  1435. //export gio_onTextInputDone
  1436. func gio_onTextInputDone(data unsafe.Pointer, im *C.struct_zwp_text_input_v3, serial C.uint32_t) {
  1437. s := callbackLoad(data).(*wlSeat)
  1438. s.serial = serial
  1439. }
  1440. //export gio_onDataSourceTarget
  1441. func gio_onDataSourceTarget(data unsafe.Pointer, source *C.struct_wl_data_source, mime *C.char) {
  1442. }
  1443. //export gio_onDataSourceSend
  1444. func gio_onDataSourceSend(data unsafe.Pointer, source *C.struct_wl_data_source, mime *C.char, fd C.int32_t) {
  1445. s := callbackLoad(data).(*wlSeat)
  1446. content := s.content
  1447. go func() {
  1448. defer syscall.Close(int(fd))
  1449. syscall.Write(int(fd), content)
  1450. }()
  1451. }
  1452. //export gio_onDataSourceCancelled
  1453. func gio_onDataSourceCancelled(data unsafe.Pointer, source *C.struct_wl_data_source) {
  1454. s := callbackLoad(data).(*wlSeat)
  1455. if s.source == source {
  1456. s.content = nil
  1457. s.source = nil
  1458. }
  1459. C.wl_data_source_destroy(source)
  1460. }
  1461. //export gio_onDataSourceDNDDropPerformed
  1462. func gio_onDataSourceDNDDropPerformed(data unsafe.Pointer, source *C.struct_wl_data_source) {
  1463. }
  1464. //export gio_onDataSourceDNDFinished
  1465. func gio_onDataSourceDNDFinished(data unsafe.Pointer, source *C.struct_wl_data_source) {
  1466. }
  1467. //export gio_onDataSourceAction
  1468. func gio_onDataSourceAction(data unsafe.Pointer, source *C.struct_wl_data_source, act C.uint32_t) {
  1469. }
  1470. func (w *window) flushScroll() {
  1471. var fling f32.Point
  1472. if w.fling.anim.Active() {
  1473. dist := float32(w.fling.anim.Tick(time.Now()))
  1474. fling = w.fling.dir.Mul(dist)
  1475. }
  1476. // The Wayland reported scroll distance for
  1477. // discrete scroll axes is only 10 pixels, where
  1478. // 100 seems more appropriate.
  1479. const discreteScale = 10
  1480. if w.scroll.steps.X != 0 {
  1481. w.scroll.dist.X *= discreteScale
  1482. }
  1483. if w.scroll.steps.Y != 0 {
  1484. w.scroll.dist.Y *= discreteScale
  1485. }
  1486. total := w.scroll.dist.Add(fling)
  1487. if total == (f32.Point{}) {
  1488. return
  1489. }
  1490. if w.scroll.steps == (image.Point{}) {
  1491. w.fling.xExtrapolation.SampleDelta(w.scroll.time, -w.scroll.dist.X)
  1492. w.fling.yExtrapolation.SampleDelta(w.scroll.time, -w.scroll.dist.Y)
  1493. }
  1494. // Zero scroll distance prior to calling ProcessEvent, otherwise we may recursively
  1495. // re-process the scroll distance.
  1496. w.scroll.dist = f32.Point{}
  1497. w.scroll.steps = image.Point{}
  1498. w.ProcessEvent(pointer.Event{
  1499. Kind: pointer.Scroll,
  1500. Source: pointer.Mouse,
  1501. Buttons: w.pointerBtns,
  1502. Position: w.lastPos,
  1503. Scroll: total,
  1504. Time: w.scroll.time,
  1505. Modifiers: w.disp.xkb.Modifiers(),
  1506. })
  1507. }
  1508. func (w *window) onPointerMotion(x, y C.wl_fixed_t, t C.uint32_t) {
  1509. w.flushScroll()
  1510. w.lastPos = f32.Point{
  1511. X: fromFixed(x) * float32(w.scale),
  1512. Y: fromFixed(y) * float32(w.scale),
  1513. }
  1514. w.ProcessEvent(pointer.Event{
  1515. Kind: pointer.Move,
  1516. Position: w.lastPos,
  1517. Buttons: w.pointerBtns,
  1518. Source: pointer.Mouse,
  1519. Time: time.Duration(t) * time.Millisecond,
  1520. Modifiers: w.disp.xkb.Modifiers(),
  1521. })
  1522. c, _ := w.systemGesture()
  1523. if c != w.cursor.system {
  1524. w.cursor.system = c
  1525. w.updateCursor()
  1526. }
  1527. }
  1528. // updateCursor updates the system gesture cursor according to the pointer
  1529. // position.
  1530. func (w *window) systemGesture() (*C.struct_wl_cursor, C.uint32_t) {
  1531. if w.config.Mode != Windowed || w.config.Decorated {
  1532. return nil, 0
  1533. }
  1534. _, cfg := w.getConfig()
  1535. border := cfg.Dp(3)
  1536. x, y, size := int(w.lastPos.X), int(w.lastPos.Y), w.config.Size
  1537. north := y <= border
  1538. south := y >= size.Y-border
  1539. west := x <= border
  1540. east := x >= size.X-border
  1541. switch {
  1542. default:
  1543. fallthrough
  1544. case !north && !south && !west && !east:
  1545. return nil, 0
  1546. case north && west:
  1547. return w.cursor.cursors.resizeNorthWest, C.XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT
  1548. case north && east:
  1549. return w.cursor.cursors.resizeNorthEast, C.XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT
  1550. case south && west:
  1551. return w.cursor.cursors.resizeSouthWest, C.XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT
  1552. case south && east:
  1553. return w.cursor.cursors.resizeSouthEast, C.XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT
  1554. case north:
  1555. return w.cursor.cursors.resizeNorth, C.XDG_TOPLEVEL_RESIZE_EDGE_TOP
  1556. case south:
  1557. return w.cursor.cursors.resizeSouth, C.XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM
  1558. case west:
  1559. return w.cursor.cursors.resizeWest, C.XDG_TOPLEVEL_RESIZE_EDGE_LEFT
  1560. case east:
  1561. return w.cursor.cursors.resizeEast, C.XDG_TOPLEVEL_RESIZE_EDGE_RIGHT
  1562. }
  1563. }
  1564. func (w *window) updateOpaqueRegion() {
  1565. reg := C.wl_compositor_create_region(w.disp.compositor)
  1566. C.wl_region_add(reg, 0, 0, C.int32_t(w.size.X), C.int32_t(w.size.Y))
  1567. C.wl_surface_set_opaque_region(w.surf, reg)
  1568. C.wl_region_destroy(reg)
  1569. }
  1570. func (w *window) updateOutputs() {
  1571. scale := 1
  1572. var found bool
  1573. for _, conf := range w.disp.outputConfig {
  1574. for _, w2 := range conf.windows {
  1575. if w2 == w {
  1576. found = true
  1577. if conf.scale > scale {
  1578. scale = conf.scale
  1579. }
  1580. }
  1581. }
  1582. }
  1583. if found && scale != w.scale {
  1584. w.scale = scale
  1585. C.wl_surface_set_buffer_scale(w.surf, C.int32_t(w.scale))
  1586. w.draw(true)
  1587. }
  1588. if found {
  1589. w.draw(true)
  1590. }
  1591. }
  1592. func (w *window) getConfig() (image.Point, unit.Metric) {
  1593. size := w.size.Mul(w.scale)
  1594. return size, unit.Metric{
  1595. PxPerDp: w.ppdp * float32(w.scale),
  1596. PxPerSp: w.ppsp * float32(w.scale),
  1597. }
  1598. }
  1599. func (w *window) draw(sync bool) {
  1600. if !w.configured {
  1601. return
  1602. }
  1603. w.flushScroll()
  1604. size, cfg := w.getConfig()
  1605. if cfg == (unit.Metric{}) {
  1606. return
  1607. }
  1608. if size != w.config.Size {
  1609. w.config.Size = size
  1610. w.ProcessEvent(ConfigEvent{Config: w.config})
  1611. }
  1612. anim := w.animating || w.fling.anim.Active()
  1613. // Draw animation only when not waiting for frame callback.
  1614. redrawAnim := anim && w.lastFrameCallback == nil
  1615. if !redrawAnim && !sync {
  1616. return
  1617. }
  1618. if anim {
  1619. w.lastFrameCallback = C.wl_surface_frame(w.surf)
  1620. // Use the surface as listener data for gio_onFrameDone.
  1621. C.wl_callback_add_listener(w.lastFrameCallback, &C.gio_callback_listener, unsafe.Pointer(w.surf))
  1622. }
  1623. w.ProcessEvent(frameEvent{
  1624. FrameEvent: FrameEvent{
  1625. Now: time.Now(),
  1626. Size: w.config.Size,
  1627. Metric: cfg,
  1628. },
  1629. Sync: sync,
  1630. })
  1631. }
  1632. func (w *window) display() *C.struct_wl_display {
  1633. return w.disp.disp
  1634. }
  1635. func (w *window) surface() (*C.struct_wl_surface, int, int) {
  1636. sz, _ := w.getConfig()
  1637. return w.surf, sz.X, sz.Y
  1638. }
  1639. func (w *window) ShowTextInput(show bool) {}
  1640. func (w *window) SetInputHint(_ key.InputHint) {}
  1641. func (w *window) EditorStateChanged(old, new editorState) {}
  1642. func (w *window) NewContext() (context, error) {
  1643. var firstErr error
  1644. if f := newWaylandEGLContext; f != nil {
  1645. c, err := f(w)
  1646. if err == nil {
  1647. return c, nil
  1648. }
  1649. firstErr = err
  1650. }
  1651. if f := newWaylandVulkanContext; f != nil {
  1652. c, err := f(w)
  1653. if err == nil {
  1654. return c, nil
  1655. }
  1656. firstErr = err
  1657. }
  1658. if firstErr != nil {
  1659. return nil, firstErr
  1660. }
  1661. return nil, errors.New("wayland: no available GPU backends")
  1662. }
  1663. // detectUIScale reports the system UI scale, or 1.0 if it fails.
  1664. func detectUIScale() float32 {
  1665. // TODO: What about other window environments?
  1666. out, err := exec.Command("gsettings", "get", "org.gnome.desktop.interface", "text-scaling-factor").Output()
  1667. if err != nil {
  1668. return 1.0
  1669. }
  1670. scale, err := strconv.ParseFloat(string(bytes.TrimSpace(out)), 32)
  1671. if err != nil {
  1672. return 1.0
  1673. }
  1674. return float32(scale)
  1675. }
  1676. func newWLDisplay() (*wlDisplay, error) {
  1677. d := &wlDisplay{
  1678. outputMap: make(map[C.uint32_t]*C.struct_wl_output),
  1679. outputConfig: make(map[*C.struct_wl_output]*wlOutput),
  1680. }
  1681. pipe := make([]int, 2)
  1682. if err := syscall.Pipe2(pipe, syscall.O_NONBLOCK|syscall.O_CLOEXEC); err != nil {
  1683. return nil, fmt.Errorf("wayland: failed to create pipe: %v", err)
  1684. }
  1685. d.notify.read = pipe[0]
  1686. d.notify.write = pipe[1]
  1687. xkb, err := xkb.New()
  1688. if err != nil {
  1689. d.destroy()
  1690. return nil, fmt.Errorf("wayland: %v", err)
  1691. }
  1692. d.xkb = xkb
  1693. d.disp, err = C.wl_display_connect(nil)
  1694. if d.disp == nil {
  1695. d.destroy()
  1696. return nil, fmt.Errorf("wayland: wl_display_connect failed: %v", err)
  1697. }
  1698. callbackMap.Store(unsafe.Pointer(d.disp), d)
  1699. d.reg = C.wl_display_get_registry(d.disp)
  1700. if d.reg == nil {
  1701. d.destroy()
  1702. return nil, errors.New("wayland: wl_display_get_registry failed")
  1703. }
  1704. C.wl_registry_add_listener(d.reg, &C.gio_registry_listener, unsafe.Pointer(d.disp))
  1705. // Wait for the server to register all its globals to the
  1706. // registry listener (gio_onRegistryGlobal).
  1707. C.wl_display_roundtrip(d.disp)
  1708. // Configuration listeners are added to outputs by gio_onRegistryGlobal.
  1709. // We need another roundtrip to get the initial output configurations
  1710. // through the gio_onOutput* callbacks.
  1711. C.wl_display_roundtrip(d.disp)
  1712. return d, nil
  1713. }
  1714. func (d *wlDisplay) destroy() {
  1715. if d.readClipClose != nil {
  1716. close(d.readClipClose)
  1717. d.readClipClose = nil
  1718. }
  1719. if d.notify.write != 0 {
  1720. syscall.Close(d.notify.write)
  1721. d.notify.write = 0
  1722. }
  1723. if d.notify.read != 0 {
  1724. syscall.Close(d.notify.read)
  1725. d.notify.read = 0
  1726. }
  1727. d.repeat.Stop(0)
  1728. if d.xkb != nil {
  1729. d.xkb.Destroy()
  1730. d.xkb = nil
  1731. }
  1732. if d.seat != nil {
  1733. d.seat.destroy()
  1734. d.seat = nil
  1735. }
  1736. if d.imm != nil {
  1737. C.zwp_text_input_manager_v3_destroy(d.imm)
  1738. }
  1739. if d.decor != nil {
  1740. C.zxdg_decoration_manager_v1_destroy(d.decor)
  1741. }
  1742. if d.shm != nil {
  1743. C.wl_shm_destroy(d.shm)
  1744. }
  1745. if d.compositor != nil {
  1746. C.wl_compositor_destroy(d.compositor)
  1747. }
  1748. if d.wm != nil {
  1749. C.xdg_wm_base_destroy(d.wm)
  1750. }
  1751. for _, output := range d.outputMap {
  1752. C.wl_output_destroy(output)
  1753. }
  1754. if d.reg != nil {
  1755. C.wl_registry_destroy(d.reg)
  1756. }
  1757. if d.disp != nil {
  1758. C.wl_display_disconnect(d.disp)
  1759. callbackDelete(unsafe.Pointer(d.disp))
  1760. d.disp = nil
  1761. }
  1762. }
  1763. // fromFixed converts a Wayland wl_fixed_t 23.8 number to float32.
  1764. func fromFixed(v C.wl_fixed_t) float32 {
  1765. // Convert to float64 to avoid overflow.
  1766. // From wayland-util.h.
  1767. b := ((1023 + 44) << 52) + (1 << 51) + uint64(v)
  1768. f := math.Float64frombits(b) - (3 << 43)
  1769. return float32(f)
  1770. }