window_desktop.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804
  1. //go:build !js && !wasm && !test_web_driver
  2. // +build !js,!wasm,!test_web_driver
  3. package glfw
  4. import (
  5. "bytes"
  6. "context"
  7. "image"
  8. _ "image/png" // for the icon
  9. "runtime"
  10. "sync"
  11. "fyne.io/fyne/v2"
  12. "fyne.io/fyne/v2/canvas"
  13. "fyne.io/fyne/v2/driver/desktop"
  14. "fyne.io/fyne/v2/internal/driver/common"
  15. "fyne.io/fyne/v2/internal/painter"
  16. "fyne.io/fyne/v2/internal/painter/gl"
  17. "fyne.io/fyne/v2/internal/scale"
  18. "fyne.io/fyne/v2/internal/svg"
  19. "fyne.io/fyne/v2/storage"
  20. "github.com/go-gl/glfw/v3.3/glfw"
  21. )
  22. const defaultTitle = "Fyne Application"
  23. // Input modes.
  24. const (
  25. CursorMode glfw.InputMode = glfw.CursorMode
  26. StickyKeysMode glfw.InputMode = glfw.StickyKeysMode
  27. StickyMouseButtonsMode glfw.InputMode = glfw.StickyMouseButtonsMode
  28. LockKeyMods glfw.InputMode = glfw.LockKeyMods
  29. RawMouseMotion glfw.InputMode = glfw.RawMouseMotion
  30. )
  31. // Cursor mode values.
  32. const (
  33. CursorNormal int = glfw.CursorNormal
  34. CursorHidden int = glfw.CursorHidden
  35. CursorDisabled int = glfw.CursorDisabled
  36. )
  37. var cursorMap map[desktop.StandardCursor]*glfw.Cursor
  38. func initCursors() {
  39. cursorMap = map[desktop.StandardCursor]*glfw.Cursor{
  40. desktop.DefaultCursor: glfw.CreateStandardCursor(glfw.ArrowCursor),
  41. desktop.TextCursor: glfw.CreateStandardCursor(glfw.IBeamCursor),
  42. desktop.CrosshairCursor: glfw.CreateStandardCursor(glfw.CrosshairCursor),
  43. desktop.PointerCursor: glfw.CreateStandardCursor(glfw.HandCursor),
  44. desktop.HResizeCursor: glfw.CreateStandardCursor(glfw.HResizeCursor),
  45. desktop.VResizeCursor: glfw.CreateStandardCursor(glfw.VResizeCursor),
  46. desktop.HiddenCursor: nil,
  47. }
  48. }
  49. // Declare conformity to Window interface
  50. var _ fyne.Window = (*window)(nil)
  51. type window struct {
  52. common.Window
  53. viewport *glfw.Window
  54. viewLock sync.RWMutex
  55. createLock sync.Once
  56. decorate bool
  57. closing bool
  58. fixedSize bool
  59. cursor desktop.Cursor
  60. customCursor *glfw.Cursor
  61. canvas *glCanvas
  62. driver *gLDriver
  63. title string
  64. icon fyne.Resource
  65. mainmenu *fyne.MainMenu
  66. clipboard fyne.Clipboard
  67. master bool
  68. fullScreen bool
  69. centered bool
  70. visible bool
  71. mouseLock sync.RWMutex
  72. mousePos fyne.Position
  73. mouseDragged fyne.Draggable
  74. mouseDraggedObjStart fyne.Position
  75. mouseDraggedOffset fyne.Position
  76. mouseDragPos fyne.Position
  77. mouseDragStarted bool
  78. mouseButton desktop.MouseButton
  79. mouseOver desktop.Hoverable
  80. mouseLastClick fyne.CanvasObject
  81. mousePressed fyne.CanvasObject
  82. mouseClickCount int
  83. mouseCancelFunc context.CancelFunc
  84. onClosed func()
  85. onCloseIntercepted func()
  86. menuTogglePending fyne.KeyName
  87. menuDeactivationPending fyne.KeyName
  88. xpos, ypos int
  89. width, height int
  90. requestedWidth, requestedHeight int
  91. shouldWidth, shouldHeight int
  92. shouldExpand bool
  93. pending []func()
  94. }
  95. func (w *window) SetFullScreen(full bool) {
  96. w.fullScreen = full
  97. if !w.visible {
  98. return
  99. }
  100. runOnMain(func() {
  101. monitor := w.getMonitorForWindow()
  102. mode := monitor.GetVideoMode()
  103. if full {
  104. w.viewport.SetMonitor(monitor, 0, 0, mode.Width, mode.Height, mode.RefreshRate)
  105. } else {
  106. if w.width == 0 && w.height == 0 { // if we were fullscreen on creation...
  107. w.width, w.height = w.screenSize(w.canvas.Size())
  108. }
  109. w.viewport.SetMonitor(nil, w.xpos, w.ypos, w.width, w.height, 0)
  110. }
  111. })
  112. }
  113. func (w *window) CenterOnScreen() {
  114. w.centered = true
  115. if w.view() != nil {
  116. runOnMain(w.doCenterOnScreen)
  117. }
  118. }
  119. func (w *window) SetOnDropped(dropped func(pos fyne.Position, items []fyne.URI)) {
  120. w.runOnMainWhenCreated(func() {
  121. w.viewport.SetDropCallback(func(win *glfw.Window, names []string) {
  122. if dropped == nil {
  123. return
  124. }
  125. uris := make([]fyne.URI, len(names))
  126. for i, name := range names {
  127. uris[i] = storage.NewFileURI(name)
  128. }
  129. dropped(w.mousePos, uris)
  130. })
  131. })
  132. }
  133. func (w *window) doCenterOnScreen() {
  134. viewWidth, viewHeight := w.screenSize(w.canvas.size)
  135. if w.width > viewWidth { // in case our window has not called back to canvas size yet
  136. viewWidth = w.width
  137. }
  138. if w.height > viewHeight {
  139. viewHeight = w.height
  140. }
  141. // get window dimensions in pixels
  142. monitor := w.getMonitorForWindow()
  143. monMode := monitor.GetVideoMode()
  144. // these come into play when dealing with multiple monitors
  145. monX, monY := monitor.GetPos()
  146. // math them to the middle
  147. newX := (monMode.Width-viewWidth)/2 + monX
  148. newY := (monMode.Height-viewHeight)/2 + monY
  149. // set new window coordinates
  150. w.viewport.SetPos(newX, newY)
  151. }
  152. func (w *window) RequestFocus() {
  153. if isWayland || w.view() == nil {
  154. return
  155. }
  156. w.runOnMainWhenCreated(w.viewport.Focus)
  157. }
  158. func (w *window) SetIcon(icon fyne.Resource) {
  159. w.icon = icon
  160. if icon == nil {
  161. appIcon := fyne.CurrentApp().Icon()
  162. if appIcon != nil {
  163. w.SetIcon(appIcon)
  164. }
  165. return
  166. }
  167. w.runOnMainWhenCreated(func() {
  168. if w.icon == nil {
  169. w.viewport.SetIcon(nil)
  170. return
  171. }
  172. var img image.Image
  173. if svg.IsResourceSVG(w.icon) {
  174. img = painter.PaintImage(&canvas.Image{Resource: w.icon}, nil, windowIconSize, windowIconSize)
  175. } else {
  176. pix, _, err := image.Decode(bytes.NewReader(w.icon.Content()))
  177. if err != nil {
  178. fyne.LogError("Failed to decode image for window icon", err)
  179. return
  180. }
  181. img = pix
  182. }
  183. w.viewport.SetIcon([]image.Image{img})
  184. })
  185. }
  186. func (w *window) SetMaster() {
  187. w.master = true
  188. }
  189. func (w *window) fitContent() {
  190. if w.canvas.Content() == nil || (w.fullScreen && w.visible) {
  191. return
  192. }
  193. if w.isClosing() {
  194. return
  195. }
  196. minWidth, minHeight := w.minSizeOnScreen()
  197. w.viewLock.RLock()
  198. view := w.viewport
  199. w.viewLock.RUnlock()
  200. w.shouldWidth, w.shouldHeight = w.width, w.height
  201. if w.width < minWidth || w.height < minHeight {
  202. if w.width < minWidth {
  203. w.shouldWidth = minWidth
  204. }
  205. if w.height < minHeight {
  206. w.shouldHeight = minHeight
  207. }
  208. w.viewLock.Lock()
  209. w.shouldExpand = true // queue the resize to happen on main
  210. w.viewLock.Unlock()
  211. }
  212. if w.fixedSize {
  213. if w.shouldWidth > w.requestedWidth {
  214. w.requestedWidth = w.shouldWidth
  215. }
  216. if w.shouldHeight > w.requestedHeight {
  217. w.requestedHeight = w.shouldHeight
  218. }
  219. view.SetSizeLimits(w.requestedWidth, w.requestedHeight, w.requestedWidth, w.requestedHeight)
  220. } else {
  221. view.SetSizeLimits(minWidth, minHeight, glfw.DontCare, glfw.DontCare)
  222. }
  223. }
  224. func (w *window) getMonitorForWindow() *glfw.Monitor {
  225. x, y := w.xpos, w.ypos
  226. if w.fullScreen {
  227. x, y = w.viewport.GetPos()
  228. }
  229. xOff := x + (w.width / 2)
  230. yOff := y + (w.height / 2)
  231. for _, monitor := range glfw.GetMonitors() {
  232. x, y := monitor.GetPos()
  233. if x > xOff || y > yOff {
  234. continue
  235. }
  236. if x+monitor.GetVideoMode().Width <= xOff || y+monitor.GetVideoMode().Height <= yOff {
  237. continue
  238. }
  239. return monitor
  240. }
  241. // try built-in function to detect monitor if above logic didn't succeed
  242. // if it doesn't work then return primary monitor as default
  243. monitor := w.viewport.GetMonitor()
  244. if monitor == nil {
  245. monitor = glfw.GetPrimaryMonitor()
  246. }
  247. return monitor
  248. }
  249. func (w *window) detectScale() float32 {
  250. if isWayland { // Wayland controls scale through content scaling
  251. return 1.0
  252. }
  253. monitor := w.getMonitorForWindow()
  254. if monitor == nil {
  255. return 1.0
  256. }
  257. widthMm, _ := monitor.GetPhysicalSize()
  258. widthPx := monitor.GetVideoMode().Width
  259. return calculateDetectedScale(widthMm, widthPx)
  260. }
  261. func (w *window) moved(_ *glfw.Window, x, y int) {
  262. w.processMoved(x, y)
  263. }
  264. func (w *window) resized(_ *glfw.Window, width, height int) {
  265. w.processResized(width, height)
  266. }
  267. func (w *window) scaled(_ *glfw.Window, x float32, y float32) {
  268. if !isWayland { // other platforms handle this using older APIs
  269. return
  270. }
  271. w.canvas.texScale = x
  272. w.canvas.Refresh(w.canvas.content)
  273. }
  274. func (w *window) frameSized(_ *glfw.Window, width, height int) {
  275. w.processFrameSized(width, height)
  276. }
  277. func (w *window) refresh(_ *glfw.Window) {
  278. w.processRefresh()
  279. }
  280. func (w *window) closed(viewport *glfw.Window) {
  281. if viewport != nil {
  282. viewport.SetShouldClose(false) // reset the closed flag until we check the veto in processClosed
  283. }
  284. w.processClosed()
  285. }
  286. func fyneToNativeCursor(cursor desktop.Cursor) (*glfw.Cursor, bool) {
  287. switch v := cursor.(type) {
  288. case desktop.StandardCursor:
  289. ret, ok := cursorMap[v]
  290. if !ok {
  291. return cursorMap[desktop.DefaultCursor], false
  292. }
  293. return ret, false
  294. default:
  295. img, x, y := cursor.Image()
  296. if img == nil {
  297. return nil, true
  298. }
  299. return glfw.CreateCursor(img, x, y), true
  300. }
  301. }
  302. func (w *window) SetCursor(cursor *glfw.Cursor) {
  303. w.viewport.SetCursor(cursor)
  304. }
  305. func (w *window) setCustomCursor(rawCursor *glfw.Cursor, isCustomCursor bool) {
  306. if w.customCursor != nil {
  307. w.customCursor.Destroy()
  308. w.customCursor = nil
  309. }
  310. if isCustomCursor {
  311. w.customCursor = rawCursor
  312. }
  313. }
  314. func (w *window) mouseMoved(_ *glfw.Window, xpos, ypos float64) {
  315. w.processMouseMoved(xpos, ypos)
  316. }
  317. func (w *window) mouseClicked(_ *glfw.Window, btn glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) {
  318. button, modifiers := convertMouseButton(btn, mods)
  319. mouseAction := convertAction(action)
  320. w.processMouseClicked(button, mouseAction, modifiers)
  321. }
  322. func (w *window) mouseScrolled(viewport *glfw.Window, xoff float64, yoff float64) {
  323. if runtime.GOOS != "darwin" && xoff == 0 &&
  324. (viewport.GetKey(glfw.KeyLeftShift) == glfw.Press ||
  325. viewport.GetKey(glfw.KeyRightShift) == glfw.Press) {
  326. xoff, yoff = yoff, xoff
  327. }
  328. w.processMouseScrolled(xoff, yoff)
  329. }
  330. func convertMouseButton(btn glfw.MouseButton, mods glfw.ModifierKey) (desktop.MouseButton, fyne.KeyModifier) {
  331. modifier := desktopModifier(mods)
  332. var button desktop.MouseButton
  333. rightClick := false
  334. if runtime.GOOS == "darwin" {
  335. if modifier&fyne.KeyModifierControl != 0 {
  336. rightClick = true
  337. modifier &^= fyne.KeyModifierControl
  338. }
  339. if modifier&fyne.KeyModifierSuper != 0 {
  340. modifier |= fyne.KeyModifierControl
  341. modifier &^= fyne.KeyModifierSuper
  342. }
  343. }
  344. switch btn {
  345. case glfw.MouseButton1:
  346. if rightClick {
  347. button = desktop.MouseButtonSecondary
  348. } else {
  349. button = desktop.MouseButtonPrimary
  350. }
  351. case glfw.MouseButton2:
  352. button = desktop.MouseButtonSecondary
  353. case glfw.MouseButton3:
  354. button = desktop.MouseButtonTertiary
  355. }
  356. return button, modifier
  357. }
  358. //gocyclo:ignore
  359. func glfwKeyToKeyName(key glfw.Key) fyne.KeyName {
  360. switch key {
  361. // numbers - lookup by code to avoid AZERTY using the symbol name instead of number
  362. case glfw.Key0, glfw.KeyKP0:
  363. return fyne.Key0
  364. case glfw.Key1, glfw.KeyKP1:
  365. return fyne.Key1
  366. case glfw.Key2, glfw.KeyKP2:
  367. return fyne.Key2
  368. case glfw.Key3, glfw.KeyKP3:
  369. return fyne.Key3
  370. case glfw.Key4, glfw.KeyKP4:
  371. return fyne.Key4
  372. case glfw.Key5, glfw.KeyKP5:
  373. return fyne.Key5
  374. case glfw.Key6, glfw.KeyKP6:
  375. return fyne.Key6
  376. case glfw.Key7, glfw.KeyKP7:
  377. return fyne.Key7
  378. case glfw.Key8, glfw.KeyKP8:
  379. return fyne.Key8
  380. case glfw.Key9, glfw.KeyKP9:
  381. return fyne.Key9
  382. // non-printable
  383. case glfw.KeyEscape:
  384. return fyne.KeyEscape
  385. case glfw.KeyEnter:
  386. return fyne.KeyReturn
  387. case glfw.KeyTab:
  388. return fyne.KeyTab
  389. case glfw.KeyBackspace:
  390. return fyne.KeyBackspace
  391. case glfw.KeyInsert:
  392. return fyne.KeyInsert
  393. case glfw.KeyDelete:
  394. return fyne.KeyDelete
  395. case glfw.KeyRight:
  396. return fyne.KeyRight
  397. case glfw.KeyLeft:
  398. return fyne.KeyLeft
  399. case glfw.KeyDown:
  400. return fyne.KeyDown
  401. case glfw.KeyUp:
  402. return fyne.KeyUp
  403. case glfw.KeyPageUp:
  404. return fyne.KeyPageUp
  405. case glfw.KeyPageDown:
  406. return fyne.KeyPageDown
  407. case glfw.KeyHome:
  408. return fyne.KeyHome
  409. case glfw.KeyEnd:
  410. return fyne.KeyEnd
  411. case glfw.KeySpace:
  412. return fyne.KeySpace
  413. case glfw.KeyKPEnter:
  414. return fyne.KeyEnter
  415. // desktop
  416. case glfw.KeyLeftShift:
  417. return desktop.KeyShiftLeft
  418. case glfw.KeyRightShift:
  419. return desktop.KeyShiftRight
  420. case glfw.KeyLeftControl:
  421. return desktop.KeyControlLeft
  422. case glfw.KeyRightControl:
  423. return desktop.KeyControlRight
  424. case glfw.KeyLeftAlt:
  425. return desktop.KeyAltLeft
  426. case glfw.KeyRightAlt:
  427. return desktop.KeyAltRight
  428. case glfw.KeyLeftSuper:
  429. return desktop.KeySuperLeft
  430. case glfw.KeyRightSuper:
  431. return desktop.KeySuperRight
  432. case glfw.KeyMenu:
  433. return desktop.KeyMenu
  434. case glfw.KeyPrintScreen:
  435. return desktop.KeyPrintScreen
  436. case glfw.KeyCapsLock:
  437. return desktop.KeyCapsLock
  438. // functions
  439. case glfw.KeyF1:
  440. return fyne.KeyF1
  441. case glfw.KeyF2:
  442. return fyne.KeyF2
  443. case glfw.KeyF3:
  444. return fyne.KeyF3
  445. case glfw.KeyF4:
  446. return fyne.KeyF4
  447. case glfw.KeyF5:
  448. return fyne.KeyF5
  449. case glfw.KeyF6:
  450. return fyne.KeyF6
  451. case glfw.KeyF7:
  452. return fyne.KeyF7
  453. case glfw.KeyF8:
  454. return fyne.KeyF8
  455. case glfw.KeyF9:
  456. return fyne.KeyF9
  457. case glfw.KeyF10:
  458. return fyne.KeyF10
  459. case glfw.KeyF11:
  460. return fyne.KeyF11
  461. case glfw.KeyF12:
  462. return fyne.KeyF12
  463. }
  464. return fyne.KeyUnknown
  465. }
  466. func keyCodeToKeyName(code string) fyne.KeyName {
  467. if len(code) != 1 {
  468. return fyne.KeyUnknown
  469. }
  470. char := code[0]
  471. if char >= 'a' && char <= 'z' {
  472. // Our alphabetical keys are all upper case characters.
  473. return fyne.KeyName('A' + char - 'a')
  474. }
  475. switch char {
  476. case '[':
  477. return fyne.KeyLeftBracket
  478. case '\\':
  479. return fyne.KeyBackslash
  480. case ']':
  481. return fyne.KeyRightBracket
  482. case '\'':
  483. return fyne.KeyApostrophe
  484. case ',':
  485. return fyne.KeyComma
  486. case '-':
  487. return fyne.KeyMinus
  488. case '.':
  489. return fyne.KeyPeriod
  490. case '/':
  491. return fyne.KeySlash
  492. case '*':
  493. return fyne.KeyAsterisk
  494. case '`':
  495. return fyne.KeyBackTick
  496. case ';':
  497. return fyne.KeySemicolon
  498. case '+':
  499. return fyne.KeyPlus
  500. case '=':
  501. return fyne.KeyEqual
  502. }
  503. return fyne.KeyUnknown
  504. }
  505. func keyToName(code glfw.Key, scancode int) fyne.KeyName {
  506. if runtime.GOOS == "darwin" && scancode == 0x69 { // TODO remove once fixed upstream glfw/glfw#1786
  507. code = glfw.KeyPrintScreen
  508. }
  509. ret := glfwKeyToKeyName(code)
  510. if ret != fyne.KeyUnknown {
  511. return ret
  512. }
  513. keyName := glfw.GetKeyName(code, scancode)
  514. return keyCodeToKeyName(keyName)
  515. }
  516. func convertAction(action glfw.Action) action {
  517. switch action {
  518. case glfw.Press:
  519. return press
  520. case glfw.Release:
  521. return release
  522. case glfw.Repeat:
  523. return repeat
  524. }
  525. panic("Could not convert glfw.Action.")
  526. }
  527. func convertASCII(key glfw.Key) fyne.KeyName {
  528. if key < glfw.KeyA || key > glfw.KeyZ {
  529. return fyne.KeyUnknown
  530. }
  531. return fyne.KeyName(rune(key))
  532. }
  533. func (w *window) keyPressed(_ *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
  534. keyName := keyToName(key, scancode)
  535. keyDesktopModifier := desktopModifier(mods)
  536. w.driver.currentKeyModifiers = desktopModifierCorrected(mods, key, action)
  537. keyAction := convertAction(action)
  538. keyASCII := convertASCII(key)
  539. w.processKeyPressed(keyName, keyASCII, scancode, keyAction, keyDesktopModifier)
  540. }
  541. func desktopModifier(mods glfw.ModifierKey) fyne.KeyModifier {
  542. var m fyne.KeyModifier
  543. if (mods & glfw.ModShift) != 0 {
  544. m |= fyne.KeyModifierShift
  545. }
  546. if (mods & glfw.ModControl) != 0 {
  547. m |= fyne.KeyModifierControl
  548. }
  549. if (mods & glfw.ModAlt) != 0 {
  550. m |= fyne.KeyModifierAlt
  551. }
  552. if (mods & glfw.ModSuper) != 0 {
  553. m |= fyne.KeyModifierSuper
  554. }
  555. return m
  556. }
  557. func desktopModifierCorrected(mods glfw.ModifierKey, key glfw.Key, action glfw.Action) fyne.KeyModifier {
  558. // On X11, pressing/releasing modifier keys does not include newly pressed/released keys in 'mod' mask.
  559. // https://github.com/glfw/glfw/issues/1630
  560. if action == glfw.Press {
  561. mods |= glfwKeyToModifier(key)
  562. } else {
  563. mods &= ^glfwKeyToModifier(key)
  564. }
  565. return desktopModifier(mods)
  566. }
  567. func glfwKeyToModifier(key glfw.Key) glfw.ModifierKey {
  568. var m glfw.ModifierKey
  569. switch key {
  570. case glfw.KeyLeftControl, glfw.KeyRightControl:
  571. m = glfw.ModControl
  572. case glfw.KeyLeftAlt, glfw.KeyRightAlt:
  573. m = glfw.ModAlt
  574. case glfw.KeyLeftShift, glfw.KeyRightShift:
  575. m = glfw.ModShift
  576. case glfw.KeyLeftSuper, glfw.KeyRightSuper:
  577. m = glfw.ModSuper
  578. }
  579. return m
  580. }
  581. // charInput defines the character with modifiers callback which is called when a
  582. // Unicode character is input.
  583. //
  584. // Characters do not map 1:1 to physical keys, as a key may produce zero, one or more characters.
  585. func (w *window) charInput(viewport *glfw.Window, char rune) {
  586. w.processCharInput(char)
  587. }
  588. func (w *window) focused(_ *glfw.Window, focused bool) {
  589. w.processFocused(focused)
  590. }
  591. func (w *window) DetachCurrentContext() {
  592. glfw.DetachCurrentContext()
  593. }
  594. func (w *window) rescaleOnMain() {
  595. if w.isClosing() {
  596. return
  597. }
  598. w.fitContent()
  599. if w.fullScreen {
  600. w.width, w.height = w.viewport.GetSize()
  601. scaledFull := fyne.NewSize(
  602. scale.ToFyneCoordinate(w.canvas, w.width),
  603. scale.ToFyneCoordinate(w.canvas, w.height))
  604. w.canvas.Resize(scaledFull)
  605. return
  606. }
  607. size := w.canvas.size.Max(w.canvas.MinSize())
  608. newWidth, newHeight := w.screenSize(size)
  609. w.viewport.SetSize(newWidth, newHeight)
  610. }
  611. func (w *window) create() {
  612. runOnMain(func() {
  613. if !isWayland {
  614. // make the window hidden, we will set it up and then show it later
  615. glfw.WindowHint(glfw.Visible, glfw.False)
  616. }
  617. if w.decorate {
  618. glfw.WindowHint(glfw.Decorated, glfw.True)
  619. } else {
  620. glfw.WindowHint(glfw.Decorated, glfw.False)
  621. }
  622. if w.fixedSize {
  623. glfw.WindowHint(glfw.Resizable, glfw.False)
  624. } else {
  625. glfw.WindowHint(glfw.Resizable, glfw.True)
  626. }
  627. glfw.WindowHint(glfw.AutoIconify, glfw.False)
  628. initWindowHints()
  629. pixWidth, pixHeight := w.screenSize(w.canvas.size)
  630. pixWidth = int(fyne.Max(float32(pixWidth), float32(w.width)))
  631. if pixWidth == 0 {
  632. pixWidth = 10
  633. }
  634. pixHeight = int(fyne.Max(float32(pixHeight), float32(w.height)))
  635. if pixHeight == 0 {
  636. pixHeight = 10
  637. }
  638. win, err := glfw.CreateWindow(pixWidth, pixHeight, w.title, nil, nil)
  639. if err != nil {
  640. w.driver.initFailed("window creation error", err)
  641. return
  642. }
  643. w.viewLock.Lock()
  644. w.viewport = win
  645. w.viewLock.Unlock()
  646. })
  647. if w.view() == nil { // something went wrong above, it will have been logged
  648. return
  649. }
  650. // run the GL init on the draw thread
  651. runOnDraw(w, func() {
  652. w.canvas.SetPainter(gl.NewPainter(w.canvas, w))
  653. w.canvas.Painter().Init()
  654. })
  655. runOnMain(func() {
  656. w.setDarkMode()
  657. win := w.view()
  658. win.SetCloseCallback(w.closed)
  659. win.SetPosCallback(w.moved)
  660. win.SetSizeCallback(w.resized)
  661. win.SetFramebufferSizeCallback(w.frameSized)
  662. win.SetRefreshCallback(w.refresh)
  663. win.SetContentScaleCallback(w.scaled)
  664. win.SetCursorPosCallback(w.mouseMoved)
  665. win.SetMouseButtonCallback(w.mouseClicked)
  666. win.SetScrollCallback(w.mouseScrolled)
  667. win.SetKeyCallback(w.keyPressed)
  668. win.SetCharCallback(w.charInput)
  669. win.SetFocusCallback(w.focused)
  670. w.canvas.detectedScale = w.detectScale()
  671. w.canvas.scale = w.calculatedScale()
  672. w.canvas.texScale = w.detectTextureScale()
  673. // update window size now we have scaled detected
  674. w.fitContent()
  675. for _, fn := range w.pending {
  676. fn()
  677. }
  678. if w.FixedSize() && (w.requestedWidth == 0 || w.requestedHeight == 0) {
  679. bigEnough := w.canvas.canvasSize(w.canvas.Content().MinSize())
  680. w.width, w.height = scale.ToScreenCoordinate(w.canvas, bigEnough.Width), scale.ToScreenCoordinate(w.canvas, bigEnough.Height)
  681. w.shouldWidth, w.shouldHeight = w.width, w.height
  682. }
  683. w.requestedWidth, w.requestedHeight = w.width, w.height
  684. // order of operation matters so we do these last items in order
  685. w.viewport.SetSize(w.shouldWidth, w.shouldHeight) // ensure we requested latest size
  686. })
  687. }
  688. func (w *window) view() *glfw.Window {
  689. w.viewLock.RLock()
  690. defer w.viewLock.RUnlock()
  691. if w.closing {
  692. return nil
  693. }
  694. return w.viewport
  695. }