Change icon and name
This commit is contained in:
1 parent
752c7b4305
commit
b6d40deffd
6 files changed
+313
-20
No files matched your search
@@ -0,0 +1,48 @@
|
|||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace FoxBrowser.Core;
|
||||||
|
|
||||||
|
public sealed class AppSettings
|
||||||
|
{
|
||||||
|
public string AppDisplayName { get; set; } = "FoxBrowser";
|
||||||
|
public string? AppIconPath { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AppSettingsStore
|
||||||
|
{
|
||||||
|
public static string SettingsPath => Path.Combine(AppContext.BaseDirectory, "settings.json");
|
||||||
|
|
||||||
|
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
DefaultIgnoreCondition = JsonIgnoreCondition.Never
|
||||||
|
};
|
||||||
|
|
||||||
|
public static AppSettings Load()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!File.Exists(SettingsPath)) return new AppSettings();
|
||||||
|
var settings = JsonSerializer.Deserialize<AppSettings>(File.ReadAllText(SettingsPath), JsonOptions);
|
||||||
|
if (settings is null) return new AppSettings();
|
||||||
|
if (string.IsNullOrWhiteSpace(settings.AppDisplayName)) settings.AppDisplayName = "FoxBrowser";
|
||||||
|
if (!string.IsNullOrWhiteSpace(settings.AppIconPath) && !File.Exists(settings.AppIconPath))
|
||||||
|
settings.AppIconPath = null;
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return new AppSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Save(AppSettings settings)
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(AppContext.BaseDirectory);
|
||||||
|
var tempPath = SettingsPath + ".tmp";
|
||||||
|
File.WriteAllText(tempPath, JsonSerializer.Serialize(settings, JsonOptions));
|
||||||
|
File.Move(tempPath, SettingsPath, overwrite: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,23 +13,32 @@ public sealed class AudioSessionLabeler : IDisposable
|
|||||||
{
|
{
|
||||||
private const uint SnapshotProcess = 0x00000002;
|
private const uint SnapshotProcess = 0x00000002;
|
||||||
private readonly uint _rootProcessId;
|
private readonly uint _rootProcessId;
|
||||||
private readonly string _iconPath;
|
private string _displayName;
|
||||||
|
private string _iconPath;
|
||||||
private readonly MMDeviceEnumerator _devices = new();
|
private readonly MMDeviceEnumerator _devices = new();
|
||||||
private readonly AudioSessionManager _sessions;
|
private readonly AudioSessionManager _sessions;
|
||||||
private readonly System.Threading.Timer _refreshTimer;
|
private readonly System.Threading.Timer _refreshTimer;
|
||||||
private readonly object _gate = new();
|
private readonly object _gate = new();
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
|
|
||||||
public AudioSessionLabeler(uint rootProcessId, string iconPath)
|
public AudioSessionLabeler(uint rootProcessId, string iconPath, string displayName = "FoxBrowser")
|
||||||
{
|
{
|
||||||
_rootProcessId = rootProcessId;
|
_rootProcessId = rootProcessId;
|
||||||
_iconPath = iconPath;
|
_iconPath = iconPath;
|
||||||
|
_displayName = string.IsNullOrWhiteSpace(displayName) ? "FoxBrowser" : displayName;
|
||||||
var device = _devices.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
|
var device = _devices.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
|
||||||
_sessions = device.AudioSessionManager;
|
_sessions = device.AudioSessionManager;
|
||||||
_sessions.OnSessionCreated += OnSessionCreated;
|
_sessions.OnSessionCreated += OnSessionCreated;
|
||||||
_refreshTimer = new System.Threading.Timer(_ => RefreshAndLabel(), null, TimeSpan.Zero, TimeSpan.FromSeconds(2));
|
_refreshTimer = new System.Threading.Timer(_ => RefreshAndLabel(), null, TimeSpan.Zero, TimeSpan.FromSeconds(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateIdentity(string displayName, string iconPath)
|
||||||
|
{
|
||||||
|
_displayName = string.IsNullOrWhiteSpace(displayName) ? "FoxBrowser" : displayName;
|
||||||
|
_iconPath = iconPath;
|
||||||
|
RefreshAndLabel();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnSessionCreated(object sender, IAudioSessionControl nativeSession)
|
private void OnSessionCreated(object sender, IAudioSessionControl nativeSession)
|
||||||
{
|
{
|
||||||
LabelSession(new AudioSessionControl(nativeSession), disposeAfter: true);
|
LabelSession(new AudioSessionControl(nativeSession), disposeAfter: true);
|
||||||
@@ -64,7 +73,7 @@ public sealed class AudioSessionLabeler : IDisposable
|
|||||||
{
|
{
|
||||||
var ownedPids = knownOwnedPids ?? GetFoxBrowserWebViewPids();
|
var ownedPids = knownOwnedPids ?? GetFoxBrowserWebViewPids();
|
||||||
if (!ownedPids.Contains(session.GetProcessID)) return;
|
if (!ownedPids.Contains(session.GetProcessID)) return;
|
||||||
session.DisplayName = "FoxBrowser";
|
session.DisplayName = _displayName;
|
||||||
if (File.Exists(_iconPath)) session.IconPath = _iconPath;
|
if (File.Exists(_iconPath)) session.IconPath = _iconPath;
|
||||||
}
|
}
|
||||||
catch { /* A session may close between PID lookup and property update. */ }
|
catch { /* A session may close between PID lookup and property update. */ }
|
||||||
|
|||||||
+91
-7
@@ -3,6 +3,7 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Controls.Primitives;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
@@ -21,19 +22,101 @@ public partial class MainWindow : Window
|
|||||||
private readonly DispatcherTimer _watchdogTimer = new() { Interval = TimeSpan.FromSeconds(30) };
|
private readonly DispatcherTimer _watchdogTimer = new() { Interval = TimeSpan.FromSeconds(30) };
|
||||||
private AudioSessionLabeler? _audioLabeler;
|
private AudioSessionLabeler? _audioLabeler;
|
||||||
private bool _updatingDarkModeMenu;
|
private bool _updatingDarkModeMenu;
|
||||||
|
private AppSettings _appSettings;
|
||||||
|
|
||||||
|
private const int WmNcRButtonDown = 0x00A4;
|
||||||
|
private const int WmNcRButtonUp = 0x00A5;
|
||||||
|
private const int HtSysMenu = 3;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
_appSettings = AppSettingsStore.Load();
|
||||||
|
ApplyAppIdentity(_appSettings);
|
||||||
|
SourceInitialized += MainWindow_SourceInitialized;
|
||||||
|
Loaded += MainWindow_Loaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MainWindow_SourceInitialized(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
ApplyDarkTitleBar(true);
|
||||||
|
var source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
|
||||||
|
source?.AddHook(MainWindowWndProc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntPtr MainWindowWndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
||||||
|
{
|
||||||
|
if ((msg == WmNcRButtonDown || msg == WmNcRButtonUp) && wParam.ToInt32() == HtSysMenu)
|
||||||
|
{
|
||||||
|
handled = true;
|
||||||
|
if (msg == WmNcRButtonUp)
|
||||||
|
Dispatcher.BeginInvoke(OpenAppIdentityMenu);
|
||||||
|
}
|
||||||
|
return IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenAppIdentityMenu()
|
||||||
|
{
|
||||||
|
var popup = new Popup
|
||||||
|
{
|
||||||
|
Placement = PlacementMode.MousePoint,
|
||||||
|
StaysOpen = false,
|
||||||
|
AllowsTransparency = true,
|
||||||
|
PopupAnimation = PopupAnimation.Fade
|
||||||
|
};
|
||||||
|
var item = new System.Windows.Controls.Button
|
||||||
|
{
|
||||||
|
Content = "Змінити назву й іконку…",
|
||||||
|
Style = (Style)FindResource("FoxMenuButton")
|
||||||
|
};
|
||||||
|
item.Click += (_, _) =>
|
||||||
|
{
|
||||||
|
popup.IsOpen = false;
|
||||||
|
OpenAppSettings();
|
||||||
|
};
|
||||||
|
popup.Child = new Border
|
||||||
|
{
|
||||||
|
Background = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(23, 27, 34)),
|
||||||
|
BorderBrush = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Color.FromRgb(51, 64, 78)),
|
||||||
|
BorderThickness = new Thickness(1),
|
||||||
|
CornerRadius = new CornerRadius(8),
|
||||||
|
Padding = new Thickness(8),
|
||||||
|
Child = item
|
||||||
|
};
|
||||||
|
popup.IsOpen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenAppSettings()
|
||||||
|
{
|
||||||
|
var window = new AppSettingsWindow(_appSettings, ApplyAppIdentity) { Owner = this };
|
||||||
|
window.ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyAppIdentity(AppSettings settings)
|
||||||
|
{
|
||||||
|
_appSettings = settings;
|
||||||
|
var iconPath = ResolveAppIconPath(settings);
|
||||||
|
Title = string.IsNullOrWhiteSpace(settings.AppDisplayName) ? "FoxBrowser" : settings.AppDisplayName;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var icoPath = Path.Combine(AppContext.BaseDirectory, "FoxBrowser.ico");
|
var image = new System.Windows.Media.Imaging.BitmapImage();
|
||||||
if (File.Exists(icoPath))
|
image.BeginInit();
|
||||||
Icon = new System.Windows.Media.Imaging.BitmapImage(new Uri(icoPath, UriKind.Absolute));
|
image.UriSource = new Uri(iconPath, UriKind.Absolute);
|
||||||
|
image.CacheOption = System.Windows.Media.Imaging.BitmapCacheOption.OnLoad;
|
||||||
|
image.EndInit();
|
||||||
|
image.Freeze();
|
||||||
|
Icon = image;
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
SourceInitialized += (_, _) => ApplyDarkTitleBar(true);
|
_tray?.UpdateIdentity(Title, iconPath);
|
||||||
Loaded += MainWindow_Loaded;
|
_audioLabeler?.UpdateIdentity(Title, iconPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ResolveAppIconPath(AppSettings settings)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(settings.AppIconPath) && File.Exists(settings.AppIconPath))
|
||||||
|
return settings.AppIconPath;
|
||||||
|
return Path.Combine(AppContext.BaseDirectory, "FoxBrowser.ico");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
|
private async void MainWindow_Loaded(object sender, RoutedEventArgs e)
|
||||||
@@ -41,6 +124,7 @@ public partial class MainWindow : Window
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
_tray = new TrayIconManager(this, ExitApplication);
|
_tray = new TrayIconManager(this, ExitApplication);
|
||||||
|
_tray.UpdateIdentity(Title, ResolveAppIconPath(_appSettings));
|
||||||
var environmentFactory = new WebView2EnvironmentFactory();
|
var environmentFactory = new WebView2EnvironmentFactory();
|
||||||
var recoveryMode = false;
|
var recoveryMode = false;
|
||||||
CoreWebView2Environment environment;
|
CoreWebView2Environment environment;
|
||||||
@@ -65,10 +149,10 @@ public partial class MainWindow : Window
|
|||||||
_tabManager.ActiveTabStateChanged += (_, _) => Dispatcher.Invoke(RefreshAddressBar);
|
_tabManager.ActiveTabStateChanged += (_, _) => Dispatcher.Invoke(RefreshAddressBar);
|
||||||
DataContext = _tabManager;
|
DataContext = _tabManager;
|
||||||
await _tabManager.InitializeAsync();
|
await _tabManager.InitializeAsync();
|
||||||
var iconPath = Path.Combine(AppContext.BaseDirectory, "FoxBrowser.ico");
|
var iconPath = ResolveAppIconPath(_appSettings);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_audioLabeler = new AudioSessionLabeler((uint)Process.GetCurrentProcess().Id, iconPath);
|
_audioLabeler = new AudioSessionLabeler((uint)Process.GetCurrentProcess().Id, iconPath, Title);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<Window x:Class="FoxBrowser.UI.AppSettingsWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
Title="Назва та іконка FoxBrowser" Width="540" Height="270"
|
||||||
|
MinWidth="480" Background="#15171A" Foreground="#F2F4F7"
|
||||||
|
WindowStartupLocation="CenterOwner" ResizeMode="NoResize">
|
||||||
|
<Grid Margin="20">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<TextBlock Text="Назва та іконка застосунку" FontSize="18" FontWeight="SemiBold" Margin="0,0,0,18" />
|
||||||
|
<Grid Grid.Row="1" Margin="0,0,0,12">
|
||||||
|
<Grid.ColumnDefinitions><ColumnDefinition Width="140" /><ColumnDefinition Width="*" /></Grid.ColumnDefinitions>
|
||||||
|
<TextBlock Text="Назва:" VerticalAlignment="Center" />
|
||||||
|
<TextBox x:Name="NameBox" Grid.Column="1" />
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="2" Margin="0,0,0,8">
|
||||||
|
<Grid.ColumnDefinitions><ColumnDefinition Width="140" /><ColumnDefinition Width="*" /><ColumnDefinition Width="Auto" /></Grid.ColumnDefinitions>
|
||||||
|
<TextBlock Text="Іконка:" VerticalAlignment="Center" />
|
||||||
|
<TextBlock x:Name="IconPathText" Grid.Column="1" VerticalAlignment="Center" Foreground="#AEB4BE" TextTrimming="CharacterEllipsis" />
|
||||||
|
<Button Grid.Column="2" Content="Обрати іконку…" Click="ChooseIcon_Click" Padding="10,5" Margin="10,0,0,0" />
|
||||||
|
</Grid>
|
||||||
|
<TextBlock Grid.Row="3" Text="PNG і JPG автоматично конвертуються у custom_icon.ico поруч із FoxBrowser.exe." Foreground="#AEB4BE" TextWrapping="Wrap" Margin="0,4,0,0" />
|
||||||
|
<StackPanel Grid.Row="4" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,18,0,0">
|
||||||
|
<Button Content="Скинути до стандартного" Click="Reset_Click" Padding="10,6" Margin="0,0,8,0" />
|
||||||
|
<Button Content="Скасувати" Click="Cancel_Click" Padding="10,6" Margin="0,0,8,0" />
|
||||||
|
<Button Content="Зберегти" Click="Save_Click" Padding="14,6" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows;
|
||||||
|
using FoxBrowser.Core;
|
||||||
|
|
||||||
|
namespace FoxBrowser.UI;
|
||||||
|
|
||||||
|
public partial class AppSettingsWindow : Window
|
||||||
|
{
|
||||||
|
private readonly Action<AppSettings> _apply;
|
||||||
|
private string? _iconPath;
|
||||||
|
|
||||||
|
public AppSettingsWindow(AppSettings current, Action<AppSettings> apply)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
_apply = apply;
|
||||||
|
NameBox.Text = current.AppDisplayName;
|
||||||
|
_iconPath = current.AppIconPath;
|
||||||
|
UpdateIconPathText();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ChooseIcon_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var dialog = new Microsoft.Win32.OpenFileDialog
|
||||||
|
{
|
||||||
|
Title = "Оберіть іконку застосунку",
|
||||||
|
Filter = "Зображення та іконки (*.ico;*.png;*.jpg;*.jpeg)|*.ico;*.png;*.jpg;*.jpeg|Усі файли (*.*)|*.*",
|
||||||
|
CheckFileExists = true
|
||||||
|
};
|
||||||
|
if (dialog.ShowDialog(this) != true) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_iconPath = AppIconConverter.CopyAsPortableIcon(dialog.FileName);
|
||||||
|
UpdateIconPathText();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show(this, $"Не вдалося підготувати іконку: {ex.Message}", "Іконка", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Save_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var name = NameBox.Text.Trim();
|
||||||
|
if (name.Length == 0) name = "FoxBrowser";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = new AppSettings { AppDisplayName = name, AppIconPath = _iconPath };
|
||||||
|
AppSettingsStore.Save(settings);
|
||||||
|
_apply(settings);
|
||||||
|
DialogResult = true;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
System.Windows.MessageBox.Show(this, $"Не вдалося зберегти налаштування: {ex.Message}", "Налаштування", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Reset_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
NameBox.Text = "FoxBrowser";
|
||||||
|
_iconPath = null;
|
||||||
|
try { File.Delete(Path.Combine(AppContext.BaseDirectory, "custom_icon.ico")); } catch { }
|
||||||
|
UpdateIconPathText();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel_Click(object sender, RoutedEventArgs e) => Close();
|
||||||
|
|
||||||
|
private void UpdateIconPathText() => IconPathText.Text = string.IsNullOrWhiteSpace(_iconPath) ? "Вбудована іконка" : Path.GetFileName(_iconPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class AppIconConverter
|
||||||
|
{
|
||||||
|
private const string PortableIconName = "custom_icon.ico";
|
||||||
|
|
||||||
|
public static string CopyAsPortableIcon(string sourcePath)
|
||||||
|
{
|
||||||
|
var destination = Path.Combine(AppContext.BaseDirectory, PortableIconName);
|
||||||
|
var extension = Path.GetExtension(sourcePath);
|
||||||
|
if (extension.Equals(".ico", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
if (string.Equals(Path.GetFullPath(sourcePath), Path.GetFullPath(destination), StringComparison.OrdinalIgnoreCase))
|
||||||
|
return destination;
|
||||||
|
File.Copy(sourcePath, destination, overwrite: true);
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var bitmap = new Bitmap(sourcePath);
|
||||||
|
var handle = bitmap.GetHicon();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using var icon = Icon.FromHandle(handle);
|
||||||
|
using var stream = File.Create(destination);
|
||||||
|
icon.Save(stream);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DestroyIcon(handle);
|
||||||
|
}
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
private static extern bool DestroyIcon(nint handle);
|
||||||
|
}
|
||||||
+21
-10
@@ -9,28 +9,22 @@ public sealed class TrayIconManager : IDisposable
|
|||||||
private readonly Forms.NotifyIcon _icon;
|
private readonly Forms.NotifyIcon _icon;
|
||||||
private readonly Window _window;
|
private readonly Window _window;
|
||||||
private readonly Action _exit;
|
private readonly Action _exit;
|
||||||
|
private Icon? _ownedIcon;
|
||||||
|
|
||||||
public TrayIconManager(Window window, Action exit)
|
public TrayIconManager(Window window, Action exit)
|
||||||
{
|
{
|
||||||
_window = window;
|
_window = window;
|
||||||
_exit = exit;
|
_exit = exit;
|
||||||
|
|
||||||
Icon? icon = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var icoPath = System.IO.Path.Combine(AppContext.BaseDirectory, "FoxBrowser.ico");
|
|
||||||
if (System.IO.File.Exists(icoPath)) icon = new Icon(icoPath);
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
|
|
||||||
_icon = new Forms.NotifyIcon
|
_icon = new Forms.NotifyIcon
|
||||||
{
|
{
|
||||||
Icon = icon ?? SystemIcons.Application,
|
Icon = SystemIcons.Application,
|
||||||
Text = "FoxBrowser",
|
Text = window.Title,
|
||||||
Visible = true,
|
Visible = true,
|
||||||
ContextMenuStrip = BuildMenu()
|
ContextMenuStrip = BuildMenu()
|
||||||
};
|
};
|
||||||
_icon.MouseClick += OnMouseClick;
|
_icon.MouseClick += OnMouseClick;
|
||||||
|
UpdateIdentity(window.Title, System.IO.Path.Combine(AppContext.BaseDirectory, "FoxBrowser.ico"));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void MinimizeToTray()
|
public void MinimizeToTray()
|
||||||
@@ -58,6 +52,23 @@ public sealed class TrayIconManager : IDisposable
|
|||||||
_icon.MouseClick -= OnMouseClick;
|
_icon.MouseClick -= OnMouseClick;
|
||||||
_icon.Visible = false;
|
_icon.Visible = false;
|
||||||
_icon.Dispose();
|
_icon.Dispose();
|
||||||
|
_ownedIcon?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateIdentity(string displayName, string iconPath)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Icon? next = null;
|
||||||
|
if (System.IO.File.Exists(iconPath)) next = new Icon(iconPath);
|
||||||
|
var old = _ownedIcon;
|
||||||
|
_ownedIcon = next;
|
||||||
|
_icon.Icon = next ?? SystemIcons.Application;
|
||||||
|
old?.Dispose();
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
_icon.Text = string.IsNullOrWhiteSpace(displayName) ? "FoxBrowser" : displayName[..Math.Min(63, displayName.Length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMouseClick(object? sender, Forms.MouseEventArgs e)
|
private void OnMouseClick(object? sender, Forms.MouseEventArgs e)
|
||||||
|
|||||||
Reference in new issue
Block a user