2
2
using System . Collections . Generic ;
3
3
using System . Diagnostics ;
4
4
using System . IO ;
5
- using System . IO . Pipes ;
6
5
using System . Net . Http ;
7
6
using System . Reflection ;
8
7
using System . Text ;
9
8
using System . Text . Json ;
10
9
using System . Threading ;
11
10
using System . Threading . Tasks ;
12
- using System . Linq ;
13
11
14
12
using Avalonia ;
15
13
using Avalonia . Controls ;
@@ -48,8 +46,6 @@ public static void Main(string[] args)
48
46
Environment . Exit ( exitTodo ) ;
49
47
else if ( TryLaunchAsRebaseMessageEditor ( args , out int exitMessage ) )
50
48
Environment . Exit ( exitMessage ) ;
51
- else if ( TrySendArgsToExistingInstance ( args ) )
52
- Environment . Exit ( 0 ) ;
53
49
else
54
50
BuildAvaloniaApp ( ) . StartWithClassicDesktopLifetime ( args ) ;
55
51
}
@@ -81,44 +77,6 @@ public static AppBuilder BuildAvaloniaApp()
81
77
return builder ;
82
78
}
83
79
84
- private static bool TrySendArgsToExistingInstance ( string [ ] args )
85
- {
86
- if ( args == null || args . Length != 1 || ! Directory . Exists ( args [ 0 ] ) )
87
- return false ;
88
-
89
- var pref = ViewModels . Preferences . Instance ;
90
-
91
- if ( ! pref . OpenReposInNewTab )
92
- return false ;
93
-
94
- try
95
- {
96
- var processes = Process . GetProcessesByName ( "SourceGit" ) ;
97
-
98
- if ( processes . Length <= 1 )
99
- return false ;
100
-
101
- using var client = new NamedPipeClientStream ( "." , "SourceGitIPC" , PipeDirection . Out ) ;
102
-
103
- client . Connect ( 1000 ) ;
104
-
105
- if ( client . IsConnected )
106
- {
107
- using var writer = new StreamWriter ( client ) ;
108
-
109
- writer . WriteLine ( args [ 0 ] ) ;
110
- writer . Flush ( ) ;
111
-
112
- return true ;
113
- }
114
- }
115
- catch ( Exception )
116
- {
117
- }
118
-
119
- return false ;
120
- }
121
-
122
80
private static void LogException ( Exception ex )
123
81
{
124
82
if ( ex == null )
@@ -370,13 +328,7 @@ public override void Initialize()
370
328
AvaloniaXamlLoader . Load ( this ) ;
371
329
372
330
var pref = ViewModels . Preferences . Instance ;
373
-
374
- pref . PropertyChanged += ( s , e ) => {
375
- pref . Save ( ) ;
376
-
377
- if ( e . PropertyName . Equals ( nameof ( ViewModels . Preferences . OpenReposInNewTab ) ) )
378
- HandleOpenReposInNewTabChanged ( ) ;
379
- } ;
331
+ pref . PropertyChanged += ( _ , _ ) => pref . Save ( ) ;
380
332
381
333
SetLocale ( pref . Locale ) ;
382
334
SetTheme ( pref . Theme , pref . ThemeOverrides ) ;
@@ -395,7 +347,17 @@ public override void OnFrameworkInitializationCompleted()
395
347
if ( TryLaunchAsAskpass ( desktop ) )
396
348
return ;
397
349
398
- TryLaunchAsNormal ( desktop ) ;
350
+ _ipcChannel = new Models . IpcChannel ( ) ;
351
+ if ( ! _ipcChannel . IsFirstInstance )
352
+ {
353
+ _ipcChannel . SendToFirstInstance ( desktop . Args is { Length : 1 } ? desktop . Args [ 0 ] : string . Empty ) ;
354
+ Quit ( 0 ) ;
355
+ }
356
+ else
357
+ {
358
+ _ipcChannel . MessageReceived += TryOpenRepository ;
359
+ TryLaunchAsNormal ( desktop ) ;
360
+ }
399
361
}
400
362
}
401
363
#endregion
@@ -533,104 +495,33 @@ private void TryLaunchAsNormal(IClassicDesktopStyleApplicationLifetime desktop)
533
495
if ( desktop . Args != null && desktop . Args . Length == 1 && Directory . Exists ( desktop . Args [ 0 ] ) )
534
496
startupRepo = desktop . Args [ 0 ] ;
535
497
536
- _launcher = new ViewModels . Launcher ( startupRepo ) ;
537
- desktop . MainWindow = new Views . Launcher ( ) { DataContext = _launcher } ;
538
-
539
498
var pref = ViewModels . Preferences . Instance ;
499
+ pref . SetCanModify ( ) ;
540
500
541
- HandleOpenReposInNewTabChanged ( ) ;
501
+ _launcher = new ViewModels . Launcher ( startupRepo ) ;
502
+ desktop . MainWindow = new Views . Launcher ( ) { DataContext = _launcher } ;
503
+ desktop . Exit += ( _ , _ ) => _ipcChannel . Dispose ( ) ;
542
504
543
505
#if ! DISABLE_UPDATE_DETECTION
544
506
if ( pref . ShouldCheck4UpdateOnStartup ( ) )
545
507
Check4Update ( ) ;
546
508
#endif
547
509
}
548
510
549
- private void HandleOpenReposInNewTabChanged ( )
511
+ private void TryOpenRepository ( string repo )
550
512
{
551
- var pref = ViewModels . Preferences . Instance ;
552
-
553
- if ( pref . OpenReposInNewTab )
554
- {
555
- if ( _ipcServerTask == null || _ipcServerTask . IsCompleted )
556
- {
557
- // Start IPC server
558
- _ipcServerCts = new CancellationTokenSource ( ) ;
559
- _ipcServerTask = Task . Run ( ( ) => StartIPCServer ( _ipcServerCts . Token ) ) ;
560
- }
561
- }
562
- else
563
- {
564
- // Stop IPC server if running
565
- if ( _ipcServerCts != null && ! _ipcServerCts . IsCancellationRequested )
566
- {
567
- _ipcServerCts . Cancel ( ) ;
568
- _ipcServerCts . Dispose ( ) ;
569
- _ipcServerCts = null ;
570
- }
571
- _ipcServerTask = null ;
572
- }
573
- }
513
+ if ( string . IsNullOrEmpty ( repo ) || ! Directory . Exists ( repo ) )
514
+ return ;
574
515
575
- private void StartIPCServer ( CancellationToken cancellationToken )
576
- {
577
- try
516
+ var test = new Commands . QueryRepositoryRootPath ( repo ) . ReadToEnd ( ) ;
517
+ if ( test . IsSuccess && ! string . IsNullOrEmpty ( test . StdOut ) )
578
518
{
579
- while ( ! cancellationToken . IsCancellationRequested )
519
+ Dispatcher . UIThread . Invoke ( ( ) =>
580
520
{
581
- using var server = new NamedPipeServerStream ( "SourceGitIPC" , PipeDirection . In ) ;
582
-
583
- // Use WaitForConnectionAsync with cancellation token
584
- try
585
- {
586
- Task connectionTask = server . WaitForConnectionAsync ( cancellationToken ) ;
587
- connectionTask . Wait ( cancellationToken ) ;
588
- }
589
- catch ( OperationCanceledException )
590
- {
591
- return ;
592
- }
593
- catch ( AggregateException ae ) when ( ae . InnerExceptions . Any ( e => e is OperationCanceledException ) )
594
- {
595
- return ;
596
- }
597
-
598
- // Process the connection
599
- using var reader = new StreamReader ( server ) ;
600
- var repoPath = reader . ReadLine ( ) ;
601
-
602
- if ( ! string . IsNullOrEmpty ( repoPath ) && Directory . Exists ( repoPath ) )
603
- {
604
- Dispatcher . UIThread . Post ( ( ) =>
605
- {
606
- try
607
- {
608
- var test = new Commands . QueryRepositoryRootPath ( repoPath ) . ReadToEnd ( ) ;
609
-
610
- if ( test . IsSuccess && ! string . IsNullOrEmpty ( test . StdOut ) )
611
- {
612
- var repoRootPath = test . StdOut . Trim ( ) ;
613
- var pref = ViewModels . Preferences . Instance ;
614
- var node = pref . FindOrAddNodeByRepositoryPath ( repoRootPath , null , false ) ;
615
-
616
- ViewModels . Welcome . Instance . Refresh ( ) ;
617
-
618
- _launcher ? . OpenRepositoryInTab ( node , null ) ;
619
-
620
- if ( ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop && desktop . MainWindow != null )
621
- desktop . MainWindow . Activate ( ) ;
622
- }
623
- }
624
- catch ( Exception )
625
- {
626
- }
627
- } ) ;
628
- }
629
- }
630
- }
631
- catch ( Exception )
632
- {
633
- // Pipe server failed, we can just exit the thread
521
+ var node = ViewModels . Preferences . Instance . FindOrAddNodeByRepositoryPath ( test . StdOut . Trim ( ) , null , false ) ;
522
+ ViewModels . Welcome . Instance . Refresh ( ) ;
523
+ _launcher ? . OpenRepositoryInTab ( node , null ) ;
524
+ } ) ;
634
525
}
635
526
}
636
527
@@ -719,11 +610,10 @@ private string FixFontFamilyName(string input)
719
610
return trimmed . Count > 0 ? string . Join ( ',' , trimmed ) : string . Empty ;
720
611
}
721
612
613
+ private Models . IpcChannel _ipcChannel = null ;
722
614
private ViewModels . Launcher _launcher = null ;
723
615
private ResourceDictionary _activeLocale = null ;
724
616
private ResourceDictionary _themeOverrides = null ;
725
617
private ResourceDictionary _fontsOverrides = null ;
726
- private Task _ipcServerTask = null ;
727
- private CancellationTokenSource _ipcServerCts = null ;
728
618
}
729
619
}
0 commit comments