Skip to content

Commit 7de9309

Browse files
committed
A kind of a single instance mode
only first launched instance creates system tray icon and does not quit
1 parent 5ca0238 commit 7de9309

File tree

7 files changed

+65
-7
lines changed

7 files changed

+65
-7
lines changed

src/App.axaml.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ public static void SetTheme(string theme, string themeOverridesFile)
169169
}
170170
}
171171

172-
public static void SetupTrayIcon(bool enable)
172+
public void SetupTrayIcon(bool enable)
173173
{
174-
if (enable)
174+
if (enable && Native.OS.EnsureSingleInstance())
175175
{
176176
var icons = new TrayIcons {
177177
new TrayIcon {
@@ -186,6 +186,7 @@ public static void SetupTrayIcon(bool enable)
186186
};
187187
icons[0].Clicked += (_, _) => ToggleWindow();
188188
TrayIcon.SetIcons(Current, icons);
189+
_createdSystemTrayIcon = true;
189190
}
190191
}
191192

@@ -519,11 +520,11 @@ private void TryLaunchedAsNormal(IClassicDesktopStyleApplicationLifetime desktop
519520
startupRepo = desktop.Args[0];
520521

521522
var pref = ViewModels.Preference.Instance;
522-
if (pref.SystemTrayIcon) {
523+
if (_createdSystemTrayIcon) {
523524
desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown;
524525
}
525526

526-
_launcher = new ViewModels.Launcher(startupRepo);
527+
_launcher = new ViewModels.Launcher(startupRepo, _createdSystemTrayIcon);
527528
desktop.MainWindow = new Views.Launcher() { DataContext = _launcher };
528529

529530
#if !DISABLE_UPDATE_DETECTION
@@ -589,5 +590,6 @@ private void ShowSelfUpdateResult(object data)
589590
private ResourceDictionary _activeLocale = null;
590591
private ResourceDictionary _themeOverrides = null;
591592
private ResourceDictionary _fontsOverrides = null;
593+
private bool _createdSystemTrayIcon = false;
592594
}
593595
}

src/Native/Linux.cs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace SourceGit.Native
1111
[SupportedOSPlatform("linux")]
1212
internal class Linux : OS.IBackend
1313
{
14+
private FileStream _fs = null;
1415
public void SetupApp(AppBuilder builder)
1516
{
1617
builder.With(new X11PlatformOptions() { EnableIme = true });
@@ -97,6 +98,26 @@ public void OpenWithDefaultEditor(string file)
9798
}
9899
}
99100

101+
public bool EnsureSingleInstance()
102+
{
103+
var pidfile = Path.Combine(Path.GetTempPath(), "sourcegit.pid");
104+
var pid = Process.GetCurrentProcess().Id.ToString();
105+
Console.WriteLine("pid " + pid);
106+
107+
try
108+
{
109+
_fs = File.OpenWrite(pidfile);
110+
_fs.Lock(0, 1000);
111+
new StreamWriter(_fs).Write(pid);
112+
return true;
113+
}
114+
catch (IOException)
115+
{
116+
Console.WriteLine("another SourceGit is running");
117+
return false;
118+
}
119+
}
120+
100121
private string FindExecutable(string filename)
101122
{
102123
var pathVariable = Environment.GetEnvironmentVariable("PATH") ?? string.Empty;

src/Native/MacOS.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,5 +86,7 @@ public void OpenWithDefaultEditor(string file)
8686
{
8787
Process.Start("open", $"\"{file}\"");
8888
}
89+
90+
public bool EnsureSingleInstance() { return true; }
8991
}
9092
}

src/Native/OS.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public interface IBackend
2121
void OpenInFileManager(string path, bool select);
2222
void OpenBrowser(string url);
2323
void OpenWithDefaultEditor(string file);
24+
25+
bool EnsureSingleInstance();
2426
}
2527

2628
public static string DataDir { get; private set; } = string.Empty;
@@ -123,6 +125,11 @@ public static void OpenWithDefaultEditor(string file)
123125
_backend.OpenWithDefaultEditor(file);
124126
}
125127

128+
public static bool EnsureSingleInstance()
129+
{
130+
return _backend.EnsureSingleInstance();
131+
}
132+
126133
private static IBackend _backend = null;
127134
}
128135
}

src/Native/Windows.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ namespace SourceGit.Native
1414
[SupportedOSPlatform("windows")]
1515
internal class Windows : OS.IBackend
1616
{
17+
private FileStream _fs = null;
18+
1719
[StructLayout(LayoutKind.Sequential)]
1820
internal struct RTL_OSVERSIONINFOEX
1921
{
@@ -393,5 +395,25 @@ private string FindVSSolutionFile(DirectoryInfo dir, int leftDepth)
393395

394396
return null;
395397
}
398+
399+
public bool EnsureSingleInstance()
400+
{
401+
var pidfile = Path.Combine(Path.GetTempPath(), "sourcegit.pid");
402+
var pid = Process.GetCurrentProcess().Id.ToString();
403+
Console.WriteLine("pid " + pid);
404+
405+
try
406+
{
407+
_fs = File.OpenWrite(pidfile);
408+
_fs.Lock(0, 1000);
409+
new StreamWriter(_fs).Write(pid);
410+
return true;
411+
}
412+
catch (IOException)
413+
{
414+
Console.WriteLine("another SourceGit is running");
415+
return false;
416+
}
417+
}
396418
}
397419
}

src/ViewModels/Launcher.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ public Workspace ActiveWorkspace
2929
private set => SetProperty(ref _activeWorkspace, value);
3030
}
3131

32+
public bool InterceptQuit { get; } = false;
33+
3234
public LauncherPage ActivePage
3335
{
3436
get => _activePage;
@@ -44,9 +46,10 @@ public LauncherPage ActivePage
4446
}
4547
}
4648

47-
public Launcher(string startupRepo)
49+
public Launcher(string startupRepo, bool interceptClosing)
4850
{
4951
_ignoreIndexChange = true;
52+
InterceptQuit = interceptClosing;
5053

5154
Pages = new AvaloniaList<LauncherPage>();
5255
AddNewTab();

src/Views/Launcher.axaml.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,12 @@ protected override void OnKeyUp(KeyEventArgs e)
256256
protected override void OnClosing(WindowClosingEventArgs e)
257257
{
258258
var pref = ViewModels.Preference.Instance;
259-
if (pref.SystemTrayIcon) {
259+
var launcher = DataContext as ViewModels.Launcher;
260+
if (pref.SystemTrayIcon && launcher is { InterceptQuit: true }) {
260261
e.Cancel = true;
261262
Hide();
262263
} else {
263-
(DataContext as ViewModels.Launcher)?.Quit(Width, Height);
264+
launcher?.Quit(Width, Height);
264265
}
265266
base.OnClosing(e);
266267
}

0 commit comments

Comments
 (0)