diff --git a/MelonVPNClient/MainWindow.cs b/MelonVPNClient/MainWindow.cs index ebe8f8e..744face 100644 --- a/MelonVPNClient/MainWindow.cs +++ b/MelonVPNClient/MainWindow.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Threading; using Gtk; using MelonVPNCore; +using Notify; public partial class MainWindow : Window { @@ -16,7 +17,8 @@ public partial class MainWindow : Window private TextView clientsListText; private Thread startupCheckThread; private ThreadWrapper wrapper; - private StatusIcon statusIcon; + private StatusIcon trayIcon; + private bool ConnectedToVPN; public static readonly string MelonIconImg = "MiniMelonVPNIcon.png"; public static readonly string MelonOnlineImg = "MiniMelonVPNOnline.png"; @@ -31,7 +33,9 @@ public partial class MainWindow : Window SetPosition(WindowPosition.CenterAlways); Resizable = false; - TypeHint = Gdk.WindowTypeHint.Normal; + TypeHint = Gdk.WindowTypeHint.Dialog; + + ShowAll(); Present(); statusLabel = new Label @@ -105,170 +109,231 @@ public partial class MainWindow : Window }; startupCheckThread.Start(); - statusIcon = new StatusIcon + trayIcon = new StatusIcon { - Visible = true + Visible = true, + TooltipText = "Melon VPN" }; + trayIcon.Activate += OnActivateTrayIcon; + trayIcon.PopupMenu += OnTrayIconPopup; } - void UpdateIcon(string file) + private void OnActivateTrayIcon(object sender, EventArgs args) { - DirectoryInfo ExeLocation = Directory.GetParent(Assembly.GetEntryAssembly().Location); - string IconPath = System.IO.Path.Combine(ExeLocation.FullName, file); - Console.WriteLine("Trying to update icon to: " + IconPath); - if (File.Exists(IconPath)) - { - Icon = new Gdk.Pixbuf(IconPath); - if (statusIcon != null) statusIcon.Icon = new Gdk.Pixbuf(IconPath); - } + Visible = !Visible; } - string GenerateTable(string[][] a) + private void OnTrayIconPopup(object o, PopupMenuArgs args) { - if (a.Length == 0) return ""; - int maxlength = a[0][0].Length; - foreach (string b in a[0]) - { - if (b.Length > maxlength) maxlength = b.Length; - } - string[] c = new string[a.Length]; - for (int i = 0; i < a.Length; i++) c[i] = a[i][0].PadRight(maxlength, ' ') + a[i][1]; - return string.Join("\n", c); + Menu popupMenu = new Menu(); + + ImageMenuItem menuItemToggle = new ImageMenuItem(ConnectedToVPN ? "Disconnect" : "Connect"); + Image toggleimg = new Image(ConnectedToVPN ? Stock.MediaPause : Stock.MediaPlay); + menuItemToggle.Image = toggleimg; + popupMenu.Add(menuItemToggle); + menuItemToggle.Activated += OnToggleMenuItem; + + ImageMenuItem menuItemQuit = new ImageMenuItem("Quit"); + Image appimg = new Image(Stock.Quit, IconSize.Menu); + menuItemQuit.Image = appimg; + popupMenu.Add(menuItemQuit); + menuItemQuit.Activated += delegate { QuitApp(); }; + + popupMenu.ShowAll(); + popupMenu.Popup(); } - string GetVpnInternalIp() + void OnToggleMenuItem(object sender, EventArgs args) + { + if (ConnectedToVPN) OnStopClicked(this, new EventArgs()); + else OnStartClicked(this, new EventArgs()); + } + + void UpdateIcon(string file) + { + DirectoryInfo ExeLocation = Directory.GetParent(Assembly.GetEntryAssembly().Location); + string IconPath = System.IO.Path.Combine(ExeLocation.FullName, file); + Console.WriteLine("Trying to update icon to: " + IconPath); + if (File.Exists(IconPath)) + { + Icon = new Gdk.Pixbuf(IconPath); + if (trayIcon != null) trayIcon.Icon = new Gdk.Pixbuf(IconPath); + } + } + + string GenerateTable(string[][] a) + { + if (a.Length == 0) return ""; + int maxlength = a[0][0].Length; + foreach (string b in a[0]) + { + if (b.Length > maxlength) maxlength = b.Length; + } + string[] c = new string[a.Length]; + for (int i = 0; i < a.Length; i++) c[i] = a[i][0].PadRight(maxlength, ' ') + a[i][1]; + return string.Join("\n", c); + } + + string GetVpnInternalIp() + { + if (NetworkInterface.GetIsNetworkAvailable()) + { + foreach (NetworkInterface f in NetworkInterface.GetAllNetworkInterfaces()) + { + IPInterfaceProperties p = f.GetIPProperties(); + IPAddressInformationCollection addressesColl = p.AnycastAddresses; + foreach (IPAddressInformation ip in addressesColl) + { + if (ip.Address.ToString().StartsWith("10.137.248.", StringComparison.CurrentCulture)) + { + return ip.Address.ToString(); + } + } + } + } + return ""; + } + + void StartupCheckMethod() + { + ClientResponseState s = Client.SendDataMessage(DataMessage.Status); + Console.WriteLine(s); + Application.Invoke(delegate + { + UpdateStatus(s); + }); + } + + void Refresh() + { + ClientResponseState s = Client.SendDataMessage(DataMessage.Status); + switch (s) + { + case ClientResponseState.Error: + case ClientResponseState.ServerError: + UpdateStatus(s); + MessageDialog md = new MessageDialog(this, + DialogFlags.DestroyWithParent, MessageType.Error, + ButtonsType.Ok, "Error stopping VPN. Is the daemon running?"); + md.Run(); + md.Destroy(); + break; + case ClientResponseState.Online: + case ClientResponseState.Offline: + UpdateStatus(s); + break; + } + } + + void UpdateStatus(ClientResponseState s) { - if (NetworkInterface.GetIsNetworkAvailable()) - { - foreach (NetworkInterface f in NetworkInterface.GetAllNetworkInterfaces()) - { - IPInterfaceProperties p = f.GetIPProperties(); - IPAddressInformationCollection addressesColl = p.AnycastAddresses; - foreach (IPAddressInformation ip in addressesColl) - { - if (ip.Address.ToString().StartsWith("10.137.248.", StringComparison.CurrentCulture)) - { - return ip.Address.ToString(); - } - } + bool oldState = ConnectedToVPN; + switch (s) + { + case ClientResponseState.Error: + statusLabel.Text = "Client Error"; + ConnectedToVPN = false; + break; + case ClientResponseState.ServerError: + statusLabel.Text = "Server Error"; + ConnectedToVPN = false; + break; + case ClientResponseState.Blank: + statusLabel.Text = "No reply"; + ConnectedToVPN = false; + break; + case ClientResponseState.Online: + statusLabel.Text = "Online - " + GetVpnInternalIp(); + ConnectedToVPN = true; + break; + case ClientResponseState.Offline: + statusLabel.Text = "Offline"; + ConnectedToVPN = false; + break; + } + if (ConnectedToVPN) UpdateIcon(MelonOnlineImg); + else UpdateIcon(MelonIconImg); + NotifyStateUpdate(oldState,ConnectedToVPN); + } + + void NotifyStateUpdate(bool old, bool current) + { + if(old!=current) + { + if(current==true) + { + Notification pop = new Notification("Melon VPN", "Connected to the VPN"); + pop.Show(); + } + else + { + Notification pop = new Notification("Melon VPN", "Disconnected from the VPN"); + pop.Show(); } - } - return ""; - } - - void StartupCheckMethod() + } + } + + protected void OnDeleteEvent(object sender, DeleteEventArgs a) { - ClientResponseState s = Client.SendDataMessage(DataMessage.Status); - Console.WriteLine(s); - Application.Invoke(delegate - { - UpdateStatus(s); - }); - } - - void Refresh() - { - ClientResponseState s = Client.SendDataMessage(DataMessage.Status); - switch (s) - { - case ClientResponseState.Error: - case ClientResponseState.ServerError: - UpdateStatus(s); - MessageDialog md = new MessageDialog(this, - DialogFlags.DestroyWithParent, MessageType.Error, - ButtonsType.Ok, "Error stopping VPN. Is the daemon running?"); - md.Run(); - md.Destroy(); - break; - case ClientResponseState.Online: - case ClientResponseState.Offline: - UpdateStatus(s); - break; - } - } - - void UpdateStatus(ClientResponseState s) - { - switch (s) - { - case ClientResponseState.Error: - statusLabel.Text = "Client Error"; - UpdateIcon(MelonIconImg); - break; - case ClientResponseState.ServerError: - statusLabel.Text = "Server Error"; - UpdateIcon(MelonIconImg); - break; - case ClientResponseState.Blank: - statusLabel.Text = "No reply"; - UpdateIcon(MelonIconImg); - break; - case ClientResponseState.Online: - statusLabel.Text = "Online - " + GetVpnInternalIp(); - UpdateIcon(MelonOnlineImg); - break; - case ClientResponseState.Offline: - statusLabel.Text = "Offline"; - UpdateIcon(MelonIconImg); - break; - } - } - - protected void OnDeleteEvent(object sender, DeleteEventArgs a) - { - if (wrapper != null) - { - wrapper.Kill(); - wrapper.Join(); - } - if (statusIcon != null) statusIcon.Dispose(); - Application.Quit(); - a.RetVal = true; - } - - void OnStartClicked(object sender, EventArgs e) - { - ClientResponseState s = Client.SendDataMessage(DataMessage.Start); - switch (s) - { - case ClientResponseState.Error: - case ClientResponseState.ServerError: - case ClientResponseState.Offline: - UpdateStatus(s); - MessageDialog md = new MessageDialog(this, - DialogFlags.DestroyWithParent, MessageType.Error, - ButtonsType.Ok, "Error starting VPN. Is the daemon running?"); - md.Run(); - md.Destroy(); - break; - } - } - - void OnStopClicked(object sender, EventArgs e) - { - ClientResponseState s = Client.SendDataMessage(DataMessage.Stop); - switch (s) - { - case ClientResponseState.Error: - case ClientResponseState.ServerError: - case ClientResponseState.Online: - UpdateStatus(s); - MessageDialog md = new MessageDialog(this, - DialogFlags.DestroyWithParent, MessageType.Error, - ButtonsType.Ok, "Error stopping VPN. Is the daemon running?"); - md.Run(); - md.Destroy(); - break; - } - } - - void OnRefreshClicked(object sender, EventArgs e) - { - Refresh(); - } - - void OnViewClientsClicked(object sender, EventArgs e) - { - Refresh(); + if (ConnectedToVPN) Visible = false; + else QuitApp(); + a.RetVal = true; + } + + protected void QuitApp() + { + if (wrapper != null) + { + wrapper.Kill(); + wrapper.Join(); + } + if (trayIcon != null) trayIcon.Dispose(); + Application.Quit(); + } + + void OnStartClicked(object sender, EventArgs e) + { + ClientResponseState s = Client.SendDataMessage(DataMessage.Start); + switch (s) + { + case ClientResponseState.Error: + case ClientResponseState.ServerError: + case ClientResponseState.Offline: + UpdateStatus(s); + MessageDialog md = new MessageDialog(this, + DialogFlags.DestroyWithParent, MessageType.Error, + ButtonsType.Ok, "Error starting VPN. Is the daemon running?"); + md.Run(); + md.Destroy(); + break; + } + } + + void OnStopClicked(object sender, EventArgs e) + { + ClientResponseState s = Client.SendDataMessage(DataMessage.Stop); + switch (s) + { + case ClientResponseState.Error: + case ClientResponseState.ServerError: + case ClientResponseState.Online: + UpdateStatus(s); + MessageDialog md = new MessageDialog(this, + DialogFlags.DestroyWithParent, MessageType.Error, + ButtonsType.Ok, "Error stopping VPN. Is the daemon running?"); + md.Run(); + md.Destroy(); + break; + } + } + + void OnRefreshClicked(object sender, EventArgs e) + { + Refresh(); + } + + void OnViewClientsClicked(object sender, EventArgs e) + { + Refresh(); } } diff --git a/MelonVPNClient/MelonVPNClient.csproj b/MelonVPNClient/MelonVPNClient.csproj index 738c40d..57600f4 100644 --- a/MelonVPNClient/MelonVPNClient.csproj +++ b/MelonVPNClient/MelonVPNClient.csproj @@ -60,6 +60,9 @@ ..\..\..\net-libs\Newtonsoft.Json.dll + + ..\..\..\net-libs\libnotify.net.dll + diff --git a/MelonVPNClient/Program.cs b/MelonVPNClient/Program.cs index d7679ba..cae1fd6 100644 --- a/MelonVPNClient/Program.cs +++ b/MelonVPNClient/Program.cs @@ -6,7 +6,7 @@ namespace MelonVPNClient { public static void Main(string[] args) { - Application.Init(); + Application.Init("Melon VPN", ref args); MainWindow win = new MainWindow(); win.Show(); Application.Run(); diff --git a/install-components b/install-components index a413329..b6ac914 100755 --- a/install-components +++ b/install-components @@ -36,6 +36,7 @@ fi sudo chown root:root /etc/melon-vpn/client.cfg # copy more files +sudo cp MelonVPNClient/bin/Release/libnotify.net.dll /usr/lib/melon-vpn/ sudo cp MelonVPNClient/bin/Release/MelonVPNClient.exe /usr/lib/melon-vpn/ sudo cp MelonVPNClient/bin/Release/MelonVPNClient.exe.config /usr/lib/melon-vpn/ sudo cp MelonVPNClient/bin/Release/MiniMelonVPNIcon.png /usr/lib/melon-vpn/