@@ -116,7 +116,7 @@ namespace Shadowsocks.Properties { | |||||
///logfile ss_privoxy.log | ///logfile ss_privoxy.log | ||||
///show-on-task-bar 0 | ///show-on-task-bar 0 | ||||
///activity-animation 0 | ///activity-animation 0 | ||||
///forward-socks5 / 127.0.0.1:__SOCKS_PORT__ . | |||||
///forward-socks5 / __SOCKS_HOST__:__SOCKS_PORT__ . | |||||
///max-client-connections 2048 | ///max-client-connections 2048 | ||||
///hide-console | ///hide-console | ||||
///. | ///. | ||||
@@ -150,9 +150,9 @@ namespace Shadowsocks.Properties { | |||||
/// <summary> | /// <summary> | ||||
/// Looks up a localized resource of type System.Drawing.Bitmap. | /// Looks up a localized resource of type System.Drawing.Bitmap. | ||||
/// </summary> | /// </summary> | ||||
internal static System.Drawing.Bitmap ss16 { | |||||
internal static System.Drawing.Bitmap ss32Fill { | |||||
get { | get { | ||||
object obj = ResourceManager.GetObject("ss16", resourceCulture); | |||||
object obj = ResourceManager.GetObject("ss32Fill", resourceCulture); | |||||
return ((System.Drawing.Bitmap)(obj)); | return ((System.Drawing.Bitmap)(obj)); | ||||
} | } | ||||
} | } | ||||
@@ -160,9 +160,9 @@ namespace Shadowsocks.Properties { | |||||
/// <summary> | /// <summary> | ||||
/// Looks up a localized resource of type System.Drawing.Bitmap. | /// Looks up a localized resource of type System.Drawing.Bitmap. | ||||
/// </summary> | /// </summary> | ||||
internal static System.Drawing.Bitmap ss20 { | |||||
internal static System.Drawing.Bitmap ss32In { | |||||
get { | get { | ||||
object obj = ResourceManager.GetObject("ss20", resourceCulture); | |||||
object obj = ResourceManager.GetObject("ss32In", resourceCulture); | |||||
return ((System.Drawing.Bitmap)(obj)); | return ((System.Drawing.Bitmap)(obj)); | ||||
} | } | ||||
} | } | ||||
@@ -170,9 +170,9 @@ namespace Shadowsocks.Properties { | |||||
/// <summary> | /// <summary> | ||||
/// Looks up a localized resource of type System.Drawing.Bitmap. | /// Looks up a localized resource of type System.Drawing.Bitmap. | ||||
/// </summary> | /// </summary> | ||||
internal static System.Drawing.Bitmap ss24 { | |||||
internal static System.Drawing.Bitmap ss32Out { | |||||
get { | get { | ||||
object obj = ResourceManager.GetObject("ss24", resourceCulture); | |||||
object obj = ResourceManager.GetObject("ss32Out", resourceCulture); | |||||
return ((System.Drawing.Bitmap)(obj)); | return ((System.Drawing.Bitmap)(obj)); | ||||
} | } | ||||
} | } | ||||
@@ -180,19 +180,9 @@ namespace Shadowsocks.Properties { | |||||
/// <summary> | /// <summary> | ||||
/// Looks up a localized resource of type System.Drawing.Bitmap. | /// Looks up a localized resource of type System.Drawing.Bitmap. | ||||
/// </summary> | /// </summary> | ||||
internal static System.Drawing.Bitmap ssIn24 { | |||||
internal static System.Drawing.Bitmap ss32Outline { | |||||
get { | get { | ||||
object obj = ResourceManager.GetObject("ssIn24", resourceCulture); | |||||
return ((System.Drawing.Bitmap)(obj)); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Looks up a localized resource of type System.Drawing.Bitmap. | |||||
/// </summary> | |||||
internal static System.Drawing.Bitmap ssOut24 { | |||||
get { | |||||
object obj = ResourceManager.GetObject("ssOut24", resourceCulture); | |||||
object obj = ResourceManager.GetObject("ss32Outline", resourceCulture); | |||||
return ((System.Drawing.Bitmap)(obj)); | return ((System.Drawing.Bitmap)(obj)); | ||||
} | } | ||||
} | } | ||||
@@ -136,20 +136,17 @@ | |||||
<data name="proxy_pac_txt" type="System.Resources.ResXFileRef, System.Windows.Forms"> | <data name="proxy_pac_txt" type="System.Resources.ResXFileRef, System.Windows.Forms"> | ||||
<value>..\Data\proxy.pac.txt.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | <value>..\Data\proxy.pac.txt.gz;System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> | ||||
</data> | </data> | ||||
<data name="ss16" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||||
<value>..\Resources\ss16.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||||
<data name="ss32Fill" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||||
<value>..\Resources\ss32Fill.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||||
</data> | </data> | ||||
<data name="ss20" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||||
<value>..\Resources\ss20.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||||
<data name="ss32In" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||||
<value>..\Resources\ss32In.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||||
</data> | </data> | ||||
<data name="ss24" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||||
<value>..\Resources\ss24.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||||
<data name="ss32Out" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||||
<value>..\Resources\ss32Out.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||||
</data> | </data> | ||||
<data name="ssIn24" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||||
<value>..\Resources\ssIn24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||||
</data> | |||||
<data name="ssOut24" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||||
<value>..\Resources\ssOut24.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||||
<data name="ss32Outline" type="System.Resources.ResXFileRef, System.Windows.Forms"> | |||||
<value>..\Resources\ss32Outline.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | |||||
</data> | </data> | ||||
<data name="ssw128" type="System.Resources.ResXFileRef, System.Windows.Forms"> | <data name="ssw128" type="System.Resources.ResXFileRef, System.Windows.Forms"> | ||||
<value>..\Resources\ssw128.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | <value>..\Resources\ssw128.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value> | ||||
@@ -60,18 +60,16 @@ namespace Shadowsocks.Util | |||||
// Support on Windows 10 1903+ | // Support on Windows 10 1903+ | ||||
public static WindowsThemeMode GetWindows10SystemThemeSetting() | public static WindowsThemeMode GetWindows10SystemThemeSetting() | ||||
{ | { | ||||
WindowsThemeMode registData = WindowsThemeMode.Dark; | |||||
WindowsThemeMode themeMode = WindowsThemeMode.Dark; | |||||
try | try | ||||
{ | { | ||||
RegistryKey reg_HKCU = Registry.CurrentUser; | |||||
RegistryKey reg_ThemesPersonalize = reg_HKCU.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", false); | |||||
RegistryKey reg_ThemesPersonalize = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize", false); | |||||
if (reg_ThemesPersonalize.GetValue("SystemUsesLightTheme") != null) | if (reg_ThemesPersonalize.GetValue("SystemUsesLightTheme") != null) | ||||
{ | { | ||||
if (Convert.ToInt32(reg_ThemesPersonalize.GetValue("SystemUsesLightTheme").ToString()) == 0) // 0:dark mode, 1:light mode | |||||
registData = WindowsThemeMode.Dark; | |||||
if ((int)(reg_ThemesPersonalize.GetValue("SystemUsesLightTheme")) == 0) // 0:dark mode, 1:light mode | |||||
themeMode = WindowsThemeMode.Dark; | |||||
else | else | ||||
registData = WindowsThemeMode.Light; | |||||
//Console.WriteLine(registData); | |||||
themeMode = WindowsThemeMode.Light; | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
@@ -83,7 +81,7 @@ namespace Shadowsocks.Util | |||||
Logging.Info( | Logging.Info( | ||||
$"Cannot get Windows 10 system theme mode, return default value 0 (dark mode)."); | $"Cannot get Windows 10 system theme mode, return default value 0 (dark mode)."); | ||||
} | } | ||||
return registData; | |||||
return themeMode; | |||||
} | } | ||||
// return a full path with filename combined which pointed to the temporary directory | // return a full path with filename combined which pointed to the temporary directory | ||||
@@ -1,35 +1,99 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Reflection; | |||||
using System.Windows.Forms; | |||||
namespace Shadowsocks.Util | |||||
{ | |||||
public static class ViewUtils | |||||
{ | |||||
public static IEnumerable<TControl> GetChildControls<TControl>(this Control control) where TControl : Control | |||||
{ | |||||
if (control.Controls.Count == 0) | |||||
{ | |||||
return Enumerable.Empty<TControl>(); | |||||
} | |||||
var children = control.Controls.OfType<TControl>().ToList(); | |||||
return children.SelectMany(GetChildControls<TControl>).Concat(children); | |||||
} | |||||
// Workaround NotifyIcon's 63 chars limit | |||||
// https://stackoverflow.com/questions/579665/how-can-i-show-a-systray-tooltip-longer-than-63-chars | |||||
public static void SetNotifyIconText(NotifyIcon ni, string text) | |||||
{ | |||||
if (text.Length >= 128) | |||||
throw new ArgumentOutOfRangeException("Text limited to 127 characters"); | |||||
Type t = typeof(NotifyIcon); | |||||
BindingFlags hidden = BindingFlags.NonPublic | BindingFlags.Instance; | |||||
t.GetField("text", hidden).SetValue(ni, text); | |||||
if ((bool)t.GetField("added", hidden).GetValue(ni)) | |||||
t.GetMethod("UpdateIcon", hidden).Invoke(ni, new object[] { true }); | |||||
} | |||||
} | |||||
} | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Drawing; | |||||
using System.Drawing.Drawing2D; | |||||
using System.Drawing.Imaging; | |||||
using System.Linq; | |||||
using System.Reflection; | |||||
using System.Windows.Forms; | |||||
namespace Shadowsocks.Util | |||||
{ | |||||
public static class ViewUtils | |||||
{ | |||||
public static IEnumerable<TControl> GetChildControls<TControl>(this Control control) where TControl : Control | |||||
{ | |||||
if (control.Controls.Count == 0) | |||||
{ | |||||
return Enumerable.Empty<TControl>(); | |||||
} | |||||
var children = control.Controls.OfType<TControl>().ToList(); | |||||
return children.SelectMany(GetChildControls<TControl>).Concat(children); | |||||
} | |||||
// Workaround NotifyIcon's 63 chars limit | |||||
// https://stackoverflow.com/questions/579665/how-can-i-show-a-systray-tooltip-longer-than-63-chars | |||||
public static void SetNotifyIconText(NotifyIcon ni, string text) | |||||
{ | |||||
if (text.Length >= 128) | |||||
throw new ArgumentOutOfRangeException("Text limited to 127 characters"); | |||||
Type t = typeof(NotifyIcon); | |||||
BindingFlags hidden = BindingFlags.NonPublic | BindingFlags.Instance; | |||||
t.GetField("text", hidden).SetValue(ni, text); | |||||
if ((bool)t.GetField("added", hidden).GetValue(ni)) | |||||
t.GetMethod("UpdateIcon", hidden).Invoke(ni, new object[] { true }); | |||||
} | |||||
public static Bitmap AddBitmapOverlay(Bitmap original, params Bitmap[] overlays) | |||||
{ | |||||
Bitmap bitmap = new Bitmap(original.Width, original.Height, PixelFormat.Format64bppArgb); | |||||
Graphics canvas = Graphics.FromImage(bitmap); | |||||
canvas.DrawImage(original, new Point(0, 0)); | |||||
foreach (Bitmap overlay in overlays) | |||||
{ | |||||
canvas.DrawImage(new Bitmap(overlay, original.Size), new Point(0, 0)); | |||||
} | |||||
canvas.Save(); | |||||
return bitmap; | |||||
} | |||||
public static Bitmap ChangeBitmapColor(Bitmap original, Color colorMask) | |||||
{ | |||||
Bitmap newBitmap = new Bitmap(original); | |||||
for (int x = 0; x < newBitmap.Width; x++) | |||||
{ | |||||
for (int y = 0; y < newBitmap.Height; y++) | |||||
{ | |||||
Color color = original.GetPixel(x, y); | |||||
if (color.A != 0) | |||||
{ | |||||
int red = color.R * colorMask.R / 255; | |||||
int green = color.G * colorMask.G / 255; | |||||
int blue = color.B * colorMask.B / 255; | |||||
int alpha = color.A * colorMask.A / 255; | |||||
newBitmap.SetPixel(x, y, Color.FromArgb(alpha, red, green, blue)); | |||||
} | |||||
else | |||||
{ | |||||
newBitmap.SetPixel(x, y, color); | |||||
} | |||||
} | |||||
} | |||||
return newBitmap; | |||||
} | |||||
public static Bitmap ResizeBitmap (Bitmap original, int width, int height) | |||||
{ | |||||
Bitmap newBitmap = new Bitmap(width, height); | |||||
using (Graphics g = Graphics.FromImage(newBitmap)) | |||||
{ | |||||
g.SmoothingMode = SmoothingMode.HighQuality; | |||||
g.InterpolationMode = InterpolationMode.HighQualityBicubic; | |||||
g.PixelOffsetMode = PixelOffsetMode.HighQuality; | |||||
g.CompositingQuality = CompositingQuality.HighQuality; | |||||
g.DrawImage(original, new Rectangle(0, 0, width, height)); | |||||
} | |||||
return newBitmap; | |||||
} | |||||
public static int GetScreenDpi() | |||||
{ | |||||
Graphics graphics = Graphics.FromHwnd(IntPtr.Zero); | |||||
int dpi = (int)graphics.DpiX; | |||||
graphics.Dispose(); | |||||
return dpi; | |||||
} | |||||
} | |||||
} |
@@ -28,12 +28,13 @@ namespace Shadowsocks.View | |||||
private UpdateChecker updateChecker; | private UpdateChecker updateChecker; | ||||
private NotifyIcon _notifyIcon; | private NotifyIcon _notifyIcon; | ||||
private Bitmap icon_baseBitmap; | |||||
private Icon icon_base, icon_in, icon_out, icon_both, targetIcon; | |||||
private ContextMenu contextMenu1; | |||||
private Icon icon, icon_in, icon_out, icon_both, previousIcon; | |||||
private bool _isFirstRun; | private bool _isFirstRun; | ||||
private bool _isStartupChecking; | private bool _isStartupChecking; | ||||
private string _urlToOpen; | |||||
private ContextMenu contextMenu1; | |||||
private MenuItem disableItem; | private MenuItem disableItem; | ||||
private MenuItem AutoStartupItem; | private MenuItem AutoStartupItem; | ||||
private MenuItem ShareOverLANItem; | private MenuItem ShareOverLANItem; | ||||
@@ -54,12 +55,19 @@ namespace Shadowsocks.View | |||||
private MenuItem proxyItem; | private MenuItem proxyItem; | ||||
private MenuItem hotKeyItem; | private MenuItem hotKeyItem; | ||||
private MenuItem VerboseLoggingToggleItem; | private MenuItem VerboseLoggingToggleItem; | ||||
private ConfigForm configForm; | private ConfigForm configForm; | ||||
private ProxyForm proxyForm; | private ProxyForm proxyForm; | ||||
private LogForm logForm; | private LogForm logForm; | ||||
private HotkeySettingsForm hotkeySettingsForm; | private HotkeySettingsForm hotkeySettingsForm; | ||||
private string _urlToOpen; | |||||
private Utils.WindowsThemeMode currentWindowsThemeMode; | |||||
// color definition for icon color transformation | |||||
private readonly Color colorMaskBlue = Color.FromArgb(255, 25, 125, 191); | |||||
private readonly Color colorMaskDarkSilver = Color.FromArgb(128, 192, 192, 192); | |||||
private readonly Color colorMaskLightSilver = Color.FromArgb(192, 192, 192, 192); | |||||
private readonly Color colorMaskEclipse = Color.FromArgb(192, 64, 64, 64); | |||||
public MenuViewController(ShadowsocksController controller) | public MenuViewController(ShadowsocksController controller) | ||||
{ | { | ||||
@@ -79,7 +87,7 @@ namespace Shadowsocks.View | |||||
controller.UpdatePACFromGFWListError += controller_UpdatePACFromGFWListError; | controller.UpdatePACFromGFWListError += controller_UpdatePACFromGFWListError; | ||||
_notifyIcon = new NotifyIcon(); | _notifyIcon = new NotifyIcon(); | ||||
UpdateTrayIcon(); | |||||
UpdateTrayIconAndNotifyText(); | |||||
_notifyIcon.Visible = true; | _notifyIcon.Visible = true; | ||||
_notifyIcon.ContextMenu = contextMenu1; | _notifyIcon.ContextMenu = contextMenu1; | ||||
_notifyIcon.BalloonTipClicked += notifyIcon1_BalloonTipClicked; | _notifyIcon.BalloonTipClicked += notifyIcon1_BalloonTipClicked; | ||||
@@ -109,7 +117,7 @@ namespace Shadowsocks.View | |||||
private void controller_TrafficChanged(object sender, EventArgs e) | private void controller_TrafficChanged(object sender, EventArgs e) | ||||
{ | { | ||||
if (icon_baseBitmap == null) | |||||
if (icon == null) | |||||
return; | return; | ||||
Icon newIcon; | Icon newIcon; | ||||
@@ -124,11 +132,11 @@ namespace Shadowsocks.View | |||||
else if (hasOutbound) | else if (hasOutbound) | ||||
newIcon = icon_out; | newIcon = icon_out; | ||||
else | else | ||||
newIcon = icon_base; | |||||
newIcon = icon; | |||||
if (newIcon != this.targetIcon) | |||||
if (newIcon != this.previousIcon) | |||||
{ | { | ||||
this.targetIcon = newIcon; | |||||
this.previousIcon = newIcon; | |||||
_notifyIcon.Icon = newIcon; | _notifyIcon.Icon = newIcon; | ||||
} | } | ||||
} | } | ||||
@@ -140,46 +148,19 @@ namespace Shadowsocks.View | |||||
#region Tray Icon | #region Tray Icon | ||||
private void UpdateTrayIcon() | |||||
private void UpdateTrayIconAndNotifyText() | |||||
{ | { | ||||
int dpi; | |||||
Graphics graphics = Graphics.FromHwnd(IntPtr.Zero); | |||||
dpi = (int)graphics.DpiX; | |||||
graphics.Dispose(); | |||||
icon_baseBitmap = null; | |||||
if (dpi < 97) | |||||
{ | |||||
// dpi = 96; | |||||
icon_baseBitmap = Resources.ss16; | |||||
} | |||||
else if (dpi < 121) | |||||
{ | |||||
// dpi = 120; | |||||
icon_baseBitmap = Resources.ss20; | |||||
} | |||||
else | |||||
{ | |||||
icon_baseBitmap = Resources.ss24; | |||||
} | |||||
Configuration config = controller.GetConfigurationCopy(); | Configuration config = controller.GetConfigurationCopy(); | ||||
bool enabled = config.enabled; | bool enabled = config.enabled; | ||||
bool global = config.global; | bool global = config.global; | ||||
// set Windows 10 Theme color (1903+) | |||||
currentWindowsThemeMode = Utils.GetWindows10SystemThemeSetting(); | |||||
Color colorMask = SelectColorMask(enabled, global); | |||||
Size iconSize = SelectIconSize(); | |||||
if (currentWindowsThemeMode == Utils.WindowsThemeMode.Light) | |||||
if (!global || !enabled) | |||||
icon_baseBitmap = getDarkTrayIcon(icon_baseBitmap); | |||||
UpdateIconSet(colorMask, iconSize, out icon, out icon_in, out icon_out, out icon_both); | |||||
icon_baseBitmap = getTrayIconByState(icon_baseBitmap, enabled, global); | |||||
icon_base = Icon.FromHandle(icon_baseBitmap.GetHicon()); | |||||
targetIcon = icon_base; | |||||
icon_in = Icon.FromHandle(AddBitmapOverlay(icon_baseBitmap, Resources.ssIn24).GetHicon()); | |||||
icon_out = Icon.FromHandle(AddBitmapOverlay(icon_baseBitmap, Resources.ssOut24).GetHicon()); | |||||
icon_both = Icon.FromHandle(AddBitmapOverlay(icon_baseBitmap, Resources.ssIn24, Resources.ssOut24).GetHicon()); | |||||
_notifyIcon.Icon = targetIcon; | |||||
previousIcon = icon; | |||||
_notifyIcon.Icon = previousIcon; | |||||
string serverInfo = null; | string serverInfo = null; | ||||
if (controller.GetCurrentStrategy() != null) | if (controller.GetCurrentStrategy() != null) | ||||
@@ -203,89 +184,90 @@ namespace Shadowsocks.View | |||||
ViewUtils.SetNotifyIconText(_notifyIcon, text); | ViewUtils.SetNotifyIconText(_notifyIcon, text); | ||||
} | } | ||||
private Bitmap getDarkTrayIcon(Bitmap originIcon) | |||||
/// <summary> | |||||
/// Determine the icon size based on the screen DPI. | |||||
/// </summary> | |||||
/// <returns></returns> | |||||
/// https://stackoverflow.com/a/40851713/2075611 | |||||
private Size SelectIconSize() | |||||
{ | { | ||||
Bitmap iconCopy = new Bitmap(originIcon); | |||||
for (int x = 0; x < iconCopy.Width; x++) | |||||
Size size = new Size(32, 32); | |||||
int dpi = ViewUtils.GetScreenDpi(); | |||||
if (dpi < 97) | |||||
{ | { | ||||
for (int y = 0; y < iconCopy.Height; y++) | |||||
{ | |||||
Color color = originIcon.GetPixel(x, y); | |||||
if (color.A != 0) | |||||
{ | |||||
Color flyBlue = Color.FromArgb(192, 0, 0, 0); | |||||
// Multiply with flyBlue | |||||
int red = color.R * flyBlue.R / 255; | |||||
int green = color.G * flyBlue.G / 255; | |||||
int blue = color.B * flyBlue.B / 255; | |||||
int alpha = color.A; | |||||
iconCopy.SetPixel(x, y, Color.FromArgb(alpha, red, green, blue)); | |||||
} | |||||
else | |||||
{ | |||||
iconCopy.SetPixel(x, y, Color.FromArgb(color.A, color.R, color.G, color.B)); | |||||
} | |||||
} | |||||
// dpi = 96; | |||||
size = new Size(16, 16); | |||||
} | |||||
else if (dpi < 121) | |||||
{ | |||||
// dpi = 120; | |||||
size = new Size(20, 20); | |||||
} | |||||
else if (dpi < 145) | |||||
{ | |||||
// dpi = 144; | |||||
size = new Size(24, 24); | |||||
} | } | ||||
return iconCopy; | |||||
else | |||||
{ | |||||
// dpi = 168; | |||||
size = new Size(28, 28); | |||||
} | |||||
return size; | |||||
} | } | ||||
private Bitmap getTrayIconByState(Bitmap originIcon, bool enabled, bool global) | |||||
private Color SelectColorMask(bool isProxyEnabled, bool isGlobalProxy) | |||||
{ | { | ||||
Bitmap iconCopy = new Bitmap(originIcon); | |||||
for (int x = 0; x < iconCopy.Width; x++) | |||||
Color colorMask = Color.White; | |||||
Utils.WindowsThemeMode currentWindowsThemeMode = Utils.GetWindows10SystemThemeSetting(); | |||||
if (isProxyEnabled) | |||||
{ | { | ||||
for (int y = 0; y < iconCopy.Height; y++) | |||||
if (isGlobalProxy) // global | |||||
{ | { | ||||
Color color = originIcon.GetPixel(x, y); | |||||
if (color.A != 0) | |||||
{ | |||||
if (!enabled) | |||||
{ | |||||
// Multiply with flyBlue | |||||
Color flyBlue; | |||||
if (currentWindowsThemeMode == Utils.WindowsThemeMode.Light) | |||||
flyBlue = Color.FromArgb(128, 192, 192, 192); // Dark icon more transparent | |||||
else | |||||
flyBlue = Color.FromArgb(192, 192, 192, 192); // Light icon less transparent | |||||
int red = color.R * flyBlue.R / 255; | |||||
int green = color.G * flyBlue.G / 255; | |||||
int blue = color.B * flyBlue.B / 255; | |||||
int alpha = color.A * flyBlue.A / 255; | |||||
iconCopy.SetPixel(x, y, Color.FromArgb(alpha, red, green, blue)); | |||||
} | |||||
else if (global) | |||||
{ | |||||
Color flyBlue = Color.FromArgb(25, 125, 191); | |||||
// Multiply with flyBlue | |||||
int red = color.R * flyBlue.R / 255; | |||||
int green = color.G * flyBlue.G / 255; | |||||
int blue = color.B * flyBlue.B / 255; | |||||
iconCopy.SetPixel(x, y, Color.FromArgb(color.A, red, green, blue)); | |||||
} | |||||
} | |||||
else | |||||
colorMask = colorMaskBlue; | |||||
} | |||||
else // PAC | |||||
{ | |||||
if (currentWindowsThemeMode == Utils.WindowsThemeMode.Light) | |||||
{ | { | ||||
iconCopy.SetPixel(x, y, Color.FromArgb(color.A, color.R, color.G, color.B)); | |||||
colorMask = colorMaskEclipse; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
return iconCopy; | |||||
else // disabled | |||||
{ | |||||
if (currentWindowsThemeMode == Utils.WindowsThemeMode.Light) | |||||
{ | |||||
colorMask = colorMaskDarkSilver; | |||||
} | |||||
else | |||||
{ | |||||
colorMask = colorMaskLightSilver; | |||||
} | |||||
} | |||||
return colorMask; | |||||
} | } | ||||
private Bitmap AddBitmapOverlay(Bitmap original, params Bitmap[] overlays) | |||||
private void UpdateIconSet(Color colorMask, Size size, | |||||
out Icon icon, out Icon icon_in, out Icon icon_out, out Icon icon_both) | |||||
{ | { | ||||
Bitmap bitmap = new Bitmap(original.Width, original.Height, PixelFormat.Format64bppArgb); | |||||
Graphics canvas = Graphics.FromImage(bitmap); | |||||
canvas.DrawImage(original, new Point(0, 0)); | |||||
foreach (Bitmap overlay in overlays) | |||||
{ | |||||
canvas.DrawImage(new Bitmap(overlay, original.Size), new Point(0, 0)); | |||||
} | |||||
canvas.Save(); | |||||
return bitmap; | |||||
Bitmap iconBitmap; | |||||
// generate the base icon | |||||
iconBitmap = ViewUtils.ChangeBitmapColor(Resources.ss32Fill, colorMask); | |||||
iconBitmap = ViewUtils.AddBitmapOverlay(iconBitmap, Resources.ss32Outline); | |||||
icon = Icon.FromHandle(ViewUtils.ResizeBitmap(iconBitmap, size.Width, size.Height).GetHicon()); | |||||
icon_in = Icon.FromHandle(ViewUtils.ResizeBitmap(ViewUtils.AddBitmapOverlay(iconBitmap, Resources.ss32In), size.Width, size.Height).GetHicon()); | |||||
icon_out = Icon.FromHandle(ViewUtils.ResizeBitmap(ViewUtils.AddBitmapOverlay(iconBitmap, Resources.ss32In), size.Width, size.Height).GetHicon()); | |||||
icon_both = Icon.FromHandle(ViewUtils.ResizeBitmap(ViewUtils.AddBitmapOverlay(iconBitmap, Resources.ss32In, Resources.ss32Out), size.Width, size.Height).GetHicon()); | |||||
} | } | ||||
#endregion | #endregion | ||||
#region MenuItems and MenuGroups | #region MenuItems and MenuGroups | ||||
@@ -355,7 +337,7 @@ namespace Shadowsocks.View | |||||
private void controller_ConfigChanged(object sender, EventArgs e) | private void controller_ConfigChanged(object sender, EventArgs e) | ||||
{ | { | ||||
LoadCurrentConfiguration(); | LoadCurrentConfiguration(); | ||||
UpdateTrayIcon(); | |||||
UpdateTrayIconAndNotifyText(); | |||||
} | } | ||||
private void controller_EnableStatusChanged(object sender, EventArgs e) | private void controller_EnableStatusChanged(object sender, EventArgs e) | ||||
@@ -629,7 +611,7 @@ namespace Shadowsocks.View | |||||
private void notifyIcon1_Click(object sender, MouseEventArgs e) | private void notifyIcon1_Click(object sender, MouseEventArgs e) | ||||
{ | { | ||||
UpdateTrayIcon(); | |||||
UpdateTrayIconAndNotifyText(); | |||||
if (e.Button == MouseButtons.Middle) | if (e.Button == MouseButtons.Middle) | ||||
{ | { | ||||
ShowLogForm(); | ShowLogForm(); | ||||
@@ -124,6 +124,11 @@ | |||||
<Compile Include="Model\HotKeyConfig.cs" /> | <Compile Include="Model\HotKeyConfig.cs" /> | ||||
<Compile Include="Model\ProxyConfig.cs" /> | <Compile Include="Model\ProxyConfig.cs" /> | ||||
<Compile Include="Model\SysproxyConfig.cs" /> | <Compile Include="Model\SysproxyConfig.cs" /> | ||||
<Compile Include="Properties\Resources.Designer.cs"> | |||||
<AutoGen>True</AutoGen> | |||||
<DesignTime>True</DesignTime> | |||||
<DependentUpon>Resources.resx</DependentUpon> | |||||
</Compile> | |||||
<Compile Include="Properties\Settings.Designer.cs"> | <Compile Include="Properties\Settings.Designer.cs"> | ||||
<AutoGen>True</AutoGen> | <AutoGen>True</AutoGen> | ||||
<DesignTimeSharedInput>True</DesignTimeSharedInput> | <DesignTimeSharedInput>True</DesignTimeSharedInput> | ||||
@@ -150,11 +155,6 @@ | |||||
<Compile Include="Model\Configuration.cs" /> | <Compile Include="Model\Configuration.cs" /> | ||||
<Compile Include="Model\StatisticsRecord.cs" /> | <Compile Include="Model\StatisticsRecord.cs" /> | ||||
<Compile Include="Model\StatisticsStrategyConfiguration.cs" /> | <Compile Include="Model\StatisticsStrategyConfiguration.cs" /> | ||||
<Compile Include="Properties\Resources.Designer.cs"> | |||||
<AutoGen>True</AutoGen> | |||||
<DesignTime>True</DesignTime> | |||||
<DependentUpon>Resources.resx</DependentUpon> | |||||
</Compile> | |||||
<Compile Include="Controller\Strategy\BalancingStrategy.cs" /> | <Compile Include="Controller\Strategy\BalancingStrategy.cs" /> | ||||
<Compile Include="Controller\Strategy\StrategyManager.cs" /> | <Compile Include="Controller\Strategy\StrategyManager.cs" /> | ||||
<Compile Include="Controller\Strategy\IStrategy.cs" /> | <Compile Include="Controller\Strategy\IStrategy.cs" /> | ||||
@@ -269,9 +269,6 @@ | |||||
<Generator>SettingsSingleFileGenerator</Generator> | <Generator>SettingsSingleFileGenerator</Generator> | ||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput> | <LastGenOutput>Settings.Designer.cs</LastGenOutput> | ||||
</None> | </None> | ||||
<None Include="Resources\ss20.png" /> | |||||
<None Include="Resources\ss16.png" /> | |||||
<None Include="Resources\ss24.png" /> | |||||
<None Include="Resources\ssw128.png" /> | <None Include="Resources\ssw128.png" /> | ||||
<Content Include="Data\zh_CN.txt" /> | <Content Include="Data\zh_CN.txt" /> | ||||
<Content Include="Data\zh_TW.txt" /> | <Content Include="Data\zh_TW.txt" /> | ||||
@@ -281,8 +278,10 @@ | |||||
<None Include="FodyWeavers.xml"> | <None Include="FodyWeavers.xml"> | ||||
<SubType>Designer</SubType> | <SubType>Designer</SubType> | ||||
</None> | </None> | ||||
<Content Include="Resources\ssIn24.png" /> | |||||
<Content Include="Resources\ssOut24.png" /> | |||||
<Content Include="Resources\ss32Fill.png" /> | |||||
<Content Include="Resources\ss32In.png" /> | |||||
<Content Include="Resources\ss32Out.png" /> | |||||
<Content Include="Resources\ss32Outline.png" /> | |||||
<Content Include="shadowsocks.ico" /> | <Content Include="shadowsocks.ico" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||