window.ts 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. import { invoke } from './tauri'
  2. import { EventCallback, emit, listen, once } from './helpers/event'
  3. interface WindowDef {
  4. label: string
  5. }
  6. declare global {
  7. interface Window {
  8. __TAURI__: {
  9. __windows: WindowDef[]
  10. __currentWindow: WindowDef
  11. }
  12. }
  13. }
  14. function getCurrent(): WebviewWindowHandle {
  15. return new WebviewWindowHandle(window.__TAURI__.__currentWindow.label)
  16. }
  17. function getAll(): WindowDef[] {
  18. return window.__TAURI__.__windows
  19. }
  20. // events that are emitted right here instead of by the created webview
  21. const localTauriEvents = ['tauri://created', 'tauri://error']
  22. class WebviewWindowHandle {
  23. label: string
  24. listeners: { [key: string]: Array<EventCallback<any>> }
  25. constructor(label: string) {
  26. this.label = label
  27. this.listeners = {}
  28. }
  29. /**
  30. * Listen to an event emitted by the webview
  31. *
  32. * @param event the event name
  33. * @param handler the event handler callback
  34. */
  35. async listen<T>(event: string, handler: EventCallback<T>): Promise<void> {
  36. if (this._handleTauriEvent(event, handler)) {
  37. return Promise.resolve()
  38. }
  39. return listen(event, handler)
  40. }
  41. /**
  42. * Listen to an one-off event emitted by the webview
  43. *
  44. * @param event the event name
  45. * @param handler the event handler callback
  46. */
  47. async once<T>(event: string, handler: EventCallback<T>): Promise<void> {
  48. if (this._handleTauriEvent(event, handler)) {
  49. return Promise.resolve()
  50. }
  51. return once(event, handler)
  52. }
  53. /**
  54. * emits an event to the webview
  55. *
  56. * @param event the event name
  57. * @param [payload] the event payload
  58. */
  59. async emit(event: string, payload?: string): Promise<void> {
  60. if (localTauriEvents.includes(event)) {
  61. // eslint-disable-next-line
  62. for (const handler of this.listeners[event] || []) {
  63. handler({ type: event, payload })
  64. }
  65. return Promise.resolve()
  66. }
  67. return emit(event, this.label, payload)
  68. }
  69. _handleTauriEvent<T>(event: string, handler: EventCallback<T>): boolean {
  70. if (localTauriEvents.includes(event)) {
  71. if (!(event in this.listeners)) {
  72. // eslint-disable-next-line
  73. this.listeners[event] = [handler]
  74. } else {
  75. // eslint-disable-next-line
  76. this.listeners[event].push(handler)
  77. }
  78. return true
  79. }
  80. return false
  81. }
  82. _emitTauriEvent(event: string): void {}
  83. }
  84. class WebviewWindow extends WebviewWindowHandle {
  85. constructor(label: string, options: WindowOptions = {}) {
  86. super(label)
  87. invoke({
  88. __tauriModule: 'Window',
  89. message: {
  90. cmd: 'createWebview',
  91. options: {
  92. label,
  93. ...options
  94. }
  95. }
  96. })
  97. .then(async () => this.emit('tauri://created'))
  98. .catch(async (e) => this.emit('tauri://error', e))
  99. }
  100. /**
  101. * Gets the WebviewWindow handle for the webview associated with the given label.
  102. *
  103. * @param {string} label the webview window label.
  104. *
  105. * @return {WebviewWindowHandle} the handle to communicate with the webview or null if the webview doesn't exist
  106. */
  107. static getByLabel(label: string): WebviewWindowHandle | null {
  108. if (getAll().some((w) => w.label === label)) {
  109. return new WebviewWindowHandle(label)
  110. }
  111. return null
  112. }
  113. }
  114. class WindowManager {
  115. /**
  116. * Updates the window resizable flag.
  117. */
  118. async setResizable(resizable: boolean): Promise<void> {
  119. return invoke({
  120. __tauriModule: 'Window',
  121. message: {
  122. cmd: 'setResizable',
  123. resizable
  124. }
  125. })
  126. }
  127. /**
  128. * sets the window title
  129. *
  130. * @param title the new title
  131. */
  132. async setTitle(title: string): Promise<void> {
  133. return invoke({
  134. __tauriModule: 'Window',
  135. message: {
  136. cmd: 'setTitle',
  137. title
  138. }
  139. })
  140. }
  141. /**
  142. * Maximizes the window.
  143. */
  144. async maximize(): Promise<void> {
  145. return invoke({
  146. __tauriModule: 'Window',
  147. message: {
  148. cmd: 'maximize'
  149. }
  150. })
  151. }
  152. /**
  153. * Unmaximizes the window.
  154. */
  155. async unmaximize(): Promise<void> {
  156. return invoke({
  157. __tauriModule: 'Window',
  158. message: {
  159. cmd: 'unmaximize'
  160. }
  161. })
  162. }
  163. /**
  164. * Minimizes the window.
  165. */
  166. async minimize(): Promise<void> {
  167. return invoke({
  168. __tauriModule: 'Window',
  169. message: {
  170. cmd: 'minimize'
  171. }
  172. })
  173. }
  174. /**
  175. * Unminimizes the window.
  176. */
  177. async unminimize(): Promise<void> {
  178. return invoke({
  179. __tauriModule: 'Window',
  180. message: {
  181. cmd: 'unminimize'
  182. }
  183. })
  184. }
  185. /**
  186. * Sets the window visibility to true.
  187. */
  188. async show(): Promise<void> {
  189. return invoke({
  190. __tauriModule: 'Window',
  191. message: {
  192. cmd: 'show'
  193. }
  194. })
  195. }
  196. /**
  197. * Sets the window visibility to false.
  198. */
  199. async hide(): Promise<void> {
  200. return invoke({
  201. __tauriModule: 'Window',
  202. message: {
  203. cmd: 'hide'
  204. }
  205. })
  206. }
  207. /**
  208. * Sets the window transparent flag.
  209. *
  210. * @param {boolean} transparent whether the the window should be transparent or not
  211. */
  212. async setTransparent(transparent: boolean): Promise<void> {
  213. return invoke({
  214. __tauriModule: 'Window',
  215. message: {
  216. cmd: 'setTransparent',
  217. transparent
  218. }
  219. })
  220. }
  221. /**
  222. * Whether the window should have borders and bars.
  223. *
  224. * @param {boolean} decorations whether the window should have borders and bars
  225. */
  226. async setDecorations(decorations: boolean): Promise<void> {
  227. return invoke({
  228. __tauriModule: 'Window',
  229. message: {
  230. cmd: 'setDecorations',
  231. decorations
  232. }
  233. })
  234. }
  235. /**
  236. * Whether the window should always be on top of other windows.
  237. *
  238. * @param {boolean} alwaysOnTop whether the window should always be on top of other windows or not
  239. */
  240. async setAlwaysOnTop(alwaysOnTop: boolean): Promise<void> {
  241. return invoke({
  242. __tauriModule: 'Window',
  243. message: {
  244. cmd: 'setAlwaysOnTop',
  245. alwaysOnTop
  246. }
  247. })
  248. }
  249. /**
  250. * Sets the window width.
  251. *
  252. * @param {number} width the new window width
  253. */
  254. async setWidth(width: number): Promise<void> {
  255. return invoke({
  256. __tauriModule: 'Window',
  257. message: {
  258. cmd: 'setWidth',
  259. width
  260. }
  261. })
  262. }
  263. /**
  264. * Sets the window height.
  265. *
  266. * @param {number} height the new window height
  267. */
  268. async setHeight(height: number): Promise<void> {
  269. return invoke({
  270. __tauriModule: 'Window',
  271. message: {
  272. cmd: 'setHeight',
  273. height
  274. }
  275. })
  276. }
  277. /**
  278. * Resizes the window.
  279. *
  280. * @param {number} width the new window width
  281. * @param {number} height the new window height
  282. */
  283. async resize(width: number, height: number): Promise<void> {
  284. return invoke({
  285. __tauriModule: 'Window',
  286. message: {
  287. cmd: 'resize',
  288. width,
  289. height
  290. }
  291. })
  292. }
  293. /**
  294. * Sets the window min size.
  295. *
  296. * @param {number} minWidth the new window min width
  297. * @param {number} minHeight the new window min height
  298. */
  299. async setMinSize(minWidth: number, minHeight: number): Promise<void> {
  300. return invoke({
  301. __tauriModule: 'Window',
  302. message: {
  303. cmd: 'setMinSize',
  304. minWidth,
  305. minHeight
  306. }
  307. })
  308. }
  309. /**
  310. * Sets the window max size.
  311. *
  312. * @param {number} maxWidth the new window max width
  313. * @param {number} maxHeight the new window max height
  314. */
  315. async setMaxSize(maxWidth: number, maxHeight: number): Promise<void> {
  316. return invoke({
  317. __tauriModule: 'Window',
  318. message: {
  319. cmd: 'setMaxSize',
  320. maxWidth,
  321. maxHeight
  322. }
  323. })
  324. }
  325. /**
  326. * Sets the window x position.
  327. *
  328. * @param {number} x the new window x position
  329. */
  330. async setX(x: number): Promise<void> {
  331. return invoke({
  332. __tauriModule: 'Window',
  333. message: {
  334. cmd: 'setX',
  335. x
  336. }
  337. })
  338. }
  339. /**
  340. * Sets the window y position.
  341. *
  342. * @param {number} y the new window y position
  343. */
  344. async setY(y: number): Promise<void> {
  345. return invoke({
  346. __tauriModule: 'Window',
  347. message: {
  348. cmd: 'setY',
  349. y
  350. }
  351. })
  352. }
  353. /**
  354. * Sets the window position.
  355. *
  356. * @param {number} x the new window x position
  357. * @param {number} y the new window y position
  358. */
  359. async setPosition(x: number, y: number): Promise<void> {
  360. return invoke({
  361. __tauriModule: 'Window',
  362. message: {
  363. cmd: 'setPosition',
  364. x,
  365. y
  366. }
  367. })
  368. }
  369. /**
  370. * Sets the window fullscreen state.
  371. *
  372. * @param {boolean} fullscreen whether the window should go to fullscreen or not
  373. */
  374. async setFullscreen(fullscreen: boolean): Promise<void> {
  375. return invoke({
  376. __tauriModule: 'Window',
  377. message: {
  378. cmd: 'setFullscreen',
  379. fullscreen
  380. }
  381. })
  382. }
  383. /**
  384. * Sets the window icon
  385. *
  386. * @param {string | number[]} icon icon bytes or path to the icon file
  387. */
  388. async setIcon(icon: 'string' | number[]): Promise<void> {
  389. return invoke({
  390. __tauriModule: 'Window',
  391. message: {
  392. cmd: 'setIcon',
  393. icon
  394. }
  395. })
  396. }
  397. }
  398. const manager = new WindowManager()
  399. export interface WindowOptions {
  400. url?: 'app' | string
  401. x?: number
  402. y?: number
  403. width?: number
  404. height?: number
  405. minWidth?: number
  406. minHeight?: number
  407. maxWidth?: number
  408. maxHeight?: number
  409. resizable?: boolean
  410. title?: string
  411. fullscreen?: boolean
  412. transparent?: boolean
  413. maximized?: boolean
  414. visible?: boolean
  415. decorations?: boolean
  416. alwaysOnTop?: boolean
  417. }
  418. export { WebviewWindow, getCurrent, getAll, manager }