44 *--------------------------------------------------------------------------------------------*/
55
66import { app , ipcMain as ipc , systemPreferences , shell , Event , contentTracing , protocol } from 'electron' ;
7- import * as platform from 'vs/base/common/platform' ;
7+ import { IProcessEnvironment , isWindows , isMacintosh } from 'vs/base/common/platform' ;
88import { WindowsManager } from 'vs/code/electron-main/windows' ;
99import { IWindowsService , OpenContext , ActiveWindowManager } from 'vs/platform/windows/common/windows' ;
1010import { WindowsChannel } from 'vs/platform/windows/node/windowsIpc' ;
@@ -88,7 +88,7 @@ export class CodeApplication extends Disposable {
8888
8989 constructor (
9090 private mainIpcServer : Server ,
91- private userEnv : platform . IProcessEnvironment ,
91+ private userEnv : IProcessEnvironment ,
9292 @IInstantiationService private instantiationService : IInstantiationService ,
9393 @ILogService private logService : ILogService ,
9494 @IEnvironmentService private environmentService : IEnvironmentService ,
@@ -138,12 +138,27 @@ export class CodeApplication extends Disposable {
138138 app . on ( 'web-contents-created' , ( event : any , contents ) => {
139139 contents . on ( 'will-attach-webview' , ( event : Electron . Event , webPreferences , params ) => {
140140
141+ const isValidWebviewSource = ( source : string ) : boolean => {
142+ if ( ! source ) {
143+ return false ;
144+ }
145+
146+ if ( source === 'data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%20lang%3D%22en%22%20style%3D%22width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3Chead%3E%0D%0A%09%3Ctitle%3EVirtual%20Document%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%20style%3D%22margin%3A%200%3B%20overflow%3A%20hidden%3B%20width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3C%2Fbody%3E%0D%0A%3C%2Fhtml%3E' ) {
147+ return true ;
148+ }
149+
150+ const srcUri : any = URI . parse ( source ) . fsPath . toLowerCase ( ) ;
151+ const rootUri = URI . file ( this . environmentService . appRoot ) . fsPath . toLowerCase ( ) ;
152+
153+ return srcUri . startsWith ( rootUri + nativeSep ) ;
154+ } ;
155+
141156 // Ensure defaults
142157 delete webPreferences . preload ;
143158 webPreferences . nodeIntegration = false ;
144159
145160 // Verify URLs being loaded
146- if ( this . isValidWebviewSource ( params . src ) && this . isValidWebviewSource ( webPreferences . preloadURL ) ) {
161+ if ( isValidWebviewSource ( params . src ) && isValidWebviewSource ( webPreferences . preloadURL ) ) {
147162 return ;
148163 }
149164
@@ -168,85 +183,6 @@ export class CodeApplication extends Disposable {
168183 } ) ;
169184 } ) ;
170185
171- const connectionPool : Map < string , ActiveConnection > = new Map < string , ActiveConnection > ( ) ;
172-
173- class ActiveConnection {
174- private _authority : string ;
175- private _client : Promise < Client < RemoteAgentConnectionContext > > ;
176- private _disposeRunner : RunOnceScheduler ;
177-
178- constructor ( authority : string , host : string , port : number ) {
179- this . _authority = authority ;
180- this . _client = connectRemoteAgentManagement ( authority , host , port , `main` ) ;
181- this . _disposeRunner = new RunOnceScheduler ( ( ) => this . _dispose ( ) , 5000 ) ;
182- }
183-
184- private _dispose ( ) : void {
185- this . _disposeRunner . dispose ( ) ;
186- connectionPool . delete ( this . _authority ) ;
187- this . _client . then ( ( connection ) => {
188- connection . dispose ( ) ;
189- } ) ;
190- }
191-
192- public getClient ( ) : Promise < Client < RemoteAgentConnectionContext > > {
193- this . _disposeRunner . schedule ( ) ;
194- return this . _client ;
195- }
196- }
197-
198- const resolvedAuthorities = new Map < string , ResolvedAuthority > ( ) ;
199- ipc . on ( 'vscode:remoteAuthorityResolved' , ( event : any , data : ResolvedAuthority ) => {
200- resolvedAuthorities . set ( data . authority , data ) ;
201- } ) ;
202- const resolveAuthority = ( authority : string ) : ResolvedAuthority | null => {
203- if ( authority . indexOf ( '+' ) >= 0 ) {
204- if ( resolvedAuthorities . has ( authority ) ) {
205- return resolvedAuthorities . get ( authority ) ;
206- }
207- return null ;
208- } else {
209- const [ host , strPort ] = authority . split ( ':' ) ;
210- const port = parseInt ( strPort , 10 ) ;
211- return { authority, host, port, syncExtensions : false } ;
212- }
213- } ;
214-
215- protocol . registerBufferProtocol ( REMOTE_HOST_SCHEME , async ( request , callback ) => {
216- if ( request . method !== 'GET' ) {
217- return callback ( null ) ;
218- }
219- const uri = URI . parse ( request . url ) ;
220-
221- let activeConnection : ActiveConnection = null ;
222- if ( connectionPool . has ( uri . authority ) ) {
223- activeConnection = connectionPool . get ( uri . authority ) ;
224- } else {
225- let resolvedAuthority = resolveAuthority ( uri . authority ) ;
226- if ( ! resolvedAuthority ) {
227- callback ( null ) ;
228- return ;
229- }
230- activeConnection = new ActiveConnection ( uri . authority , resolvedAuthority . host , resolvedAuthority . port ) ;
231- connectionPool . set ( uri . authority , activeConnection ) ;
232- }
233- try {
234- const rawClient = await activeConnection . getClient ( ) ;
235- if ( connectionPool . has ( uri . authority ) ) { // not disposed in the meantime
236- const channel = rawClient . getChannel ( REMOTE_FILE_SYSTEM_CHANNEL_NAME ) ;
237-
238- // TODO@alex don't use call directly, wrap it around a `RemoteExtensionsFileSystemProvider`
239- const fileContents = await channel . call < Uint8Array > ( 'readFile' , [ uri ] ) ;
240- callback ( Buffer . from ( fileContents ) ) ;
241- } else {
242- callback ( null ) ;
243- }
244- } catch ( err ) {
245- errors . onUnexpectedError ( err ) ;
246- callback ( null ) ;
247- }
248- } ) ;
249-
250186 let macOpenFileURIs : URI [ ] = [ ] ;
251187 let runningTimeout : any = null ;
252188 app . on ( 'open-file' , ( event : Event , path : string ) => {
@@ -315,39 +251,10 @@ export class CodeApplication extends Disposable {
315251 }
316252 } ) ;
317253
318- ipc . on ( 'vscode:toggleDevTools' , ( event : Event ) => {
319- event . sender . toggleDevTools ( ) ;
320- } ) ;
321-
322- ipc . on ( 'vscode:openDevTools' , ( event : Event ) => {
323- event . sender . openDevTools ( ) ;
324- } ) ;
325-
326- ipc . on ( 'vscode:reloadWindow' , ( event : Event ) => {
327- event . sender . reload ( ) ;
328- } ) ;
329-
330- // Keyboard layout changes
331- KeyboardLayoutMonitor . INSTANCE . onDidChangeKeyboardLayout ( ( ) => {
332- if ( this . windowsMainService ) {
333- this . windowsMainService . sendToAll ( 'vscode:keyboardLayoutChanged' , false ) ;
334- }
335- } ) ;
336- }
337-
338- private isValidWebviewSource ( source : string ) : boolean {
339- if ( ! source ) {
340- return false ;
341- }
342-
343- if ( source === 'data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%20lang%3D%22en%22%20style%3D%22width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3Chead%3E%0D%0A%09%3Ctitle%3EVirtual%20Document%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%20style%3D%22margin%3A%200%3B%20overflow%3A%20hidden%3B%20width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3C%2Fbody%3E%0D%0A%3C%2Fhtml%3E' ) {
344- return true ;
345- }
346-
347- const srcUri : any = URI . parse ( source ) . fsPath . toLowerCase ( ) ;
348- const rootUri = URI . file ( this . environmentService . appRoot ) . fsPath . toLowerCase ( ) ;
254+ ipc . on ( 'vscode:toggleDevTools' , ( event : Event ) => event . sender . toggleDevTools ( ) ) ;
255+ ipc . on ( 'vscode:openDevTools' , ( event : Event ) => event . sender . openDevTools ( ) ) ;
349256
350- return srcUri . startsWith ( rootUri + nativeSep ) ;
257+ ipc . on ( 'vscode:reloadWindow' , ( event : Event ) => event . sender . reload ( ) ) ;
351258 }
352259
353260 private onUnexpectedError ( err : Error ) : void {
@@ -391,7 +298,7 @@ export class CodeApplication extends Disposable {
391298 // This will help Windows to associate the running program with
392299 // any shortcut that is pinned to the taskbar and prevent showing
393300 // two icons in the taskbar for the same app.
394- if ( platform . isWindows && product . win32AppUserModelId ) {
301+ if ( isWindows && product . win32AppUserModelId ) {
395302 app . setAppUserModelId ( product . win32AppUserModelId ) ;
396303 }
397304
@@ -402,7 +309,7 @@ export class CodeApplication extends Disposable {
402309 // Explicitly opt out of the patch here before creating any windows.
403310 // See: https://github.com/Microsoft/vscode/issues/35361#issuecomment-399794085
404311 try {
405- if ( platform . isMacintosh && this . configurationService . getValue < boolean > ( 'window.nativeTabs' ) === true && ! systemPreferences . getUserDefault ( 'NSUseImprovedLayoutPass' , 'boolean' ) ) {
312+ if ( isMacintosh && this . configurationService . getValue < boolean > ( 'window.nativeTabs' ) === true && ! systemPreferences . getUserDefault ( 'NSUseImprovedLayoutPass' , 'boolean' ) ) {
406313 systemPreferences . setUserDefault ( 'NSUseImprovedLayoutPass' , 'boolean' , true as any ) ;
407314 }
408315 } catch ( error ) {
@@ -631,8 +538,6 @@ export class CodeApplication extends Disposable {
631538 // Propagate to clients
632539 const windowsMainService = this . windowsMainService = accessor . get ( IWindowsMainService ) ; // TODO@Joao : unfold this
633540
634- const args = this . environmentService . args ;
635-
636541 // Create a URL handler which forwards to the last active window
637542 const activeWindowManager = new ActiveWindowManager ( windowsService ) ;
638543 const activeWindowRouter = new StaticRouter ( ctx => activeWindowManager . getActiveClientId ( ) . then ( id => ctx === id ) ) ;
@@ -641,7 +546,7 @@ export class CodeApplication extends Disposable {
641546
642547 // On Mac, Code can be running without any open windows, so we must create a window to handle urls,
643548 // if there is none
644- if ( platform . isMacintosh ) {
549+ if ( isMacintosh ) {
645550 const environmentService = accessor . get ( IEnvironmentService ) ;
646551
647552 urlService . registerHandler ( {
@@ -662,6 +567,7 @@ export class CodeApplication extends Disposable {
662567 urlService . registerHandler ( multiplexURLHandler ) ;
663568
664569 // Watch Electron URLs and forward them to the UrlService
570+ const args = this . environmentService . args ;
665571 const urls = args [ 'open-url' ] ? args . _urls : [ ] ;
666572 const urlListener = new ElectronURLListener ( urls , urlService , this . windowsMainService ) ;
667573 this . _register ( urlListener ) ;
@@ -690,7 +596,7 @@ export class CodeApplication extends Disposable {
690596 const windowsMainService = accessor . get ( IWindowsMainService ) ;
691597
692598 let windowsMutex : Mutex | null = null ;
693- if ( platform . isWindows ) {
599+ if ( isWindows ) {
694600
695601 // Setup Windows mutex
696602 try {
@@ -726,6 +632,14 @@ export class CodeApplication extends Disposable {
726632 }
727633 }
728634
635+ // Remote Authorities
636+ this . handleRemoteAuthorities ( ) ;
637+
638+ // Keyboard layout changes
639+ KeyboardLayoutMonitor . INSTANCE . onDidChangeKeyboardLayout ( ( ) => {
640+ this . windowsMainService . sendToAll ( 'vscode:keyboardLayoutChanged' , false ) ;
641+ } ) ;
642+
729643 // Jump List
730644 this . historyMainService . updateWindowsJumpList ( ) ;
731645 this . historyMainService . onRecentlyOpenedChange ( ( ) => this . historyMainService . updateWindowsJumpList ( ) ) ;
@@ -734,4 +648,87 @@ export class CodeApplication extends Disposable {
734648 const sharedProcessSpawn = this . _register ( new RunOnceScheduler ( ( ) => getShellEnvironment ( ) . then ( userEnv => this . sharedProcess . spawn ( userEnv ) ) , 3000 ) ) ;
735649 sharedProcessSpawn . schedule ( ) ;
736650 }
651+
652+ private handleRemoteAuthorities ( ) : void {
653+ const connectionPool : Map < string , ActiveConnection > = new Map < string , ActiveConnection > ( ) ;
654+
655+ class ActiveConnection {
656+ private _authority : string ;
657+ private _client : Promise < Client < RemoteAgentConnectionContext > > ;
658+ private _disposeRunner : RunOnceScheduler ;
659+
660+ constructor ( authority : string , host : string , port : number ) {
661+ this . _authority = authority ;
662+ this . _client = connectRemoteAgentManagement ( authority , host , port , `main` ) ;
663+ this . _disposeRunner = new RunOnceScheduler ( ( ) => this . _dispose ( ) , 5000 ) ;
664+ }
665+
666+ private _dispose ( ) : void {
667+ this . _disposeRunner . dispose ( ) ;
668+ connectionPool . delete ( this . _authority ) ;
669+ this . _client . then ( ( connection ) => {
670+ connection . dispose ( ) ;
671+ } ) ;
672+ }
673+
674+ public getClient ( ) : Promise < Client < RemoteAgentConnectionContext > > {
675+ this . _disposeRunner . schedule ( ) ;
676+ return this . _client ;
677+ }
678+ }
679+
680+ const resolvedAuthorities = new Map < string , ResolvedAuthority > ( ) ;
681+ ipc . on ( 'vscode:remoteAuthorityResolved' , ( event : any , data : ResolvedAuthority ) => {
682+ resolvedAuthorities . set ( data . authority , data ) ;
683+ } ) ;
684+
685+ const resolveAuthority = ( authority : string ) : ResolvedAuthority | null => {
686+ if ( authority . indexOf ( '+' ) >= 0 ) {
687+ if ( resolvedAuthorities . has ( authority ) ) {
688+ return resolvedAuthorities . get ( authority ) ;
689+ }
690+ return null ;
691+ } else {
692+ const [ host , strPort ] = authority . split ( ':' ) ;
693+ const port = parseInt ( strPort , 10 ) ;
694+ return { authority, host, port, syncExtensions : false } ;
695+ }
696+ } ;
697+
698+ protocol . registerBufferProtocol ( REMOTE_HOST_SCHEME , async ( request , callback ) => {
699+ if ( request . method !== 'GET' ) {
700+ return callback ( null ) ;
701+ }
702+ const uri = URI . parse ( request . url ) ;
703+
704+ let activeConnection : ActiveConnection = null ;
705+ if ( connectionPool . has ( uri . authority ) ) {
706+ activeConnection = connectionPool . get ( uri . authority ) ;
707+ } else {
708+ let resolvedAuthority = resolveAuthority ( uri . authority ) ;
709+ if ( ! resolvedAuthority ) {
710+ callback ( null ) ;
711+ return ;
712+ }
713+ activeConnection = new ActiveConnection ( uri . authority , resolvedAuthority . host , resolvedAuthority . port ) ;
714+ connectionPool . set ( uri . authority , activeConnection ) ;
715+ }
716+ try {
717+ const rawClient = await activeConnection . getClient ( ) ;
718+ if ( connectionPool . has ( uri . authority ) ) { // not disposed in the meantime
719+ const channel = rawClient . getChannel ( REMOTE_FILE_SYSTEM_CHANNEL_NAME ) ;
720+
721+ // TODO@alex don't use call directly, wrap it around a `RemoteExtensionsFileSystemProvider`
722+ const fileContents = await channel . call < Uint8Array > ( 'readFile' , [ uri ] ) ;
723+ callback ( Buffer . from ( fileContents ) ) ;
724+ } else {
725+ callback ( null ) ;
726+ }
727+ } catch ( err ) {
728+ errors . onUnexpectedError ( err ) ;
729+ callback ( null ) ;
730+ }
731+ } ) ;
732+ }
737733}
734+
0 commit comments