@theia/core 1.18.0-next.de7b81be → 1.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/LICENSE +642 -0
  2. package/README.md +3 -2
  3. package/lib/browser/about-dialog.d.ts.map +1 -1
  4. package/lib/browser/about-dialog.js +1 -1
  5. package/lib/browser/about-dialog.js.map +1 -1
  6. package/lib/browser/authentication-service.d.ts.map +1 -1
  7. package/lib/browser/authentication-service.js +1 -1
  8. package/lib/browser/authentication-service.js.map +1 -1
  9. package/lib/browser/color-registry.d.ts +3 -69
  10. package/lib/browser/color-registry.d.ts.map +1 -1
  11. package/lib/browser/color-registry.js +13 -27
  12. package/lib/browser/color-registry.js.map +1 -1
  13. package/lib/browser/common-frontend-contribution.d.ts +7 -0
  14. package/lib/browser/common-frontend-contribution.d.ts.map +1 -1
  15. package/lib/browser/common-frontend-contribution.js +138 -121
  16. package/lib/browser/common-frontend-contribution.js.map +1 -1
  17. package/lib/browser/core-preferences.d.ts +2 -0
  18. package/lib/browser/core-preferences.d.ts.map +1 -1
  19. package/lib/browser/core-preferences.js +33 -18
  20. package/lib/browser/core-preferences.js.map +1 -1
  21. package/lib/browser/dialogs.d.ts +6 -0
  22. package/lib/browser/dialogs.d.ts.map +1 -1
  23. package/lib/browser/dialogs.js +10 -3
  24. package/lib/browser/dialogs.js.map +1 -1
  25. package/lib/browser/frontend-application-module.d.ts.map +1 -1
  26. package/lib/browser/frontend-application-module.js +3 -0
  27. package/lib/browser/frontend-application-module.js.map +1 -1
  28. package/lib/browser/frontend-application.d.ts +6 -0
  29. package/lib/browser/frontend-application.d.ts.map +1 -1
  30. package/lib/browser/frontend-application.js +13 -0
  31. package/lib/browser/frontend-application.js.map +1 -1
  32. package/lib/browser/index.d.ts +1 -0
  33. package/lib/browser/index.d.ts.map +1 -1
  34. package/lib/browser/index.js +1 -0
  35. package/lib/browser/index.js.map +1 -1
  36. package/lib/browser/keybinding.spec.js +5 -0
  37. package/lib/browser/keybinding.spec.js.map +1 -1
  38. package/lib/browser/keyboard/browser-keyboard-frontend-contribution.d.ts.map +1 -1
  39. package/lib/browser/keyboard/browser-keyboard-frontend-contribution.js +16 -11
  40. package/lib/browser/keyboard/browser-keyboard-frontend-contribution.js.map +1 -1
  41. package/lib/browser/keyboard/browser-keyboard-layout-provider.d.ts +1 -1
  42. package/lib/browser/keyboard/browser-keyboard-layout-provider.d.ts.map +1 -1
  43. package/lib/browser/keyboard/browser-keyboard-layout-provider.spec.js +6 -4
  44. package/lib/browser/keyboard/browser-keyboard-layout-provider.spec.js.map +1 -1
  45. package/lib/browser/keyboard/keys.d.ts +2 -251
  46. package/lib/browser/keyboard/keys.d.ts.map +1 -1
  47. package/lib/browser/keyboard/keys.js +12 -614
  48. package/lib/browser/keyboard/keys.js.map +1 -1
  49. package/lib/browser/menu/browser-context-menu-renderer.d.ts +1 -1
  50. package/lib/browser/menu/browser-context-menu-renderer.d.ts.map +1 -1
  51. package/lib/browser/menu/browser-menu-plugin.d.ts +3 -0
  52. package/lib/browser/menu/browser-menu-plugin.d.ts.map +1 -1
  53. package/lib/browser/menu/browser-menu-plugin.js +24 -4
  54. package/lib/browser/menu/browser-menu-plugin.js.map +1 -1
  55. package/lib/browser/messaging/ws-connection-provider.d.ts +3 -3
  56. package/lib/browser/messaging/ws-connection-provider.d.ts.map +1 -1
  57. package/lib/browser/messaging/ws-connection-provider.js +14 -4
  58. package/lib/browser/messaging/ws-connection-provider.js.map +1 -1
  59. package/lib/browser/{nls.d.ts → nls-loader.d.ts} +1 -6
  60. package/lib/browser/nls-loader.d.ts.map +1 -0
  61. package/lib/browser/nls-loader.js +29 -0
  62. package/lib/browser/nls-loader.js.map +1 -0
  63. package/lib/browser/progress-status-bar-item.d.ts +1 -2
  64. package/lib/browser/progress-status-bar-item.d.ts.map +1 -1
  65. package/lib/browser/progress-status-bar-item.js.map +1 -1
  66. package/lib/browser/quick-input/quick-command-frontend-contribution.d.ts.map +1 -1
  67. package/lib/browser/quick-input/quick-command-frontend-contribution.js +2 -1
  68. package/lib/browser/quick-input/quick-command-frontend-contribution.js.map +1 -1
  69. package/lib/browser/quick-input/quick-command-service.d.ts.map +1 -1
  70. package/lib/browser/quick-input/quick-command-service.js +2 -2
  71. package/lib/browser/quick-input/quick-command-service.js.map +1 -1
  72. package/lib/browser/quick-input/quick-input-service.d.ts +1 -201
  73. package/lib/browser/quick-input/quick-input-service.d.ts.map +1 -1
  74. package/lib/browser/quick-input/quick-input-service.js +11 -93
  75. package/lib/browser/quick-input/quick-input-service.js.map +1 -1
  76. package/lib/browser/quick-input/quick-view-service.d.ts +1 -2
  77. package/lib/browser/quick-input/quick-view-service.d.ts.map +1 -1
  78. package/lib/browser/quick-input/quick-view-service.js.map +1 -1
  79. package/lib/browser/shell/application-shell.d.ts +3 -1
  80. package/lib/browser/shell/application-shell.d.ts.map +1 -1
  81. package/lib/browser/shell/application-shell.js +1 -2
  82. package/lib/browser/shell/application-shell.js.map +1 -1
  83. package/lib/browser/shell/shell-layout-restorer.d.ts.map +1 -1
  84. package/lib/browser/shell/shell-layout-restorer.js +5 -3
  85. package/lib/browser/shell/shell-layout-restorer.js.map +1 -1
  86. package/lib/browser/shell/tab-bar-decorator.d.ts +1 -1
  87. package/lib/browser/shell/tab-bar-decorator.d.ts.map +1 -1
  88. package/lib/browser/shell/tab-bar-decorator.js.map +1 -1
  89. package/lib/browser/shell/tab-bar-toolbar.d.ts.map +1 -1
  90. package/lib/browser/shell/tab-bar-toolbar.js +2 -1
  91. package/lib/browser/shell/tab-bar-toolbar.js.map +1 -1
  92. package/lib/browser/shell/tab-bars.d.ts +14 -1
  93. package/lib/browser/shell/tab-bars.d.ts.map +1 -1
  94. package/lib/browser/shell/tab-bars.js +99 -7
  95. package/lib/browser/shell/tab-bars.js.map +1 -1
  96. package/lib/browser/status-bar/status-bar.d.ts +3 -1
  97. package/lib/browser/status-bar/status-bar.d.ts.map +1 -1
  98. package/lib/browser/status-bar/status-bar.js +16 -2
  99. package/lib/browser/status-bar/status-bar.js.map +1 -1
  100. package/lib/browser/storage-service.spec.js +1 -1
  101. package/lib/browser/storage-service.spec.js.map +1 -1
  102. package/lib/browser/theming.d.ts +5 -14
  103. package/lib/browser/theming.d.ts.map +1 -1
  104. package/lib/browser/theming.js +14 -0
  105. package/lib/browser/theming.js.map +1 -1
  106. package/lib/browser/tooltip-service.d.ts +52 -0
  107. package/lib/browser/tooltip-service.d.ts.map +1 -0
  108. package/lib/browser/tooltip-service.js +89 -0
  109. package/lib/browser/tooltip-service.js.map +1 -0
  110. package/lib/browser/tree/tree-model.d.ts.map +1 -1
  111. package/lib/browser/tree/tree-widget.js +1 -1
  112. package/lib/browser/view-container.d.ts +55 -14
  113. package/lib/browser/view-container.d.ts.map +1 -1
  114. package/lib/browser/view-container.js +284 -66
  115. package/lib/browser/view-container.js.map +1 -1
  116. package/lib/browser/window/default-window-service.js +2 -2
  117. package/lib/browser/window/default-window-service.js.map +1 -1
  118. package/lib/browser/window/window-service.d.ts +1 -7
  119. package/lib/browser/window/window-service.d.ts.map +1 -1
  120. package/lib/browser/window/window-service.js +1 -5
  121. package/lib/browser/window/window-service.js.map +1 -1
  122. package/lib/browser/window-contribution.d.ts.map +1 -1
  123. package/lib/browser/window-contribution.js +2 -2
  124. package/lib/browser/window-contribution.js.map +1 -1
  125. package/lib/common/cancellation.d.ts +3 -0
  126. package/lib/common/cancellation.d.ts.map +1 -1
  127. package/lib/common/cancellation.js +8 -1
  128. package/lib/common/cancellation.js.map +1 -1
  129. package/lib/common/color.d.ts +84 -0
  130. package/lib/common/color.d.ts.map +1 -0
  131. package/lib/common/color.js +44 -0
  132. package/lib/common/color.js.map +1 -0
  133. package/lib/common/command.d.ts +1 -0
  134. package/lib/common/command.d.ts.map +1 -1
  135. package/lib/common/command.js +5 -1
  136. package/lib/common/command.js.map +1 -1
  137. package/lib/common/i18n/localization.d.ts +14 -0
  138. package/lib/common/i18n/localization.d.ts.map +1 -1
  139. package/lib/common/i18n/localization.js +54 -1
  140. package/lib/common/i18n/localization.js.map +1 -1
  141. package/lib/common/index.d.ts +1 -0
  142. package/lib/common/index.d.ts.map +1 -1
  143. package/lib/common/index.js +1 -0
  144. package/lib/common/index.js.map +1 -1
  145. package/lib/common/keys.d.ts +269 -0
  146. package/lib/common/keys.d.ts.map +1 -0
  147. package/lib/common/keys.js +634 -0
  148. package/lib/common/keys.js.map +1 -0
  149. package/lib/common/messaging/abstract-connection-provider.d.ts +1 -1
  150. package/lib/common/messaging/abstract-connection-provider.d.ts.map +1 -1
  151. package/lib/common/messaging/abstract-connection-provider.js +3 -1
  152. package/lib/common/messaging/abstract-connection-provider.js.map +1 -1
  153. package/lib/common/messaging/proxy-factory.js +1 -1
  154. package/lib/common/messaging/proxy-factory.js.map +1 -1
  155. package/lib/common/nls.d.ts +28 -0
  156. package/lib/common/nls.d.ts.map +1 -0
  157. package/lib/common/nls.js +91 -0
  158. package/lib/common/nls.js.map +1 -0
  159. package/lib/common/path.d.ts +6 -0
  160. package/lib/common/path.d.ts.map +1 -1
  161. package/lib/common/path.js +16 -4
  162. package/lib/common/path.js.map +1 -1
  163. package/lib/common/path.spec.js +12 -0
  164. package/lib/common/path.spec.js.map +1 -1
  165. package/lib/common/promise-util.d.ts +2 -2
  166. package/lib/common/promise-util.d.ts.map +1 -1
  167. package/lib/common/promise-util.js.map +1 -1
  168. package/lib/common/quick-pick-service.d.ts +219 -1
  169. package/lib/common/quick-pick-service.d.ts.map +1 -1
  170. package/lib/common/quick-pick-service.js +108 -1
  171. package/lib/common/quick-pick-service.js.map +1 -1
  172. package/lib/common/theme.d.ts +30 -0
  173. package/lib/common/theme.d.ts.map +1 -0
  174. package/lib/common/theme.js +18 -0
  175. package/lib/common/theme.js.map +1 -0
  176. package/lib/common/window.d.ts +29 -0
  177. package/lib/common/window.d.ts.map +1 -0
  178. package/lib/common/window.js +23 -0
  179. package/lib/common/window.js.map +1 -0
  180. package/lib/electron-browser/menu/electron-context-menu-renderer.d.ts +9 -5
  181. package/lib/electron-browser/menu/electron-context-menu-renderer.d.ts.map +1 -1
  182. package/lib/electron-browser/menu/electron-context-menu-renderer.js +40 -15
  183. package/lib/electron-browser/menu/electron-context-menu-renderer.js.map +1 -1
  184. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts +5 -8
  185. package/lib/electron-browser/menu/electron-main-menu-factory.d.ts.map +1 -1
  186. package/lib/electron-browser/menu/electron-main-menu-factory.js +10 -17
  187. package/lib/electron-browser/menu/electron-main-menu-factory.js.map +1 -1
  188. package/lib/electron-browser/menu/electron-menu-contribution.d.ts +15 -7
  189. package/lib/electron-browser/menu/electron-menu-contribution.d.ts.map +1 -1
  190. package/lib/electron-browser/menu/electron-menu-contribution.js +112 -42
  191. package/lib/electron-browser/menu/electron-menu-contribution.js.map +1 -1
  192. package/lib/electron-browser/window/electron-window-preferences.d.ts +1 -0
  193. package/lib/electron-browser/window/electron-window-preferences.d.ts.map +1 -1
  194. package/lib/electron-browser/window/electron-window-preferences.js +12 -1
  195. package/lib/electron-browser/window/electron-window-preferences.js.map +1 -1
  196. package/lib/electron-browser/window/electron-window-service.d.ts +1 -1
  197. package/lib/electron-browser/window/electron-window-service.d.ts.map +1 -1
  198. package/lib/electron-common/electron-main-window-service.d.ts +1 -1
  199. package/lib/electron-common/electron-main-window-service.d.ts.map +1 -1
  200. package/lib/electron-common/messaging/electron-messages.d.ts +20 -0
  201. package/lib/electron-common/messaging/electron-messages.d.ts.map +1 -0
  202. package/lib/electron-common/messaging/electron-messages.js +23 -0
  203. package/lib/electron-common/messaging/electron-messages.js.map +1 -0
  204. package/lib/electron-main/electron-main-application.d.ts +6 -0
  205. package/lib/electron-main/electron-main-application.d.ts.map +1 -1
  206. package/lib/electron-main/electron-main-application.js +80 -23
  207. package/lib/electron-main/electron-main-application.js.map +1 -1
  208. package/lib/electron-main/electron-main-window-service-impl.d.ts +1 -1
  209. package/lib/electron-main/electron-main-window-service-impl.d.ts.map +1 -1
  210. package/lib/electron-main/messaging/electron-messaging-contribution.d.ts +1 -1
  211. package/lib/electron-main/messaging/electron-messaging-contribution.d.ts.map +1 -1
  212. package/lib/electron-main/messaging/electron-messaging-contribution.js +1 -2
  213. package/lib/electron-main/messaging/electron-messaging-contribution.js.map +1 -1
  214. package/package.json +13 -9
  215. package/shared/@theia/application-package/lib/api.d.ts +1 -0
  216. package/shared/@theia/application-package/lib/api.js +1 -0
  217. package/src/browser/about-dialog.tsx +2 -2
  218. package/src/browser/authentication-service.ts +1 -2
  219. package/src/browser/color-registry.ts +3 -85
  220. package/src/browser/common-frontend-contribution.ts +116 -99
  221. package/src/browser/core-preferences.ts +37 -18
  222. package/src/browser/dialogs.ts +10 -3
  223. package/src/browser/frontend-application-module.ts +4 -0
  224. package/src/browser/frontend-application.ts +13 -0
  225. package/src/browser/index.ts +1 -0
  226. package/src/browser/keybinding.spec.ts +8 -1
  227. package/src/browser/keyboard/browser-keyboard-frontend-contribution.ts +16 -11
  228. package/src/browser/keyboard/browser-keyboard-layout-provider.spec.ts +10 -4
  229. package/src/browser/keyboard/keys.ts +2 -675
  230. package/src/browser/menu/browser-context-menu-renderer.ts +1 -1
  231. package/src/browser/menu/browser-menu-plugin.ts +25 -5
  232. package/src/browser/messaging/ws-connection-provider.ts +13 -4
  233. package/src/browser/nls-loader.ts +26 -0
  234. package/src/browser/progress-status-bar-item.ts +1 -2
  235. package/src/browser/quick-input/quick-command-frontend-contribution.ts +2 -2
  236. package/src/browser/quick-input/quick-command-service.ts +2 -2
  237. package/src/browser/quick-input/quick-input-service.ts +1 -278
  238. package/src/browser/quick-input/quick-view-service.ts +1 -2
  239. package/src/browser/shell/application-shell.ts +4 -3
  240. package/src/browser/shell/shell-layout-restorer.ts +4 -3
  241. package/src/browser/shell/tab-bar-decorator.ts +1 -1
  242. package/src/browser/shell/tab-bar-toolbar.tsx +3 -1
  243. package/src/browser/shell/tab-bars.ts +103 -8
  244. package/src/browser/status-bar/status-bar.tsx +16 -1
  245. package/src/browser/storage-service.spec.ts +1 -1
  246. package/src/browser/style/alert-messages.css +1 -0
  247. package/src/browser/style/index.css +5 -0
  248. package/src/browser/style/menus.css +10 -1
  249. package/src/browser/style/sidepanel.css +9 -3
  250. package/src/browser/style/tabs.css +30 -0
  251. package/src/browser/style/tooltip.css +28 -0
  252. package/src/browser/style/view-container.css +9 -9
  253. package/src/browser/theming.ts +6 -17
  254. package/src/browser/tooltip-service.tsx +98 -0
  255. package/src/browser/tree/tree-model.ts +1 -1
  256. package/src/browser/tree/tree-widget.tsx +1 -1
  257. package/src/browser/view-container.ts +312 -80
  258. package/src/browser/window/default-window-service.ts +2 -2
  259. package/src/browser/window/window-service.ts +1 -9
  260. package/src/browser/window-contribution.ts +2 -2
  261. package/src/common/cancellation.ts +7 -0
  262. package/src/common/color.ts +100 -0
  263. package/src/common/command.ts +11 -1
  264. package/src/common/i18n/localization.ts +54 -0
  265. package/src/common/i18n/nls.metadata.json +20421 -0
  266. package/src/common/index.ts +1 -0
  267. package/src/common/keys.ts +693 -0
  268. package/src/common/messaging/abstract-connection-provider.ts +3 -1
  269. package/src/common/messaging/proxy-factory.ts +1 -1
  270. package/src/common/nls.ts +104 -0
  271. package/src/common/path.spec.ts +15 -0
  272. package/src/common/path.ts +16 -4
  273. package/src/common/promise-util.ts +3 -3
  274. package/src/common/quick-pick-service.ts +299 -3
  275. package/src/common/theme.ts +32 -0
  276. package/src/common/window.ts +30 -0
  277. package/src/electron-browser/menu/electron-context-menu-renderer.ts +38 -16
  278. package/src/electron-browser/menu/electron-main-menu-factory.ts +10 -15
  279. package/src/electron-browser/menu/electron-menu-contribution.ts +129 -39
  280. package/src/electron-browser/menu/electron-menu-style.css +84 -0
  281. package/src/electron-browser/window/electron-window-preferences.ts +13 -1
  282. package/src/electron-browser/window/electron-window-service.ts +1 -1
  283. package/src/electron-common/electron-main-window-service.ts +1 -1
  284. package/src/electron-common/messaging/electron-messages.ts +20 -0
  285. package/src/electron-main/electron-main-application.ts +86 -20
  286. package/src/electron-main/electron-main-window-service-impl.ts +1 -1
  287. package/src/electron-main/messaging/electron-messaging-contribution.ts +1 -2
  288. package/lib/browser/nls.d.ts.map +0 -1
  289. package/lib/browser/nls.js +0 -64
  290. package/lib/browser/nls.js.map +0 -1
  291. package/src/browser/nls.ts +0 -65
@@ -24,10 +24,9 @@ import {
24
24
  } from '../../common';
25
25
  import { Keybinding } from '../../common/keybinding';
26
26
  import { PreferenceService, KeybindingRegistry, CommonCommands } from '../../browser';
27
- import { ContextKeyService } from '../../browser/context-key-service';
28
27
  import debounce = require('lodash.debounce');
29
- import { ContextMenuContext } from '../../browser/menu/context-menu-context';
30
28
  import { MAXIMIZED_CLASS } from '../../browser/shell/theia-dock-panel';
29
+ import { BrowserMainMenuFactory } from '../../browser/menu/browser-menu-plugin';
31
30
 
32
31
  /**
33
32
  * Representation of possible electron menu options.
@@ -55,23 +54,18 @@ export type ElectronMenuItemRole = ('undo' | 'redo' | 'cut' | 'copy' | 'paste' |
55
54
  'moveTabToNewWindow' | 'windowMenu');
56
55
 
57
56
  @injectable()
58
- export class ElectronMainMenuFactory {
57
+ export class ElectronMainMenuFactory extends BrowserMainMenuFactory {
59
58
 
60
59
  protected _menu: Electron.Menu | undefined;
61
60
  protected _toggledCommands: Set<string> = new Set();
62
61
 
63
- @inject(ContextKeyService)
64
- protected readonly contextKeyService: ContextKeyService;
65
-
66
- @inject(ContextMenuContext)
67
- protected readonly context: ContextMenuContext;
68
-
69
62
  constructor(
70
63
  @inject(CommandRegistry) protected readonly commandRegistry: CommandRegistry,
71
64
  @inject(PreferenceService) protected readonly preferencesService: PreferenceService,
72
65
  @inject(MenuModelRegistry) protected readonly menuProvider: MenuModelRegistry,
73
66
  @inject(KeybindingRegistry) protected readonly keybindingRegistry: KeybindingRegistry
74
67
  ) {
68
+ super();
75
69
  preferencesService.onPreferenceChanged(
76
70
  debounce(e => {
77
71
  if (e.preferenceName === 'window.menuBarVisibility') {
@@ -92,15 +86,16 @@ export class ElectronMainMenuFactory {
92
86
 
93
87
  async setMenuBar(): Promise<void> {
94
88
  await this.preferencesService.ready;
95
- const createdMenuBar = this.createMenuBar();
96
89
  if (isOSX) {
90
+ const createdMenuBar = this.createElectronMenuBar();
97
91
  electron.remote.Menu.setApplicationMenu(createdMenuBar);
98
- } else {
92
+ } else if (this.preferencesService.get('window.titleBarStyle') === 'native') {
93
+ const createdMenuBar = this.createElectronMenuBar();
99
94
  electron.remote.getCurrentWindow().setMenu(createdMenuBar);
100
95
  }
101
96
  }
102
97
 
103
- createMenuBar(): Electron.Menu | null {
98
+ createElectronMenuBar(): Electron.Menu | null {
104
99
  const preference = this.preferencesService.get<string>('window.menuBarVisibility') || 'classic';
105
100
  const maxWidget = document.getElementsByClassName(MAXIMIZED_CLASS);
106
101
  if (preference === 'visible' || (preference === 'classic' && maxWidget.length === 0)) {
@@ -118,7 +113,7 @@ export class ElectronMainMenuFactory {
118
113
  return null;
119
114
  }
120
115
 
121
- createContextMenu(menuPath: MenuPath, args?: any[]): Electron.Menu {
116
+ createElectronContextMenu(menuPath: MenuPath, args?: any[]): Electron.Menu {
122
117
  const menuModel = this.menuProvider.getMenu(menuPath);
123
118
  const template = this.fillMenuTemplate([], menuModel, args, { showDisabled: false });
124
119
  return electron.remote.Menu.buildFromTemplate(template);
@@ -221,13 +216,13 @@ export class ElectronMainMenuFactory {
221
216
  this._toggledCommands.add(commandId);
222
217
  }
223
218
  } else {
224
- items.push(...this.handleDefault(menu, args, options));
219
+ items.push(...this.handleElectronDefault(menu, args, options));
225
220
  }
226
221
  }
227
222
  return items;
228
223
  }
229
224
 
230
- protected handleDefault(menuNode: MenuNode, args: any[] = [], options?: ElectronMenuOptions): Electron.MenuItemConstructorOptions[] {
225
+ protected handleElectronDefault(menuNode: MenuNode, args: any[] = [], options?: ElectronMenuOptions): Electron.MenuItemConstructorOptions[] {
231
226
  return [];
232
227
  }
233
228
 
@@ -18,44 +18,51 @@ import * as electron from '../../../shared/electron';
18
18
  import { inject, injectable } from 'inversify';
19
19
  import {
20
20
  Command, CommandContribution, CommandRegistry,
21
- isOSX, isWindows, MenuModelRegistry, MenuContribution, Disposable
21
+ isOSX, isWindows, MenuModelRegistry, MenuContribution, Disposable, nls
22
22
  } from '../../common';
23
- import { ApplicationShell, KeybindingContribution, KeybindingRegistry, PreferenceScope, PreferenceService } from '../../browser';
24
- import { FrontendApplication, FrontendApplicationContribution, CommonMenus } from '../../browser';
23
+ import {
24
+ ApplicationShell, codicon, ConfirmDialog, KeybindingContribution, KeybindingRegistry,
25
+ PreferenceScope, Widget, FrontendApplication, FrontendApplicationContribution, CommonMenus, CommonCommands, Dialog
26
+ } from '../../browser';
25
27
  import { ElectronMainMenuFactory } from './electron-main-menu-factory';
26
28
  import { FrontendApplicationStateService, FrontendApplicationState } from '../../browser/frontend-application-state';
29
+ import { FrontendApplicationConfigProvider } from '../../browser/frontend-application-config-provider';
30
+ import { RequestTitleBarStyle, Restart, TitleBarStyleAtStartup, TitleBarStyleChanged } from '../../electron-common/messaging/electron-messages';
27
31
  import { ZoomLevel } from '../window/electron-window-preferences';
32
+ import { BrowserMenuBarContribution } from '../../browser/menu/browser-menu-plugin';
33
+
34
+ import '../../../src/electron-browser/menu/electron-menu-style.css';
28
35
 
29
36
  export namespace ElectronCommands {
30
- export const TOGGLE_DEVELOPER_TOOLS: Command = {
37
+ export const TOGGLE_DEVELOPER_TOOLS = Command.toDefaultLocalizedCommand({
31
38
  id: 'theia.toggleDevTools',
32
39
  label: 'Toggle Developer Tools'
33
- };
34
- export const RELOAD: Command = {
40
+ });
41
+ export const RELOAD = Command.toDefaultLocalizedCommand({
35
42
  id: 'view.reload',
36
43
  label: 'Reload Window'
37
- };
38
- export const ZOOM_IN: Command = {
44
+ });
45
+ export const ZOOM_IN = Command.toDefaultLocalizedCommand({
39
46
  id: 'view.zoomIn',
40
47
  label: 'Zoom In'
41
- };
42
- export const ZOOM_OUT: Command = {
48
+ });
49
+ export const ZOOM_OUT = Command.toDefaultLocalizedCommand({
43
50
  id: 'view.zoomOut',
44
51
  label: 'Zoom Out'
45
- };
46
- export const RESET_ZOOM: Command = {
52
+ });
53
+ export const RESET_ZOOM = Command.toDefaultLocalizedCommand({
47
54
  id: 'view.resetZoom',
48
55
  label: 'Reset Zoom'
49
- };
50
- export const CLOSE_WINDOW: Command = {
56
+ });
57
+ export const CLOSE_WINDOW = Command.toDefaultLocalizedCommand({
51
58
  id: 'close.window',
52
59
  label: 'Close Window'
53
- };
54
- export const TOGGLE_FULL_SCREEN: Command = {
60
+ });
61
+ export const TOGGLE_FULL_SCREEN = Command.toDefaultLocalizedCommand({
55
62
  id: 'workbench.action.toggleFullScreen',
56
- category: 'View',
63
+ category: CommonCommands.VIEW_CATEGORY,
57
64
  label: 'Toggle Full Screen'
58
- };
65
+ });
59
66
  }
60
67
 
61
68
  export namespace ElectronMenus {
@@ -72,38 +79,33 @@ export namespace ElectronMenus {
72
79
  }
73
80
 
74
81
  @injectable()
75
- export class ElectronMenuContribution implements FrontendApplicationContribution, CommandContribution, MenuContribution, KeybindingContribution {
82
+ export class ElectronMenuContribution extends BrowserMenuBarContribution implements FrontendApplicationContribution, CommandContribution, MenuContribution, KeybindingContribution {
76
83
 
77
84
  @inject(FrontendApplicationStateService)
78
85
  protected readonly stateService: FrontendApplicationStateService;
79
86
 
80
- @inject(PreferenceService)
81
- protected readonly preferenceService: PreferenceService;
87
+ protected titleBarStyleChangeFlag = false;
88
+ protected titleBarStyle?: string;
82
89
 
83
90
  constructor(
84
91
  @inject(ElectronMainMenuFactory) protected readonly factory: ElectronMainMenuFactory,
85
92
  @inject(ApplicationShell) protected shell: ApplicationShell
86
- ) { }
93
+ ) {
94
+ super(factory);
95
+ }
87
96
 
88
97
  onStart(app: FrontendApplication): void {
89
- this.hideTopPanel(app);
90
- this.preferenceService.ready.then(() => {
91
- this.setMenu();
92
- electron.remote.getCurrentWindow().setMenuBarVisibility(true);
93
- });
98
+ this.handleTitleBarStyling(app);
94
99
  if (isOSX) {
95
100
  // OSX: Recreate the menus when changing windows.
96
101
  // OSX only has one menu bar for all windows, so we need to swap
97
102
  // between them as the user switches windows.
98
- electron.remote.getCurrentWindow().on('focus', () => this.setMenu());
103
+ electron.remote.getCurrentWindow().on('focus', () => this.setMenu(app));
99
104
  }
100
105
  // Make sure the application menu is complete, once the frontend application is ready.
101
106
  // https://github.com/theia-ide/theia/issues/5100
102
107
  let onStateChange: Disposable | undefined = undefined;
103
108
  const stateServiceListener = (state: FrontendApplicationState) => {
104
- if (state === 'ready') {
105
- this.setMenu();
106
- }
107
109
  if (state === 'closing_window') {
108
110
  if (!!onStateChange) {
109
111
  onStateChange.dispose();
@@ -119,6 +121,30 @@ export class ElectronMenuContribution implements FrontendApplicationContribution
119
121
  });
120
122
  }
121
123
 
124
+ handleTitleBarStyling(app: FrontendApplication): void {
125
+ this.hideTopPanel(app);
126
+ electron.ipcRenderer.on(TitleBarStyleAtStartup, (_event, style: string) => {
127
+ this.titleBarStyle = style;
128
+ this.preferenceService.ready.then(() => {
129
+ this.preferenceService.set('window.titleBarStyle', this.titleBarStyle, PreferenceScope.User);
130
+ });
131
+ });
132
+ electron.ipcRenderer.send(RequestTitleBarStyle);
133
+ this.preferenceService.ready.then(() => {
134
+ this.setMenu(app);
135
+ electron.remote.getCurrentWindow().setMenuBarVisibility(['classic', 'visible'].includes(this.preferenceService.get('window.menuBarVisibility', 'classic')));
136
+ });
137
+ this.preferenceService.onPreferenceChanged(change => {
138
+ if (change.preferenceName === 'window.titleBarStyle') {
139
+ if (this.titleBarStyleChangeFlag && this.titleBarStyle !== change.newValue && electron.remote.getCurrentWindow().isFocused()) {
140
+ electron.ipcRenderer.send(TitleBarStyleChanged, change.newValue);
141
+ this.handleRequiredRestart();
142
+ }
143
+ this.titleBarStyleChangeFlag = true;
144
+ }
145
+ });
146
+ }
147
+
122
148
  handleToggleMaximized(): void {
123
149
  const preference = this.preferenceService.get('window.menuBarVisibility');
124
150
  if (preference === 'classic') {
@@ -127,31 +153,95 @@ export class ElectronMenuContribution implements FrontendApplicationContribution
127
153
  }
128
154
 
129
155
  /**
130
- * Makes the `theia-top-panel` hidden as it is unused for the electron-based application.
156
+ * Hides the `theia-top-panel` depending on the selected `titleBarStyle`.
131
157
  * The `theia-top-panel` is used as the container of the main, application menu-bar for the
132
- * browser. Electron has it's own.
158
+ * browser. Native Electron has it's own.
133
159
  * By default, this method is called on application `onStart`.
134
160
  */
135
161
  protected hideTopPanel(app: FrontendApplication): void {
136
162
  const itr = app.shell.children();
137
163
  let child = itr.next();
138
164
  while (child) {
139
- // Top panel for the menu contribution is not required for Electron.
165
+ // Top panel for the menu contribution is not required for native Electron title bar.
140
166
  if (child.id === 'theia-top-panel') {
141
- child.setHidden(true);
142
- child = undefined;
167
+ child.setHidden(this.titleBarStyle !== 'custom');
168
+ break;
143
169
  } else {
144
170
  child = itr.next();
145
171
  }
146
172
  }
147
173
  }
148
174
 
149
- private setMenu(menu: electron.Menu | null = this.factory.createMenuBar(), electronWindow: electron.BrowserWindow = electron.remote.getCurrentWindow()): void {
175
+ protected setMenu(app: FrontendApplication, electronMenu: electron.Menu | null = this.factory.createElectronMenuBar(),
176
+ electronWindow: electron.BrowserWindow = electron.remote.getCurrentWindow()): void {
150
177
  if (isOSX) {
151
- electron.remote.Menu.setApplicationMenu(menu);
178
+ electron.remote.Menu.setApplicationMenu(electronMenu);
152
179
  } else {
180
+ this.hideTopPanel(app);
181
+ if (this.titleBarStyle === 'custom' && !this.menuBar) {
182
+ this.createCustomTitleBar(app, electronWindow);
183
+ }
153
184
  // Unix/Windows: Set the per-window menus
154
- electronWindow.setMenu(menu);
185
+ electronWindow.setMenu(electronMenu);
186
+ }
187
+ }
188
+
189
+ protected createCustomTitleBar(app: FrontendApplication, electronWindow: electron.BrowserWindow): void {
190
+ const dragPanel = new Widget();
191
+ dragPanel.id = 'theia-drag-panel';
192
+ app.shell.addWidget(dragPanel, { area: 'top' });
193
+ this.appendMenu(app.shell);
194
+ const controls = document.createElement('div');
195
+ controls.id = 'window-controls';
196
+ controls.append(
197
+ this.createControlButton('minimize', () => electronWindow.minimize()),
198
+ this.createControlButton('maximize', () => electronWindow.maximize()),
199
+ this.createControlButton('restore', () => electronWindow.unmaximize()),
200
+ this.createControlButton('close', () => electronWindow.close())
201
+ );
202
+ app.shell.topPanel.node.append(controls);
203
+ this.handleWindowControls(electronWindow);
204
+ }
205
+
206
+ protected handleWindowControls(electronWindow: electron.BrowserWindow): void {
207
+ toggleControlButtons();
208
+ electronWindow.on('maximize', toggleControlButtons);
209
+ electronWindow.on('unmaximize', toggleControlButtons);
210
+
211
+ function toggleControlButtons(): void {
212
+ if (electronWindow.isMaximized()) {
213
+ document.body.classList.add('maximized');
214
+ } else {
215
+ document.body.classList.remove('maximized');
216
+ }
217
+ }
218
+ }
219
+
220
+ protected createControlButton(id: string, handler: () => void): HTMLElement {
221
+ const button = document.createElement('div');
222
+ button.id = `${id}-button`;
223
+ button.className = `control-button ${codicon(`chrome-${id}`)}`;
224
+ button.addEventListener('click', handler);
225
+ return button;
226
+ }
227
+
228
+ protected async handleRequiredRestart(): Promise<void> {
229
+ const msgNode = document.createElement('div');
230
+ const message = document.createElement('p');
231
+ message.textContent = nls.localizeByDefault('A setting has changed that requires a restart to take effect');
232
+ const detail = document.createElement('p');
233
+ detail.textContent = nls.localizeByDefault(
234
+ 'Press the restart button to restart {0} and enable the setting.', FrontendApplicationConfigProvider.get().applicationName);
235
+ msgNode.append(message, detail);
236
+ const restart = nls.localizeByDefault('Restart');
237
+ const dialog = new ConfirmDialog({
238
+ title: restart,
239
+ msg: msgNode,
240
+ ok: restart,
241
+ cancel: Dialog.CANCEL
242
+ });
243
+ if (await dialog.open()) {
244
+ electron.ipcRenderer.send(Restart);
155
245
  }
156
246
  }
157
247
 
@@ -0,0 +1,84 @@
1
+ /********************************************************************************
2
+ * Copyright (C) 2021 TypeFox and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ #theia-drag-panel {
18
+ position: absolute;
19
+ display: block;
20
+ top: 0;
21
+ left: 0;
22
+ width: 100%;
23
+ height: calc(100% - 4px);
24
+ margin: 4px;
25
+ -webkit-app-region: drag !important;
26
+ }
27
+
28
+ #theia-top-panel > * {
29
+ -webkit-app-region: no-drag;
30
+ }
31
+
32
+ #window-controls {
33
+ display: grid;
34
+ grid-template-columns: repeat(3, 48px);
35
+ position: absolute;
36
+ top: 0;
37
+ right: 0;
38
+ height: 100%;
39
+ }
40
+
41
+ #window-controls .control-button {
42
+ display: flex;
43
+ line-height: 30px;
44
+ justify-content: center;
45
+ align-items: center;
46
+ width: 100%;
47
+ height: 100%;
48
+ }
49
+
50
+ #minimize-button {
51
+ grid-column: 1;
52
+ }
53
+
54
+ #maximize-button, #restore-button {
55
+ grid-column: 2;
56
+ }
57
+
58
+ #close-button {
59
+ grid-column: 3;
60
+ }
61
+
62
+ #window-controls .control-button {
63
+ user-select: none;
64
+ }
65
+
66
+ #window-controls .control-button:hover {
67
+ background: rgba(50%, 50%, 50%, 0.2);
68
+ }
69
+
70
+ #window-controls #close-button:hover {
71
+ background: #E81123;
72
+ }
73
+
74
+ #window-controls #close-button:hover:before {
75
+ color: white;
76
+ }
77
+
78
+ body:not(.maximized) #restore-button {
79
+ display: none;
80
+ }
81
+
82
+ body.maximized #maximize-button {
83
+ display: none;
84
+ }
@@ -15,7 +15,9 @@
15
15
  ********************************************************************************/
16
16
 
17
17
  import { interfaces } from 'inversify';
18
+ import { nls } from '../../common/nls';
18
19
  import { createPreferenceProxy, PreferenceContribution, PreferenceProxy, PreferenceSchema, PreferenceService } from '../../browser/preferences';
20
+ import { isOSX, isWindows } from '../../common';
19
21
 
20
22
  export namespace ZoomLevel {
21
23
  export const DEFAULT = 0;
@@ -36,13 +38,23 @@ export const electronWindowPreferencesSchema: PreferenceSchema = {
36
38
  'maximum': ZoomLevel.MAX,
37
39
  'scope': 'application',
38
40
  // eslint-disable-next-line max-len
39
- 'description': 'Adjust the zoom level of the window. The original size is 0 and each increment above (e.g. 1.0) or below (e.g. -1.0) represents zooming 20% larger or smaller. You can also enter decimals to adjust the zoom level with a finer granularity.'
41
+ 'description': nls.localizeByDefault('Adjust the zoom level of the window. The original size is 0 and each increment above (e.g. 1.0) or below (e.g. -1.0) represents zooming 20% larger or smaller. You can also enter decimals to adjust the zoom level with a finer granularity.')
42
+ },
43
+ 'window.titleBarStyle': {
44
+ type: 'string',
45
+ enum: ['native', 'custom'],
46
+ default: isWindows ? 'custom' : 'native',
47
+ scope: 'application',
48
+ // eslint-disable-next-line max-len
49
+ description: nls.localizeByDefault('Adjust the appearance of the window title bar. On Linux and Windows, this setting also affects the application and context menu appearances. Changes require a full restart to apply.'),
50
+ included: !isOSX
40
51
  },
41
52
  }
42
53
  };
43
54
 
44
55
  export class ElectronWindowConfiguration {
45
56
  'window.zoomLevel': number;
57
+ 'window.titleBarStyle': 'native' | 'custom';
46
58
  }
47
59
 
48
60
  export const ElectronWindowPreferenceContribution = Symbol('ElectronWindowPreferenceContribution');
@@ -16,7 +16,7 @@
16
16
 
17
17
  import { injectable, inject, postConstruct } from 'inversify';
18
18
  import { remote } from '../../../shared/electron';
19
- import { NewWindowOptions } from '../../browser/window/window-service';
19
+ import { NewWindowOptions } from '../../common/window';
20
20
  import { DefaultWindowService } from '../../browser/window/default-window-service';
21
21
  import { ElectronMainWindowService } from '../../electron-common/electron-main-window-service';
22
22
  import { ElectronWindowPreferences } from './electron-window-preferences';
@@ -14,7 +14,7 @@
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
16
 
17
- import { NewWindowOptions } from '../browser/window/window-service';
17
+ import { NewWindowOptions } from '../common/window';
18
18
 
19
19
  export const electronMainWindowServicePath = '/services/electron-window';
20
20
  export const ElectronMainWindowService = Symbol('ElectronMainWindowService');
@@ -0,0 +1,20 @@
1
+ /********************************************************************************
2
+ * Copyright (C) 2021 TypeFox and others.
3
+ *
4
+ * This program and the accompanying materials are made available under the
5
+ * terms of the Eclipse Public License v. 2.0 which is available at
6
+ * http://www.eclipse.org/legal/epl-2.0.
7
+ *
8
+ * This Source Code may also be made available under the following Secondary
9
+ * Licenses when the conditions for such availability set forth in the Eclipse
10
+ * Public License v. 2.0 are satisfied: GNU General Public License, version 2
11
+ * with the GNU Classpath Exception which is available at
12
+ * https://www.gnu.org/software/classpath/license.html.
13
+ *
14
+ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
+ ********************************************************************************/
16
+
17
+ export const RequestTitleBarStyle = 'requestTitleBarStyle';
18
+ export const TitleBarStyleChanged = 'titleBarStyleChanged';
19
+ export const TitleBarStyleAtStartup = 'titleBarStyleAtStartup';
20
+ export const Restart = 'restart';
@@ -15,7 +15,7 @@
15
15
  ********************************************************************************/
16
16
 
17
17
  import { inject, injectable, named } from 'inversify';
18
- import { screen, globalShortcut, app, BrowserWindow, BrowserWindowConstructorOptions, Event as ElectronEvent } from '../../shared/electron';
18
+ import { screen, globalShortcut, ipcMain, app, BrowserWindow, BrowserWindowConstructorOptions, Event as ElectronEvent } from '../../shared/electron';
19
19
  import * as path from 'path';
20
20
  import { Argv } from 'yargs';
21
21
  import { AddressInfo } from 'net';
@@ -30,7 +30,10 @@ import { ContributionProvider } from '../common/contribution-provider';
30
30
  import { ElectronSecurityTokenService } from './electron-security-token-service';
31
31
  import { ElectronSecurityToken } from '../electron-common/electron-token';
32
32
  import Storage = require('electron-store');
33
- import { DEFAULT_WINDOW_HASH } from '../browser/window/window-service';
33
+ import { isOSX, isWindows } from '../common';
34
+ import { RequestTitleBarStyle, Restart, TitleBarStyleAtStartup, TitleBarStyleChanged } from '../electron-common/messaging/electron-messages';
35
+ import { DEFAULT_WINDOW_HASH } from '../common/window';
36
+
34
37
  const createYargs: (argv?: string[], cwd?: string) => Argv = require('yargs/yargs');
35
38
 
36
39
  /**
@@ -180,6 +183,10 @@ export class ElectronMainApplication {
180
183
  readonly backendPort = this._backendPort.promise;
181
184
 
182
185
  protected _config: FrontendApplicationConfig | undefined;
186
+ protected useNativeWindowFrame: boolean = true;
187
+ protected didUseNativeWindowFrameOnStart = new Map<number, boolean>();
188
+ protected restarting = false;
189
+
183
190
  get config(): FrontendApplicationConfig {
184
191
  if (!this._config) {
185
192
  throw new Error('You have to start the application first.');
@@ -188,6 +195,7 @@ export class ElectronMainApplication {
188
195
  }
189
196
 
190
197
  async start(config: FrontendApplicationConfig): Promise<void> {
198
+ this.useNativeWindowFrame = this.getTitleBarStyle(config) === 'native';
191
199
  this._config = config;
192
200
  this.hookApplicationEvents();
193
201
  const port = await this.startBackend();
@@ -202,6 +210,23 @@ export class ElectronMainApplication {
202
210
  });
203
211
  }
204
212
 
213
+ protected getTitleBarStyle(config: FrontendApplicationConfig): 'native' | 'custom' {
214
+ if (isOSX) {
215
+ return 'native';
216
+ }
217
+ const storedFrame = this.electronStore.get('windowstate')?.frame;
218
+ if (storedFrame !== undefined) {
219
+ return !!storedFrame ? 'native' : 'custom';
220
+ }
221
+ if (config.preferences && config.preferences['window.titleBarStyle']) {
222
+ const titleBarStyle = config.preferences['window.titleBarStyle'];
223
+ if (titleBarStyle === 'native' || titleBarStyle === 'custom') {
224
+ return titleBarStyle;
225
+ }
226
+ }
227
+ return isWindows ? 'custom' : 'native';
228
+ }
229
+
205
230
  protected async launch(params: ElectronMainExecutionParams): Promise<void> {
206
231
  createYargs(params.argv, params.cwd)
207
232
  .command('$0 [file]', false,
@@ -231,6 +256,7 @@ export class ElectronMainApplication {
231
256
  async getLastWindowOptions(): Promise<TheiaBrowserWindowOptions> {
232
257
  const windowState: TheiaBrowserWindowOptions | undefined = this.electronStore.get('windowstate') || this.getDefaultTheiaWindowOptions();
233
258
  return {
259
+ frame: this.useNativeWindowFrame,
234
260
  ...windowState,
235
261
  ...this.getDefaultOptions()
236
262
  };
@@ -325,6 +351,7 @@ export class ElectronMainApplication {
325
351
  const y = Math.round(bounds.y + (bounds.height - height) / 2);
326
352
  const x = Math.round(bounds.x + (bounds.width - width) / 2);
327
353
  return {
354
+ frame: this.useNativeWindowFrame,
328
355
  isFullScreen: false,
329
356
  isMaximized: false,
330
357
  width,
@@ -346,31 +373,41 @@ export class ElectronMainApplication {
346
373
  * Save the window geometry state on every change.
347
374
  */
348
375
  protected attachSaveWindowState(electronWindow: BrowserWindow): void {
349
- const saveWindowState = () => {
350
- try {
351
- const bounds = electronWindow.getBounds();
352
- this.electronStore.set('windowstate', {
353
- isFullScreen: electronWindow.isFullScreen(),
354
- isMaximized: electronWindow.isMaximized(),
355
- width: bounds.width,
356
- height: bounds.height,
357
- x: bounds.x,
358
- y: bounds.y
359
- });
360
- } catch (e) {
361
- console.error('Error while saving window state:', e);
362
- }
363
- };
364
376
  let delayedSaveTimeout: NodeJS.Timer | undefined;
365
377
  const saveWindowStateDelayed = () => {
366
378
  if (delayedSaveTimeout) {
367
379
  clearTimeout(delayedSaveTimeout);
368
380
  }
369
- delayedSaveTimeout = setTimeout(saveWindowState, 1000);
381
+ delayedSaveTimeout = setTimeout(() => this.saveWindowState(electronWindow), 1000);
370
382
  };
371
- electronWindow.on('close', saveWindowState);
383
+ electronWindow.on('close', () => {
384
+ this.saveWindowState(electronWindow);
385
+ this.didUseNativeWindowFrameOnStart.delete(electronWindow.id);
386
+ });
372
387
  electronWindow.on('resize', saveWindowStateDelayed);
373
388
  electronWindow.on('move', saveWindowStateDelayed);
389
+ this.didUseNativeWindowFrameOnStart.set(electronWindow.id, this.useNativeWindowFrame);
390
+ }
391
+
392
+ protected saveWindowState(electronWindow: BrowserWindow): void {
393
+ // In some circumstances the `electronWindow` can be `null`
394
+ if (!electronWindow) {
395
+ return;
396
+ }
397
+ try {
398
+ const bounds = electronWindow.getBounds();
399
+ this.electronStore.set('windowstate', {
400
+ isFullScreen: electronWindow.isFullScreen(),
401
+ isMaximized: electronWindow.isMaximized(),
402
+ width: bounds.width,
403
+ height: bounds.height,
404
+ x: bounds.x,
405
+ y: bounds.y,
406
+ frame: this.useNativeWindowFrame
407
+ });
408
+ } catch (e) {
409
+ console.error('Error while saving window state:', e);
410
+ }
374
411
  }
375
412
 
376
413
  /**
@@ -475,6 +512,19 @@ export class ElectronMainApplication {
475
512
  app.on('will-quit', this.onWillQuit.bind(this));
476
513
  app.on('second-instance', this.onSecondInstance.bind(this));
477
514
  app.on('window-all-closed', this.onWindowAllClosed.bind(this));
515
+
516
+ ipcMain.on(TitleBarStyleChanged, ({ sender }, titleBarStyle: string) => {
517
+ this.useNativeWindowFrame = titleBarStyle === 'native';
518
+ this.saveWindowState(BrowserWindow.fromId(sender.id));
519
+ });
520
+
521
+ ipcMain.on(Restart, ({ sender }) => {
522
+ this.restart(sender.id);
523
+ });
524
+
525
+ ipcMain.on(RequestTitleBarStyle, ({ sender }) => {
526
+ sender.send(TitleBarStyleAtStartup, this.didUseNativeWindowFrameOnStart.get(sender.id) ? 'native' : 'custom');
527
+ });
478
528
  }
479
529
 
480
530
  protected onWillQuit(event: ElectronEvent): void {
@@ -493,7 +543,23 @@ export class ElectronMainApplication {
493
543
  }
494
544
 
495
545
  protected onWindowAllClosed(event: ElectronEvent): void {
496
- this.requestStop();
546
+ if (!this.restarting) {
547
+ this.requestStop();
548
+ }
549
+ }
550
+
551
+ protected restart(id: number): void {
552
+ this.restarting = true;
553
+ const window = BrowserWindow.fromId(id);
554
+ window.on('closed', async () => {
555
+ await this.launch({
556
+ secondInstance: false,
557
+ argv: this.processArgv.getProcessArgvWithoutBin(process.argv),
558
+ cwd: process.cwd()
559
+ });
560
+ this.restarting = false;
561
+ });
562
+ window.close();
497
563
  }
498
564
 
499
565
  protected async startContributions(): Promise<void> {