From af15a385474cce467e6054fd0f86e7a2cff1a0a4 Mon Sep 17 00:00:00 2001 From: Zhivko Laflurov Date: Wed, 13 Jan 2016 16:31:18 +0200 Subject: [PATCH] New notification module with images included --- Classes/Notifications/ProgramStatus.cs | 101 +++ Classes/Notifications/Status.cs | 41 ++ Classes/Notifications/StatusType.cs | 17 + Classes/Notifications/TaskbarNotifier.cs | 737 ++++++++++++++++++++ Classes/UpdateNotifier.cs | 44 +- Forms/AboutBox.Designer.cs | 2 +- Forms/MainForm.cs | 185 +++-- Notification Images/Basic.xcf | Bin 0 -> 50374 bytes Notification Images/close.bmp | Bin 0 -> 1616 bytes Notification Images/notification-green.png | Bin 0 -> 3702 bytes Notification Images/notification-red.png | Bin 0 -> 3671 bytes Notification Images/notification-yellow.png | Bin 0 -> 3538 bytes Properties/AssemblyInfo.cs | 4 +- Properties/Resources.Designer.cs | 67 ++ Properties/Resources.resx | 21 + TeamViewerPopupBlocker.csproj | 17 +- 16 files changed, 1136 insertions(+), 100 deletions(-) create mode 100644 Classes/Notifications/ProgramStatus.cs create mode 100644 Classes/Notifications/Status.cs create mode 100644 Classes/Notifications/StatusType.cs create mode 100644 Classes/Notifications/TaskbarNotifier.cs create mode 100644 Notification Images/Basic.xcf create mode 100644 Notification Images/close.bmp create mode 100644 Notification Images/notification-green.png create mode 100644 Notification Images/notification-red.png create mode 100644 Notification Images/notification-yellow.png diff --git a/Classes/Notifications/ProgramStatus.cs b/Classes/Notifications/ProgramStatus.cs new file mode 100644 index 0000000..1016768 --- /dev/null +++ b/Classes/Notifications/ProgramStatus.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using TeamViewerPopupBlocker.Forms; +using TeamViewerPopupBlocker.Properties; + +namespace TeamViewerPopupBlocker.Classes.Notifications +{ + public sealed class ProgramStatus + { + private static ProgramStatus instance = null; + + private static readonly object syncRoot = new Object(); + + public static ProgramStatus Instance + { + get + { + lock (syncRoot) + { + return instance ?? (instance = new ProgramStatus()); + } + } + } + + private List statusList = new List(); + + private DateTime tTimeStatusReady = DateTime.Now; + + public void AddStatus(Status srcStatus) + { + statusList.Add(srcStatus); + } + + public void GetStatus(MainForm mainForm) + { + if (statusList.Count <= 0) return; + + bool tContnue = DateTime.Now > tTimeStatusReady; + + if (!tContnue) return; + + Status status = statusList[0].Clone(); + + if (status == null) + { + return; + } + + if (status.TimeOutMinimum > 0) + { + this.tTimeStatusReady = DateTime.Now.AddMilliseconds(status.TimeOutMinimum); + } + + switch (status.StatusType) + { + case StatusType.StartBlocking: + { + mainForm.ShowNotificationMessage(status.StatusType, + Resources.ProgramStatus_GetStatus_Blocking_started, status.TimeOut); + break; + } + + case StatusType.StopBlocking: + { + mainForm.ShowNotificationMessage(status.StatusType, + Resources.ProgramStatus_GetStatus_Blocking_stopped, status.TimeOut); + break; + } + + case StatusType.ErrorException: + { + mainForm.ShowNotificationMessage(status.StatusType, + Resources.ProgramStatus_GetStatus_Exception_was_thrown_, status.TimeOut); + break; + } + + case StatusType.InfoUpToDate: + { + mainForm.ShowNotificationMessage( + status.StatusType, + Resources.Your_version_is_up_to_date, + status.TimeOut); + break; + } + + case StatusType.InfoUpdate: + { + mainForm.ShowNotificationMessage( + status.StatusType, + status.AdditionalInformation, + status.TimeOut); + + break; + } + + } + + this.statusList.RemoveAt(0); + } + } +} diff --git a/Classes/Notifications/Status.cs b/Classes/Notifications/Status.cs new file mode 100644 index 0000000..3521c52 --- /dev/null +++ b/Classes/Notifications/Status.cs @@ -0,0 +1,41 @@ +using System; + +namespace TeamViewerPopupBlocker.Classes.Notifications +{ + public class Status : ICloneable + { + public Status() + { + this.StatusType = StatusType.Unknown; + this.TimeOut = 0; + this.TimeOutMinimum = 0; + this.AdditionalInformation = ""; + } + + public Status(StatusType status, int timeOut, int timeOutMinimum = 0, string additionalInformation = "") + { + this.StatusType = status; + this.TimeOut = timeOut; + this.TimeOutMinimum = timeOutMinimum; + this.AdditionalInformation = additionalInformation; + } + + public StatusType StatusType { get; set; } + + public int TimeOut { get; set; } + + public int TimeOutMinimum { get; set; } + + public string AdditionalInformation { get; set; } + + object ICloneable.Clone() + { + return this.Clone(); + } + + public Status Clone() + { + return (Status)this.MemberwiseClone(); + } + } +} \ No newline at end of file diff --git a/Classes/Notifications/StatusType.cs b/Classes/Notifications/StatusType.cs new file mode 100644 index 0000000..daf9aba --- /dev/null +++ b/Classes/Notifications/StatusType.cs @@ -0,0 +1,17 @@ +namespace TeamViewerPopupBlocker.Classes.Notifications +{ + public enum StatusType + { + Unknown = 0, + + StartBlocking, + + StopBlocking, + + ErrorException, + + InfoUpdate, + + InfoUpToDate + } +} diff --git a/Classes/Notifications/TaskbarNotifier.cs b/Classes/Notifications/TaskbarNotifier.cs new file mode 100644 index 0000000..e409d3f --- /dev/null +++ b/Classes/Notifications/TaskbarNotifier.cs @@ -0,0 +1,737 @@ +using System.Diagnostics; + +namespace TeamViewerPopupBlocker.Classes.Notifications +{ + using System; + using System.Drawing; + using System.Drawing.Drawing2D; + using System.Windows.Forms; + using System.Runtime.InteropServices; + + /// + /// TaskbarNotifier allows to display MSN style/Skinned instant messaging pop ups + /// + public class TaskbarNotifier : Form + { + #region TaskbarNotifier Protected Members + + protected Bitmap BackgroundBitmap = null; + + protected Bitmap CloseBitmap = null; + + protected Point CloseBitmapLocation; + + protected Size CloseBitmapSize; + + protected Rectangle RealTitleRectangle; + + protected Rectangle RealContentRectangle; + + protected Rectangle WorkAreaRectangle; + + protected Timer timer = new Timer(); + + protected TaskbarStates taskbarState = TaskbarStates.hidden; + + protected string titleText; + + protected string contentText; + + protected Color normalTitleColor = Color.FromArgb(255, 0, 0); + + protected Color hoverTitleColor = Color.FromArgb(255, 0, 0); + + protected Color normalContentColor = Color.FromArgb(0, 0, 0); + + protected Color hoverContentColor = Color.FromArgb(0, 0, 0x66); + + private static string familyName = "Arial"; + + private static int fontSizeNormal = 13; + + private static int fontSizeHover = 14; + + protected Font normalTitleFont = new Font(familyName, fontSizeNormal, FontStyle.Regular, GraphicsUnit.Pixel); + + protected Font hoverTitleFont = new Font(familyName, fontSizeHover, FontStyle.Bold, GraphicsUnit.Pixel); + + protected Font normalContentFont = new Font(familyName, fontSizeNormal, FontStyle.Regular, GraphicsUnit.Pixel); + + protected Font hoverContentFont = new Font(familyName, fontSizeHover, FontStyle.Regular, GraphicsUnit.Pixel); + + protected int nShowEvents; + + protected int nHideEvents; + + protected int nVisibleEvents; + + protected int nIncrementShow; + + protected int nIncrementHide; + + protected bool bIsMouseOverPopup = false; + + protected bool bIsMouseOverClose = false; + + protected bool bIsMouseOverContent = false; + + protected bool bIsMouseOverTitle = false; + + protected bool bIsMouseDown = false; + + protected bool bKeepVisibleOnMouseOver = true; // Added Rev 002 + + protected bool bReShowOnMouseOver = false; // Added Rev 002 + + #endregion + + #region TaskbarNotifier Public Members + + public Rectangle TitleRectangle; + + public Rectangle ContentRectangle; + + public bool TitleClickable = false; + + public bool ContentClickable = true; + + public bool CloseClickable = true; + + public bool EnableSelectionRectangle = true; + + public event EventHandler CloseClick = null; + + public event EventHandler TitleClick = null; + + public event EventHandler ContentClick = null; + + #endregion + + #region TaskbarNotifier Enums + + /// + /// List of the different popup animation status + /// + public enum TaskbarStates + { + hidden = 0, + + appearing = 1, + + visible = 2, + + disappearing = 3 + } + + #endregion + + #region TaskbarNotifier Constructor + + /// + /// The Constructor for TaskbarNotifier + /// + public TaskbarNotifier() + { + // Window Style + FormBorderStyle = FormBorderStyle.None; + WindowState = FormWindowState.Minimized; + base.Show(); + base.Hide(); + WindowState = FormWindowState.Normal; + ShowInTaskbar = false; + TopMost = true; + MaximizeBox = false; + MinimizeBox = false; + ControlBox = false; + + timer.Enabled = true; + timer.Tick += new EventHandler(OnTimer); + } + + #endregion + + #region TaskbarNotifier Properties + + /// + /// Indicates if the popup should remain visible when the mouse pointer is over it. + /// Added Rev 002 + /// + public bool KeepVisibleOnMousOver + { + get + { + return bKeepVisibleOnMouseOver; + } + set + { + bKeepVisibleOnMouseOver = value; + } + } + + /// + /// Indicates if the popup should appear again when mouse moves over it while it's disappearing. + /// Added Rev 002 + /// + public bool ReShowOnMouseOver + { + get + { + return bReShowOnMouseOver; + } + set + { + bReShowOnMouseOver = value; + } + } + + #endregion + + #region TaskbarNotifier Public Methods + + [DllImport("user32.dll")] + private static extern Boolean ShowWindow(IntPtr hWnd, Int32 nCmdShow); + + /// + /// Displays the popup for a certain amount of time + /// + /// The string which will be shown as the title of the popup + /// The string which will be shown as the content of the popup + /// Duration of the showing animation (in milliseconds) + /// Duration of the visible state before collapsing (in milliseconds) + /// Duration of the hiding animation (in milliseconds) + /// Nothing + public void Show(string strTitle, string strContent, int nTimeToShow, int nTimeToStay, int nTimeToHide) + { + WorkAreaRectangle = Screen.GetWorkingArea(WorkAreaRectangle); + titleText = strTitle; + contentText = strContent; + nVisibleEvents = nTimeToStay; + CalculateMouseRectangles(); + + // We calculate the pixel increment and the timer value for the showing animation + int nEvents; + if (nTimeToShow > 10) + { + nEvents = Math.Min((nTimeToShow / 10), BackgroundBitmap.Height); + nShowEvents = nTimeToShow / nEvents; + nIncrementShow = BackgroundBitmap.Height / nEvents; + } + else + { + nShowEvents = 10; + nIncrementShow = BackgroundBitmap.Height; + } + + // We calculate the pixel increment and the timer value for the hiding animation + if (nTimeToHide > 10) + { + nEvents = Math.Min((nTimeToHide / 10), BackgroundBitmap.Height); + nHideEvents = nTimeToHide / nEvents; + nIncrementHide = BackgroundBitmap.Height / nEvents; + } + else + { + nHideEvents = 10; + nIncrementHide = BackgroundBitmap.Height; + } + + switch (taskbarState) + { + case TaskbarStates.hidden: + taskbarState = TaskbarStates.appearing; + SetBounds( + WorkAreaRectangle.Right - BackgroundBitmap.Width - 17, + WorkAreaRectangle.Bottom - 1, + BackgroundBitmap.Width, + 0); + timer.Interval = nShowEvents; + timer.Start(); + // We Show the popup without stealing focus + ShowWindow(this.Handle, 4); + break; + + case TaskbarStates.appearing: + Refresh(); + break; + + case TaskbarStates.visible: + timer.Stop(); + timer.Interval = nVisibleEvents; + timer.Start(); + Refresh(); + break; + + case TaskbarStates.disappearing: + timer.Stop(); + taskbarState = TaskbarStates.visible; + SetBounds( + WorkAreaRectangle.Right - BackgroundBitmap.Width - 17, + WorkAreaRectangle.Bottom - BackgroundBitmap.Height - 1, + BackgroundBitmap.Width, + BackgroundBitmap.Height); + timer.Interval = nVisibleEvents; + timer.Start(); + Refresh(); + break; + } + } + + /// + /// Hides the popup + /// + /// Nothing + public new void Hide() + { + if (taskbarState != TaskbarStates.hidden) + { + timer.Stop(); + taskbarState = TaskbarStates.hidden; + base.Hide(); + } + } + + /// + /// Sets the background bitmap and its transparency color + /// + /// Path of the Background Bitmap on the disk + /// Color of the Bitmap which won't be visible + /// Nothing + public void SetBackgroundBitmap(string strFilename, Color transparencyColor) + { + BackgroundBitmap = new Bitmap(strFilename); + Width = BackgroundBitmap.Width; + Height = BackgroundBitmap.Height; + Region = BitmapToRegion(BackgroundBitmap, transparencyColor); + } + + /// + /// Sets the background bitmap and its transparency color + /// + /// Image/Bitmap object which represents the Background Bitmap + /// Color of the Bitmap which won't be visible + /// Nothing + public void SetBackgroundBitmap(Image image, Color transparencyColor) + { + BackgroundBitmap = new Bitmap(image); + Width = BackgroundBitmap.Width; + Height = BackgroundBitmap.Height; + Region = BitmapToRegion(BackgroundBitmap, transparencyColor); + } + + /// + /// Sets the 3-State Close Button bitmap, its transparency color and its coordinates + /// + /// Path of the 3-state Close button Bitmap on the disk (width must a multiple of 3) + /// Color of the Bitmap which won't be visible + /// Location of the close button on the popup + /// Nothing + public void SetCloseBitmap(string strFilename, Color transparencyColor, Point position) + { + CloseBitmap = new Bitmap(strFilename); + CloseBitmap.MakeTransparent(transparencyColor); + CloseBitmapSize = new Size(CloseBitmap.Width / 3, CloseBitmap.Height); + CloseBitmapLocation = position; + } + + /// + /// Sets the 3-State Close Button bitmap, its transparency color and its coordinates + /// + /// Image/Bitmap object which represents the 3-state Close button Bitmap (width must be a multiple of 3) + /// Color of the Bitmap which won't be visible + /// /// Location of the close button on the popup + /// Nothing + public void SetCloseBitmap(Image image, Color transparencyColor, Point position) + { + CloseBitmap = new Bitmap(image); + CloseBitmap.MakeTransparent(transparencyColor); + CloseBitmapSize = new Size(CloseBitmap.Width / 3, CloseBitmap.Height); + CloseBitmapLocation = position; + } + + #endregion + + #region TaskbarNotifier Protected Methods + + protected void DrawCloseButton(Graphics grfx) + { + if (CloseBitmap != null) + { + Rectangle rectDest = new Rectangle(CloseBitmapLocation, CloseBitmapSize); + Rectangle rectSrc; + + if (bIsMouseOverClose) + { + if (bIsMouseDown) rectSrc = new Rectangle(new Point(CloseBitmapSize.Width * 2, 0), CloseBitmapSize); + else rectSrc = new Rectangle(new Point(CloseBitmapSize.Width, 0), CloseBitmapSize); + } + else rectSrc = new Rectangle(new Point(0, 0), CloseBitmapSize); + + + grfx.DrawImage(CloseBitmap, rectDest, rectSrc, GraphicsUnit.Pixel); + } + } + + protected void DrawText(Graphics grfx) + { + if (titleText != null && titleText.Length != 0) + { + StringFormat sf = new StringFormat(); + sf.Alignment = StringAlignment.Near; + sf.LineAlignment = StringAlignment.Center; + sf.FormatFlags = StringFormatFlags.NoWrap; + sf.Trimming = StringTrimming.EllipsisCharacter; // Added Rev 002 + if (bIsMouseOverTitle) grfx.DrawString(titleText, hoverTitleFont, new SolidBrush(hoverTitleColor), TitleRectangle, sf); + else grfx.DrawString(titleText, normalTitleFont, new SolidBrush(normalTitleColor), TitleRectangle, sf); + } + + if (contentText != null && contentText.Length != 0) + { + StringFormat sf = new StringFormat(); + sf.Alignment = StringAlignment.Center; + sf.LineAlignment = StringAlignment.Center; + sf.FormatFlags = StringFormatFlags.MeasureTrailingSpaces; + sf.Trimming = StringTrimming.Word; // Added Rev 002 + + if (bIsMouseOverContent) + { + grfx.DrawString( + contentText, + hoverContentFont, + new SolidBrush(hoverContentColor), + ContentRectangle, + sf); + if (EnableSelectionRectangle) + ControlPaint.DrawBorder3D( + grfx, + RealContentRectangle, + Border3DStyle.Etched, + Border3DSide.Top | Border3DSide.Bottom | Border3DSide.Left | Border3DSide.Right); + + } + else + grfx.DrawString( + contentText, + normalContentFont, + new SolidBrush(normalContentColor), + ContentRectangle, + sf); + } + } + + protected void CalculateMouseRectangles() + { + Graphics grfx = CreateGraphics(); + StringFormat sf = new StringFormat(); + sf.Alignment = StringAlignment.Center; + sf.LineAlignment = StringAlignment.Center; + sf.FormatFlags = StringFormatFlags.MeasureTrailingSpaces; + SizeF sizefTitle = grfx.MeasureString(titleText, hoverTitleFont, TitleRectangle.Width, sf); + SizeF sizefContent = grfx.MeasureString(contentText, hoverContentFont, ContentRectangle.Width, sf); + grfx.Dispose(); + + // Added Rev 002 + //We should check if the title size really fits inside the pre-defined title rectangle + if (sizefTitle.Height > TitleRectangle.Height) + { + RealTitleRectangle = new Rectangle( + TitleRectangle.Left, + TitleRectangle.Top, + TitleRectangle.Width, + TitleRectangle.Height); + } + else + { + RealTitleRectangle = new Rectangle( + TitleRectangle.Left, + TitleRectangle.Top, + (int)sizefTitle.Width, + (int)sizefTitle.Height); + } + RealTitleRectangle.Inflate(0, 2); + + // Added Rev 002 + //We should check if the Content size really fits inside the pre-defined Content rectangle + if (sizefContent.Height > ContentRectangle.Height) + { + RealContentRectangle = + new Rectangle( + (ContentRectangle.Width - (int)sizefContent.Width) / 2 + ContentRectangle.Left, + ContentRectangle.Top, + (int)sizefContent.Width, + ContentRectangle.Height); + } + else + { + RealContentRectangle = + new Rectangle( + (ContentRectangle.Width - (int)sizefContent.Width) / 2 + ContentRectangle.Left, + (ContentRectangle.Height - (int)sizefContent.Height) / 2 + ContentRectangle.Top, + (int)sizefContent.Width, + (int)sizefContent.Height); + } + RealContentRectangle.Inflate(0, 2); + } + + /// + protected Region BitmapToRegion(Bitmap bitmap, Color transparencyColor) + { + if (bitmap == null) throw new ArgumentNullException("Bitmap", "Bitmap cannot be null!"); + + int height = bitmap.Height; + int width = bitmap.Width; + + GraphicsPath path = new GraphicsPath(); + + for (int j = 0; j < height; j++) + { + for (int i = 0; i < width; i++) + { + if (bitmap.GetPixel(i, j) == transparencyColor) continue; + + int x0 = i; + + while ((i < width) && (bitmap.GetPixel(i, j) != transparencyColor)) i++; + + path.AddRectangle(new Rectangle(x0, j, i - x0, 1)); + } + } + + Region region = new Region(path); + path.Dispose(); + return region; + } + + #endregion + + #region TaskbarNotifier Events Overrides + + protected void OnTimer(Object obj, EventArgs ea) + { + switch (taskbarState) + { + case TaskbarStates.appearing: + { + //OLD: + //if (Height < BackgroundBitmap.Height) + // SetBounds(Left, Top-nIncrementShow ,Width, Height + nIncrementShow); + if (Height < BackgroundBitmap.Height) + { + Top -= nIncrementShow; + Height += nIncrementShow; + //SetBounds(Left, Top - nIncrementShow, Width, Height + nIncrementShow, BoundsSpecified.All); + } + else + { + timer.Stop(); + Height = BackgroundBitmap.Height; + timer.Interval = nVisibleEvents; + taskbarState = TaskbarStates.visible; + timer.Start(); + } + + break; + } + + case TaskbarStates.visible: + { + timer.Stop(); + timer.Interval = nHideEvents; + // Added Rev 002 + if ((bKeepVisibleOnMouseOver && !bIsMouseOverPopup) || (!bKeepVisibleOnMouseOver)) + { + taskbarState = TaskbarStates.disappearing; + } + + //taskbarState = TaskbarStates.disappearing; // Rev 002 + timer.Start(); + break; + } + + case TaskbarStates.disappearing: + { + // Added Rev 002 + if (bReShowOnMouseOver && bIsMouseOverPopup) + { + taskbarState = TaskbarStates.appearing; + } + else + { + //OLD: + //if (Top < WorkAreaRectangle.Bottom) + // SetBounds(Left, Top + nIncrementHide, Width, Height - nIncrementHide); + if (Top < WorkAreaRectangle.Bottom) + { + Top += nIncrementHide; + Height -= nIncrementHide; + + //SetBounds(Left, Top + nIncrementHide, Width, Height - nIncrementHide); + } + else + { + this.Hide(); + } + } + + break; + } + } + } + + protected override void OnDoubleClick(EventArgs e) + { + Process.Start(@"https://zhivkosk.wordpress.com/"); + } + + /// + /// The on mouse enter. + /// + /// + /// The event arguments. + /// + protected override void OnMouseEnter(EventArgs ea) + { + base.OnMouseEnter(ea); + this.bIsMouseOverPopup = true; + this.Refresh(); + } + + protected override void OnMouseLeave(EventArgs ea) + { + base.OnMouseLeave(ea); + bIsMouseOverPopup = false; + bIsMouseOverClose = false; + bIsMouseOverTitle = false; + bIsMouseOverContent = false; + Refresh(); + } + + protected override void OnMouseMove(MouseEventArgs mea) + { + base.OnMouseMove(mea); + + bool bContentModified = false; + + if ((mea.X > CloseBitmapLocation.X) && (mea.X < CloseBitmapLocation.X + CloseBitmapSize.Width) + && (mea.Y > CloseBitmapLocation.Y) && (mea.Y < CloseBitmapLocation.Y + CloseBitmapSize.Height) + && CloseClickable) + { + if (!bIsMouseOverClose) + { + bIsMouseOverClose = true; + bIsMouseOverTitle = false; + bIsMouseOverContent = false; + Cursor = Cursors.Hand; + bContentModified = true; + } + } + else if (RealContentRectangle.Contains(new Point(mea.X, mea.Y)) && ContentClickable) + { + if (!bIsMouseOverContent) + { + bIsMouseOverClose = false; + bIsMouseOverTitle = false; + bIsMouseOverContent = true; + Cursor = Cursors.Hand; + bContentModified = true; + } + } + else if (RealTitleRectangle.Contains(new Point(mea.X, mea.Y)) && TitleClickable) + { + if (!bIsMouseOverTitle) + { + bIsMouseOverClose = false; + bIsMouseOverTitle = true; + bIsMouseOverContent = false; + Cursor = Cursors.Hand; + bContentModified = true; + } + } + else + { + if (bIsMouseOverClose || bIsMouseOverTitle || bIsMouseOverContent) bContentModified = true; + + bIsMouseOverClose = false; + bIsMouseOverTitle = false; + bIsMouseOverContent = false; + Cursor = Cursors.Default; + } + + if (bContentModified) Refresh(); + } + + protected override void OnMouseDown(MouseEventArgs mea) + { + base.OnMouseDown(mea); + bIsMouseDown = true; + + if (bIsMouseOverClose) Refresh(); + } + + protected override void OnMouseUp(MouseEventArgs mea) + { + base.OnMouseUp(mea); + bIsMouseDown = false; + + if (bIsMouseOverClose) + { + Hide(); + + if (CloseClick != null) + { + CloseClick(this, new EventArgs()); + } + } + else if (bIsMouseOverTitle) + { + if (TitleClick != null) + { + TitleClick(this, new EventArgs()); + } + } + else if (bIsMouseOverContent) + { + if (ContentClick != null) + { + ContentClick(this, new EventArgs()); + } + } + } + + protected override void OnPaintBackground(PaintEventArgs pea) + { + Graphics grfx = pea.Graphics; + grfx.PageUnit = GraphicsUnit.Pixel; + + Graphics offScreenGraphics; + Bitmap offscreenBitmap; + + offscreenBitmap = new Bitmap(BackgroundBitmap.Width, BackgroundBitmap.Height); + offScreenGraphics = Graphics.FromImage(offscreenBitmap); + + if (BackgroundBitmap != null) + { + offScreenGraphics.DrawImage(BackgroundBitmap, 0, 0, BackgroundBitmap.Width, BackgroundBitmap.Height); + } + + DrawCloseButton(offScreenGraphics); + DrawText(offScreenGraphics); + + grfx.DrawImage(offscreenBitmap, 0, 0); + } + + #endregion + + private void InitializeComponent() + { + this.SuspendLayout(); + // + // CTaskbarNotifier + // + this.ClientSize = new System.Drawing.Size(284, 262); + this.Name = "TaskbarNotifier"; + this.TopMost = true; + this.ResumeLayout(false); + + } + } +} diff --git a/Classes/UpdateNotifier.cs b/Classes/UpdateNotifier.cs index e96a14c..5442c54 100644 --- a/Classes/UpdateNotifier.cs +++ b/Classes/UpdateNotifier.cs @@ -4,6 +4,9 @@ // // Zhivko Kabaivanov //----------------------------------------------------------------------- + +using TeamViewerPopupBlocker.Classes.Notifications; + namespace TeamViewerPopupBlocker.Classes { using System; @@ -92,11 +95,6 @@ public static UpdateNotifier Instance } } - /// - /// Get or sets is the main load of the application. - /// - private bool IsMainLoad { get; set; } - /// /// Gets the update file path where its stored the last update check. /// @@ -121,9 +119,8 @@ public static UpdateNotifier Instance /// Performs check for version and notifies the user for new version of the application. /// /// Is the main load of the application. - public void NotifyForUpdate(bool isMainLoad) + public void NotifyForUpdate() { - IsMainLoad = isMainLoad; this.DownloadVersionNumberFromGitHub(); } @@ -153,25 +150,13 @@ protected virtual void Dispose(bool disposing) /// private void InformAboutNewVersion() { - DialogResult dialogResult = - MessageBox.Show( - string.Format( + ProgramStatus.Instance.AddStatus( + new Status( + StatusType.InfoUpdate, 5000, 4000, string.Format( CultureInfo.InvariantCulture, Resources.UpdateNotifier_CompareVersionNumbers_Download_New, - Settings.Instance.AssemblyVersion, - this.DownloadedVersionNumber), - Resources.Program_Name, - MessageBoxButtons.YesNo, - MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1, - MessageBoxOptions.DefaultDesktopOnly); - - if (dialogResult != DialogResult.Yes) - { - return; - } - - Process.Start(this.githubReleasesUri.OriginalString); + Settings.Instance.AssemblyVersion, + this.DownloadedVersionNumber))); } /// @@ -226,16 +211,7 @@ private void CompareVersionNumbers() case 0: case 1: { - if (IsMainLoad) break; - - MessageBox.Show( - Resources.Your_version_is_up_to_date, - Resources.Program_Name, - MessageBoxButtons.OK, - MessageBoxIcon.Information, - MessageBoxDefaultButton.Button1, - MessageBoxOptions.DefaultDesktopOnly); - + ProgramStatus.Instance.AddStatus(new Status(StatusType.InfoUpToDate, 5000, 4000)); break; } diff --git a/Forms/AboutBox.Designer.cs b/Forms/AboutBox.Designer.cs index 04b46e1..26aa48c 100644 --- a/Forms/AboutBox.Designer.cs +++ b/Forms/AboutBox.Designer.cs @@ -128,7 +128,7 @@ private void InitializeComponent() this.labelCopyright.Name = "labelCopyright"; this.labelCopyright.Size = new System.Drawing.Size(283, 17); this.labelCopyright.TabIndex = 21; - this.labelCopyright.Text = global::TeamViewerPopupBlocker.Properties.Resources.AboutBox_LblCopyright___Text; ; + this.labelCopyright.Text = global::TeamViewerPopupBlocker.Properties.Resources.AboutBox_LblCopyright___Text; this.labelCopyright.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // textBoxDescription diff --git a/Forms/MainForm.cs b/Forms/MainForm.cs index 4655b61..7ac3b24 100644 --- a/Forms/MainForm.cs +++ b/Forms/MainForm.cs @@ -4,10 +4,13 @@ // // Zhivko Kabaivanov //----------------------------------------------------------------------- + +using System.Drawing; +using TeamViewerPopupBlocker.Classes.Notifications; + namespace TeamViewerPopupBlocker.Forms { using System; - using System.Globalization; using System.Timers; using System.Windows.Forms; using Classes; @@ -20,11 +23,6 @@ namespace TeamViewerPopupBlocker.Forms /// public partial class MainForm : Form { - /// - /// The promotion for showing the donation popup balloon. - /// - private static Timer donationTimer; - /// /// The blocking for closing the TeamViewer windows. /// @@ -34,7 +32,7 @@ public partial class MainForm : Form /// The update for notifying the user for new version. /// private static System.Timers.Timer updateTimer; - + /// /// Allowing the to be closed. /// @@ -53,12 +51,54 @@ public MainForm() this.InitializeComponent(); this.InitControls(); - UpdateNotifier.Instance.NotifyForUpdate(true); + UpdateNotifier.Instance.NotifyForUpdate(); + InitNotify(); Settings.Instance.Load(); this.StartBlocking(); } + /// + /// Shows the notification message to the user. + /// + /// + /// + /// + public void ShowNotificationMessage(StatusType statusType, string srcStatusText, int srcStatusTimeOut) + { + switch (statusType) + { + case StatusType.StartBlocking: + { + this.tbnRed.Hide(); + this.tbnYellow.Hide(); + + this.tbnGreen.Show(string.Empty, srcStatusText, 300, srcStatusTimeOut, 50); + + break; + } + + case StatusType.StopBlocking: + { + this.tbnGreen.Hide(); + this.tbnYellow.Hide(); + + this.tbnRed.Show(string.Empty, srcStatusText, 300, srcStatusTimeOut, 50); + break; + } + + case StatusType.InfoUpdate: + case StatusType.InfoUpToDate: + { + this.tbnGreen.Hide(); + this.tbnRed.Hide(); + this.tbnYellow.Show(string.Empty, srcStatusText, 300, srcStatusTimeOut, 50); + + break; + } + } + } + /// /// Gets or sets the . /// @@ -68,7 +108,7 @@ public MainForm() /// Gets or sets the . /// private static AboutBox AboutBox { get; set; } - + /// /// Occurs before the form is closed. /// @@ -76,7 +116,7 @@ public MainForm() protected override void OnFormClosing(FormClosingEventArgs e) { blockingTimer.Stop(); - + if (!allowClose) { this.Hide(); @@ -102,18 +142,19 @@ protected override void OnFormClosing(FormClosingEventArgs e) /// . protected override void SetVisibleCore(bool value) { - if(!allowVisible) + if (!allowVisible) { value = false; - if (!this.IsHandleCreated) try - { - CreateHandle(); - } - catch (InvalidOperationException invalidOperationException) - { - LogSystem.Instance.AddToLog(invalidOperationException, false); - } + if (!this.IsHandleCreated) + try + { + CreateHandle(); + } + catch (InvalidOperationException invalidOperationException) + { + LogSystem.Instance.AddToLog(invalidOperationException, false); + } } base.SetVisibleCore(value); @@ -130,16 +171,6 @@ private static void InitUpdateTimer() updateTimer.Start(); } - /// - /// Initialization for the blocking . - /// - private static void InitBlockingTimer() - { - blockingTimer = new Timer(); - blockingTimer.Interval = 1000; - blockingTimer.Tick += new EventHandler(BlockingTimerTick); - } - /// /// Notifying the user for a new update if available. /// @@ -147,9 +178,19 @@ private static void InitBlockingTimer() /// The e. private static void UpdateNotifyTimerElapsed(object sender, ElapsedEventArgs e) { - UpdateNotifier.Instance.NotifyForUpdate(false); + UpdateNotifier.Instance.NotifyForUpdate(); + } + + /// + /// Initialization for the blocking . + /// + private static void InitBlockingTimer() + { + blockingTimer = new Timer(); + blockingTimer.Interval = 200; + blockingTimer.Tick += new EventHandler(BlockingTimerTick); } - + /// /// The blocking timer tick event. /// @@ -168,35 +209,10 @@ private void InitControls() AddWindowNameForm = new AddWindowNameForm(); AboutBox = new AboutBox(); - this.InitPromotionTimer(); InitBlockingTimer(); InitUpdateTimer(); - - this.ShowBallonTextToolTip(string.Format(CultureInfo.InvariantCulture, "Make {0} better!", Resources.Program_Name)); - - donationTimer.Start(); } - /// - /// Initialization for the promotion . - /// - private void InitPromotionTimer() - { - donationTimer = new Timer(); - donationTimer.Interval = 60 * 60 * 1000; // 10 min. - donationTimer.Tick += new EventHandler(this.PromotionTimerTick); - } - - /// - /// The blocking timer tick event. - /// - /// The sender. - /// The e. - private void PromotionTimerTick(object sender, EventArgs e) - { - this.ShowBallonTextToolTip(string.Format(CultureInfo.InvariantCulture, "Make {0} better!", Resources.Program_Name)); - } - /// /// Click event for for starting the blocking. /// @@ -231,7 +247,7 @@ private void AddWindowNameMenuItemClick(object sender, EventArgs e) } this.StopBlocking(); - + try { AddWindowNameForm = new AddWindowNameForm(); @@ -241,7 +257,7 @@ private void AddWindowNameMenuItemClick(object sender, EventArgs e) { LogSystem.Instance.AddToLog(argumentNullException, false); } - + this.StartBlocking(); } @@ -252,7 +268,7 @@ private void AddWindowNameMenuItemClick(object sender, EventArgs e) /// The e. private void UpdateCheckMenuItemClick(object sender, EventArgs e) { - UpdateNotifier.Instance.NotifyForUpdate(false); + UpdateNotifier.Instance.NotifyForUpdate(); } /// @@ -295,7 +311,7 @@ private void StartBlocking() } this.niTray.Icon = Resources.app_icon_default; - this.ShowBallonTextToolTip("has started blocking."); + ProgramStatus.Instance.AddStatus(new Status(StatusType.StartBlocking, 5000, 4000)); } catch (ArgumentNullException ex) { @@ -320,11 +336,11 @@ private void StopBlocking() } this.niTray.Icon = Resources.app_icon_turned_off; - this.ShowBallonTextToolTip("has stopped blocking."); + ProgramStatus.Instance.AddStatus(new Status(StatusType.StopBlocking, 5000, 4000)); } catch (NullReferenceException ex) { - this.ShowBallonExceptionToolTip(); + ProgramStatus.Instance.AddStatus(new Status(StatusType.ErrorException, 5000, 4000)); LogSystem.Instance.AddToLog(ex, false); } } @@ -378,5 +394,50 @@ private void TrayNotifyIconMouseDoubleClick(object sender, MouseEventArgs e) this.OpenAboutBox(); } } + + private TaskbarNotifier tbnGreen { get; set; } + + private TaskbarNotifier tbnRed { get; set; } + + private TaskbarNotifier tbnYellow { get; set; } + + private readonly Timer timerProgramStatus = new Timer(); + + private void InitNotify() + { + tbnGreen = new TaskbarNotifier(); + tbnRed = new TaskbarNotifier(); + tbnYellow = new TaskbarNotifier(); + + this.timerProgramStatus.Tick += new EventHandler(this.OnStatusCheck); //StatusProcessing + this.timerProgramStatus.Interval = 100; + this.timerProgramStatus.Start(); + + InitNotify(this.tbnGreen, Resources.notification_green); + InitNotify(this.tbnRed, Resources.notification_red); + InitNotify(this.tbnYellow, Resources.notification_yellow); + } + + private void InitNotify(TaskbarNotifier taskbarNotifier, Image inputImage) + { + taskbarNotifier.SetBackgroundBitmap(inputImage, Color.FromArgb(255, 0, 255)); + taskbarNotifier.SetCloseBitmap( + Resources.close_buttons, + Color.FromArgb(255, 0, 255), + new Point(inputImage.Width - 40, 13)); + + taskbarNotifier.ContentRectangle = new Rectangle(15, 30, inputImage.Width - 40, inputImage.Height - 50); + taskbarNotifier.CloseClickable = true; + taskbarNotifier.TitleClickable = false; + taskbarNotifier.ContentClickable = true; + taskbarNotifier.EnableSelectionRectangle = false; + taskbarNotifier.KeepVisibleOnMousOver = true; + taskbarNotifier.ReShowOnMouseOver = true; + } + + private void OnStatusCheck(object source, EventArgs e) + { + ProgramStatus.Instance.GetStatus(this); + } } } \ No newline at end of file diff --git a/Notification Images/Basic.xcf b/Notification Images/Basic.xcf new file mode 100644 index 0000000000000000000000000000000000000000..762d299a3616653ecf4aa4fad33045c387ca9271 GIT binary patch literal 50374 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 literal 0 HcmV?d00001 diff --git a/Notification Images/close.bmp b/Notification Images/close.bmp new file mode 100644 index 0000000000000000000000000000000000000000..90bcdee60124e073397815dffb899887746e7bff GIT binary patch literal 1616 zcmZ{k>rb0y7{==tzv*ZH1O0B|7Y``Jt&G1oP zk7QmEiWve&#nWrKUR!y!R=ujJTCJ{FsjFGlYQl782pkoUUOV-X(pz|Jp|i`bDmBOp z$C>FzRSghkR6OJs=grBoLaE8~OIJ3}*zQOVg=AUR=*$o}DxUtH?+7X{{WiS%r+f0Z zin1G8%^IB<0!PJT(7Cf^(}%OB+S@(j4wpjNBuTc?gF!ze^T-S;9wApQTS-ouHJNRZ zNQAi5a@2?O9FlUlSo1|of!g0C0DPV_#k5Khzd3qWikLYmZtiYJ<@n3v1L3dOqQ;M{S2|IW_V!on7v83ISe!=5_b4~>l*s*+%*#rfdD zHgAK@41uExxoJ{odb%?u#rgW1Ul>gt!C;U#%nX5}#&SQ-yP2oFr7Zkeoah-IndK4a z%n&%LkZWjIZ)pCh*?708_?xNeud&gYA#hY7HzjpERqEI;w&yDJKHq}Ha)HiFG#pjP zRpomX${z~~Z|BHw4i4Yj-Q69qP0*Pka8x`4Ju8jPcZ|kgbh`CP_k9e6(wQM}R6OjN zlr$RmRtG;4Px@KQ47q*1b8fc>0!NMI78S3vIXgrm|L6_&gngrQW(XWr$TgWa*qpBr zi9ED)yYmY?bY=(~HJV%NN|KDk$936l9=@rj!Vw=g#E-;J1%adD;ro^pc*`m`O3Hs- zTwFGvu*!1%^`C6f`KciAs9NA1=nJ>B{{HF7KSIlEybx`}a_5)Z^wR^A5I8CxeXUb+ z!2aHT+ktm&`x2~)VjD|3Gen%w!x9g&| k1Rfsxe)OvwBmXZ5Ja#^RZW`mW>eT0+EI6ugK8r;E0#tmS_5c6? literal 0 HcmV?d00001 diff --git a/Notification Images/notification-green.png b/Notification Images/notification-green.png new file mode 100644 index 0000000000000000000000000000000000000000..5c6fddb54856f207472cd5dc67d86330f524cdf6 GIT binary patch literal 3702 zcmai%cTf}9+QvZ;j5L)h5WKbESq9*zZxcvI$HMtn(9`9i_|B5dK?cTm zm>1~TSS1A(G7*(@bnFZUP%X=_na$boFfP~V?p@#epmo9J*jRAlg~hOYjJm>07vxHW z$(ZZHQ97H~a}kyQ==0Dmdi zs+`f(J{Wyr!XO9Gf)_>X?YwI--=Fw7Q8m{v_h%Od>kWN}&nY{1Iqoj>Uz~rdSr7D` zF)E>Y%M(x3y;UFgG%2@mu)p+UU2m8XYUC>RP1Ry5_=iO!dGB zl+-*fZJ_KdiRxp3&8D2pCMXsE1#qW+M+)pyG$R&+!9I#7eiCs>5NS{7=W&>y*>*fC zna`v$eIBr6<=%4MlKyp=xxv~RQqFSbR=8{} zj~;W8tXyRE`O|Pq(*4HW8?$oe6(X82P~04P*hjc~W7-L4GjIVi48_@ZOAIYCw;mjA zL9I6KI!6Y}zlD@{+Araqa$UfTy?5EuvaSe^kH(7Qli;)WP4$GljJFmH#WFDtsg6Q(b9tSk6W zlE9m_JBMr$ncl0h2a*80aFNl7`$F7o?-qd1I#pjAR9w=!JCNi3XGhZH_bV8N0)gs# zC>xwuLT3pOtah%-M`ZVvDex$w1<#7Z(2aU{RwPlR%CRZJ;7Ar=$ z|7@{jAb6p^<_`Md^(TWGIbC@s=xZj2y@6f{HdK7!p~ohpK(jZ)yqNo<1gUp}SLk<- z1LbqP4*E;)v(4_G0wq#uxsH{Q8C>%YTfkt*I4Gj$YYRY(OQX$irQ7RvT=`=! zifFF2_lZt@=-0Iwt&7|^a0M+kg7iXsVTGegqpx&D0N@aE^+n`Xr_wj*-jI-~*Wv}b z5^%l%%|1Ytuk&S*DH%|S zM|K*a^&+^b*Q;zPwn_t0{$Nk(DMlSi@UcF=lL)I3IJF7A#2;{uE(TY$gcSfppscNr zsk62=0%7^bZQ-*gv%qq;R^tPQFIY@iz=TB#Q6t}z!F{K*5B|`}jQY&@-L5zYlF40F z@%aLA=a}f|Fc2(~t!sj$d3ZqWH2~k3>=`t#6?GCbGdE8t^Fyv}B z?`iU=g80tf(o2ylQvnqQmY0x1$G&Ug_LoCX!mg?M_<^jB3{{-F*2@ozGJoPot+8<5 z3KS1dKTjK>R*ToK`eWjm8!vzOJl7L4WXWf_zBKewZM1h8ap$vTSW>7zE4=LbL~QTn z?Os@h2aL}wbz(v($Bq`2I4?bqA8-v;vzk=zt_$fosKn8gW%ycK zCz_(Uv_f=P7$M1$+ay84d{5>~rdQ>oo^9Ws-5u~&d$wkmcf6}P8s12OpG=1&tD&iV z8Ss^qbu_`gp)Mfm!24RDOncGCH9LYATmo*Vh$hUdD^me^PouU9;E)fV^-UVK`JX+! zEmu3H*YTfYOrC!JEfImpzl1EA4B!t@cx}kva*cDq^kJc|qT^GCK?d&qW%_uh+QtB= zCi?})tMtmgQ`+{yz>Ekbjuk=Vs-&g&xX)Jmo|c9~OH!9Q;@d6kd|NyAs$zh!fR*pV z4ucb$dQ9xY8$G{YX6U8lcjvvQShsuw%Cv1ppCIwbrukmnhdbX{(j3!F2@@C1M_wIy ztT2_ef4o*DoK1`L4<87CDLRG?;e6z6)D>)i*AbBx-cA-r-q#2Q?tTLua|2Q9J~y05 zXh;8JB6CJoL08YNsK>FfsM7s9>nWENH!~F{@QSUZ$DR_l<%5qSNXODw=bajMV!JSZ zyzkP$2jYT;+QFiN)JawQZVwyWjm*udZ(@wJ@vX=V?C-YqYeu1zagBss($pa?DofgW zXrMdlrQ~p2+_+au_eY{1F{n|?e<5W+WTt?xrtx1j92auqNbHYv_g&CH=Nm__!O;LQ zmVSPN^~}yGHi30dWoU#v>*IM(*Uf{mL1b%Iq#b+HvxvRV$$Gt8;suWaF7FR)kcIRSE9%aLE6ux?|A zaJbvs|6Xy+6D%oPGafLLp3$rNnR!w9Ca%V&b@M&Xe*PpR8&X8Ob@n>T?VFJ)8$t2` zBYE>|aXUv(r5vrb-AtHr)kposn@g%n(O%s$hCCICWusG+2CI5M<404BF@wYuK_9)B z`)?@~bpflq%Zmp;By8*qcgIBTj;09OYCk#$Q9r#U)VyWJgb?h(#zcTZo}H$xWs8Zu z;ZZ>79TrNtIV+y;SaQ=laQ+Uw!CLx7SND}xD6d^Q2k)A#Ak6`=I)@w7xfCj7{DDP* zi}v|ea37y80@S&JkGhjiVRb{cb3e~85kQLf;;-pcE|X;2)ZfLZ?w|cnpV_X&QMj%l zjLNVdY&8F-Czxp)w@*(z>1RP@D&1U-@)d#$WO-*erV+cw^ZD#l630?3CE*$}Gm zCr_1TyXm>8U~bcSw&(CDy9!>ePB{pdPTUF0!UNfCYyi8pe7X{2~rXGY4y ze@r8ugt`tp6PYy1s?dK-Lfv2i*&9vTW<@(+%ZhBI3SrRQv0`>x+C$zcnNc^rMP9$9 zc&Q0)^_+BQkwU7|9}~c_ThytLVd;&sss3#4FH`1)hSQa-AwLxKch2vQ!Bc~^e>>_H zf0b7-;~JT0{a~{w!gu1m=?q8(wY^dAJ<4kq?P+lMV=evE^`@dyT6*Sft@zZgw#d@* z-_WfC%eSiX^XAmA^RJW7?h$DnGiAmh>x^>`TAVY2aTwUfgn(rVhjeagIkN*T)W;A~ zDhvA?&omR73x@b$IXV6xD)(t{LBzQb3NNu9MYOLJzjehasW2L`uU@>9=1Vh#$N{1$FE@8QMIj#A)oZ`Lb>Gs0)W5u|G~f+7@Q%&-+H!rw*GI0 zzu4hF3jd+}SI7S-|7GAGZ2U6t4}Jg1#{cU3%Z8_OkD!V{$J?3oqF6>X6~7Rl9=rIL zmZHXWvYLQWU49w-xDzS$sw2c_1i@;>Z1jJ`V`0>jTFq>vG@=iY_gmV+obV~v11X3z z*iamXcCcR(Dd9;60hvwg;#nX*GWw0hR2?x9V3?_x$i>`5Z84F-Q_vWDt&_s#0IxGb Oq%*i<0~rS)SUc{Xg%KBrC*KeQbVh~U*Z2vTiHVc{uV7}%{UFRJo(V89 zH#{@L%mui?8)#%D#ZX)@F}PzDG`>0s3$R*@=%B6V<(R!Qd9F8gRxKL zT((nv?@ek~k3X^+2D%s8Ror+=`JM0S(|CnHe~`TDn$dr#jMp_ST1`>?kqXF<=M_~P zKk?cFt~4#UzQbSwPqNKA31+9RT*0k_`?O=OsDTlOlZPSs%Q{4^=p--TWm0>=b>91( z1_H`_e`A!HL0EM61MUFGKWOekJ%D7ZP68 zB*ABfuHA+Jk|ko=?<)3k_J?b*NP7s6^6~MWKYtq+X+%UckYsoxK_S54`?s7?o*Kb&E z2l0jsN&&LUKs-VX(jj2hi|XfAFq@kJ_ZK#|N3d+-aX$tdE7Ul}W{ah$KVKwHPFm<5 zRQGkAhzHWh>}pU6FW{%*h*&r2E^m0)fM8s{+Z@o`X?`+jQ~F15lEDbS)UvX5mMLf> zI41bOPXm8q?=8Rc`H}FoYeLZa(V@5ZAD@98d_6>Q9nq^JOStQ^eP>wh!G^U8o&uE` z>1Pp%iona# zdzFjxM^jERK}hT|_h)W#Nk|(JLtj1T1gn$n+GjR`81SVXNeU#c+X-E>8AFjUb8t8| zI9u{tS%lVwVv*nnG3sz2{@Ay^j zABK$L$O|g5l!QTYD>+~eqVCZt+C9)}RjK|fJQO=uQsm0>d^LGJctsLWg(g8ZHfA{? zdcYEM=Ye!f)KHzFKSZ_7a|A^{TK%(Zzpn{e0K&|CN4w_jH^8I$%B-u}H-i0K-IQ-D zq&#*A|7N5ala-L5)MS6rUg4T^$7ZWSI6LmQDxpIhGsosu$Vjb?q7C;MgS%|O$QeNq zkNMVjtJ?U4OZdW!Df?h*mF6tnk7jK?wvK}`}D&$E@Ig;*m zzI(>|;NXE4eH<4wssargQ>JeEv$?x$z!ArQ#-q2Tza?EY2g=xOp z-tOrkmVEm3>DEvJBD97C)ou#77B}CnbVV1tT`vNKHldx3JhgjrbP+<2D*>Rs_;`-V zNH!YIIfYL%KxS9Yb`(P&_s%q2ddzlEU`#5^xAEBsQK4Bef!oK6FZWWy(d zo2#mx;Iloe7JrJ|jJ=@r2BEuaOWBQCSd8%4-2D6~5w7!%aNKyEh%A>qI^3Zt)Vk3+ z-o4w=MXy434eI@!a?69~xoV^=+h@0x-RVcTT~PE)F|nggjnt}3f=XKxYWvkk+!bxP zjb@rTM&|EadM;K{ub>AE-odx=Isp{N1HSl-sMjwayRDG|au3x$EJU%wWUfYKbQ3}1 zFlwg77mCSSE)aUt$xkUn)!U`zXkS44K!(YLoqcq1G5c^A+(8}FqETxru<5$bSWIAt z%D1FrIy;TKuV2sBc4pJur50><@(p`WnY9d+wgzbd%q%#$LboDF{K3{LX#YSav@2_y)LV-CHSwD&H#5t24`H~quDIx;KBI`jckbS<2nowE?I%ENW} z8~9r;XK&bt<@ikd>SrBB-&huU|9+B=W0ke5W&)pt+53?BBG*7o*=&fE_cyF(d~f$* zbt0KHC)jzi$|#acdV=9LzFDHf3eSzod-=PFfKk9eb==lH}*Ot-IT9hTxH5sE7vf7;G1F{SYeo}Sk` zygIQzyfSbU)+^dmELGXp=jMBtjiT!1L|W<%#Uhc%evuWn9rG61zDxDE)E=`P7+swP zJJ`tDo#K2e3yhqmlPx6)B1cW@J$a@t{FR64$9B3_AVI`q>vQS>GWg1d_(zNzF+o;I zgjU+TiHY$?$8LdmLHVMeqe|6Y2h!3voqt;GJhJNVA2ohu-kT$+X%jtzi5kO(*KdE! z%%{$8Q=kR)+2IaN*_!Uer3)>tAGo&#D?doAkLkZ9wDsO}hdjl;*x0whxN+SOl)F5> z%0}P_AvKm09qaq*gkFf4+a-1-*HXIPoF9kOdVPXV#84%g*mOI$HVSFnYhpIUynPr( zdi7Fia>KAkI3A^kzUjnXRB5Ws(;l+TXc|WrTf!eU8>!-+~}CH<sC`S?NGYtc*1h5CQJea_)bH5Y18=BUhQMNoutI7T8KyASq-io(>4!s2`zr&k| zR4|J^tVJ}7M;4vk8(~%qeBFjzh5HQ+v)o%-OPS`20N$1pZ>PRt;V3qH*3*+C{N#!4 z$T_5^v_&hwSZ}AuO_^hAZLLP>*y+=uzsM!FY98nO$kFU zf37{Hq`v6wBcfL1GvS5h1>g50glh6&9C?E!5P95qQGRX0sC8pji*~f7b&`(YJuf1H zn)?18yf@RLRqHExLYtSEzo?oRE_?k&V4{yhxHg!B6Y~Wbn_gmxaDe4|>AOXFPp&3x zTpaeUlUZm?2$zYrYjj+j+*#hCO^>dvba48J&(PnwCYDb|Ez<5CPl8poEKg>qOabr+i6j)Qf?nY+)%&;l3gw_M>;}St^-81~*0jaQ4@WrqFtsymzGPX9QLkkoGHqpMAq2aHvn?dayhW{ zSL?#!r$RoXoN10c0vEYaVuGk&q3w@l-w@7w(~rd0x_(k-he08Rb}K#^e}IMpPr{Q5 zV)*zN&R&xLZ)8|~M*gq1{~z8X@}p}UxGMyw3Tiy#yfVjMNE*q z5bGR5%D}6qLwZFM)1?av?mX6$Cy4hXC*X}u$it~3swlBdX&>*`#l<+c+=fg3`+gXf vS^vfY$6%hfW(Ezk9J9a1DaI=@?S(U68i%sM!^{~YAd`uqg+ZmB`$HJF{gof#FBPGc%1QMNqce(~zfHhJ& zS`qToa~3?2(NvrVG@h^R(e2{OSm99<%P@N=!QsSN&iwL8m1;gAL zX{xoou!|NWYh6fME15{c)D*XvU&v?e2VcZ18Hci6#XQAcQ13>iZL_|;dzhmdq52kf zI&r|GYr}NX!)x^s_I(vqsJQjsMf!A1dD5%cMZC}3n^UuLHuv$Z`_y^y>Vp5m^0b6e z7VsBWVU$KGb&VV3ehm3jUk-qHP1P2=T#)=7(%}lvX03`vl;ec9s$z;stbOJz#dv_2 zoMl%=uAdTDZeYQtHx2(=9+MRdMgzc<3xbZ>@Ojyh+@SdyRWGak+PHO#vm9{MmGWJW8{jazFvH znd~tY?Ww%EGcdsIUx<-(JY`>Yde!ckk-{C9>B^HJ#R}$@kUC!1{Ls!}*5&sQ>m*uN z0G$VQy?x*c*zK?yr{w}T04Y=*EK`5LR9~$?>^Cjx^x*WU>Y;R61w6~IE{BB-B)|;9 z7VsqjMLWppAKzj3(Z^ee9KNhI6L5K~AAIg-tVWGIV}q)eyt)#9zy^zyCyLue!yX5+!y zP*Lcu8@7n&2+^z);5tQ6sEG?kGqO!Qers32PC3n_C#ATY?8wGi~ zT|n=3mzm6EV`JJuZB_Z#UYnM(y^AG#_D8OwUOnd=1eEHfMYy?o84UddjR?3iunV!r zIA9Mb%wWZ!Yd5-t1o8&myf?OnO%nOy+&6$?PLz7Y*$*3D8p&_&Kg47rd0@ELhpT54 z^xh4x*$0Q2SXrN%n*-MyBx{2)TY(NjhoBQhiR>{x^r7Ke{gWj9e2j*EOF+fm_p;aX z9&ybr+EVUwQA--0h<67H@ljDAJgU*UD^u8{__j~ByMlfzyZ*dQ*v&|;vzJwa@j!U-m+fSs zA`Ls*4DBD6mL)p{U%_D3Lyw1?31Fa%^TQ-omRn*jx_^cB5BTDdI2!@M9q}rI0t5yx zo9{6-ZSqG0a+F3w-)^chr{<48DyynKQZYH-;aM$7P6k|Ec6lrcZEY#*!^46Ghq0S3 zAj<=SipaiNufy?%(=vEu*Exql<$QGFFlD|gZ-j>+q=H{dWg8D*|B_(0eJkneiUqSP z#W{U2o-1W?y$=9c@|X}pQ}#qAn~&@OiMoR4M>n1OT!3jP-1F}8*DQC7&#sDyHbM%jq@;K2 zFA4IrOy*QiufFC)ASmq7DM|uMnD|~6kdete`5t#BaQ}YcN*6;~4(?uoJex262y6;9 zABtzxh)+qWRpRrq#~<~nwO%q#f(ZN>LX#98&CQ)Y8-v0ZSS~%{_;4!ue}qCYrQ5ff zM3Z)Rb*O0w1@fy_QS%{tN~TqA8)v}@DJg?!|6?qI0%}VLKUnUF%99b2vhQd36S@@J zejnNE-cQckuqR#91I zRrVHIqL$d;iq!%+v}|qd8}sHZ?cAy$mXYboZH9DfKNDY#vANAR7CBer6b{TP{p_I` zFTk+~MMI}JSLg)eRqX|LVnE@>mx1j{(klCz`Vlto_h+k~NLaK<^+a0!g&0YHe?LjV z)ReTKeqe&EyBzq?isJnR2176;+_W_ZpHW_5(c@E}O6)9bF3!5Lh-1vm+ECtfkACg=2^rBMpJ;rg~ySa1zYV>(e@&egsmKAgf8 z_Txs$Z~Y>Mg2wsIZ@ z{q-m>-}tY=vSZ~8|9C@ZEo&pnSbO=Jdj-Q1hjU?vb7CKolONG@;+YZ1nE5W!CgBHo zJ`VY}E{Il!+{b6fN$i=^H5>c$Svm5_ZODgqxWjAZtD|l<&-so)e>eu`2q#=WKuR(S3ss*z zQ?}bYJ+EnKxDO&QR95m6btOwrU(d`c+8#}ReT8i+k$b37x?Lc`pa6`GcACWk*VpaU zQZ1W&u)9C9h@(SItuoYFKkO+a9o2@sASL#{qCL>7<&66((57w&>Hp++8D96tGhp#R zsVD242G4LH`EQEdIrshJ;pd1urY|P!(@SQYSU8WYOWnB>}&Z z1A}pti-(Tkqo$2FiIL>KIy&(J0s?<7`q+pVfv$nw!A{@n5f8$SlgP3~gXmiPVdLq1 zp9Y7K8ftydPEJwwKuV1`tbj}lO?U7U^>^S%Jm~UUX&IJ+XiBBd`<>L6# z5ixT`uZ~X~Ua(^xW!$oncgMxaDBq;)(r`PNLCRTQyh7Uub+G75ypzy%xeb*7*w+!Q z$W?2rTOI>o_Em^)&%$ty|3jK^-@-kSo%HvCBK|L#o#0mjuW-nuNz}mUqD!TIak9My zH1*d&qgPPWZ-m*R0;QL)F=(z0BfEp7SiZ8?i_M_Zews#;7boC4(eP`@M&l>)q0SfF z-W)(CMCYJEi;JTl@23-H#AB@EM4NN7tSq3SHZi&Y>w_7!Ff36qT3lzcLqLttli^5} zA_KOM!XR+sPiO-#kK{m2pJb?KSQX89EVRvfsZG6>l(R<>^xjcTv zqPM6`mX#pS#QmEgeo-1)u|3wczbXtC`q&DO7b8zGvksECe~KsYG4vfAy*!cIYq1S&-pnRp8k0{Xuw&MA_QAX zs=nfvQlxT3wd?36(5-X#d;I9pt7%_iD)r;al#`=uaWQl7KO9jEC|1f)-r`@_@&g&@ z?os(41Sq`RuKKydJWL<|2`A=;4$Q9YUOzElm<=r6jG-tLDjVxeEVU@}dsgFB8X3J4 zdDDHBnrl6Cqh)yid)r_AJ^r=Hv5iQ)csP$h3MuTAjcjR1^cfsmC9QKx0&0l;{`*_|>ziMXB>jXI1n(%^fS$Zlfs) zQ>CcsRfw*yV5`?CXZ2lRb#NMoxl+{n%ngPCr3bcGw@vdL$f%GX%3P>I@*$B3# xmpne?KC@?bjCRUP^hDk{nBaeD#~48XT$4R5t(2uICjP!ibhQjM8`SNh{sa5%#9IIW literal 0 HcmV?d00001 diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 7087784..7f7eb01 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -40,8 +40,8 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.1.2.2")] -[assembly: AssemblyFileVersion("0.1.2.2")] +[assembly: AssemblyVersion("0.1.2.3")] +[assembly: AssemblyFileVersion("0.1.2.3")] [assembly: NeutralResourcesLanguage("en")] diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs index 79a9fa1..e2b6aea 100644 --- a/Properties/Resources.Designer.cs +++ b/Properties/Resources.Designer.cs @@ -407,6 +407,16 @@ internal static System.Drawing.Bitmap check_for_updates { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap close_buttons { + get { + object obj = ResourceManager.GetObject("close_buttons", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// @@ -539,6 +549,36 @@ internal static string MainForm_InitializeComponent_Stop_Blocking { } } + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap notification_green { + get { + object obj = ResourceManager.GetObject("notification_green", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap notification_red { + get { + object obj = ResourceManager.GetObject("notification_red", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap notification_yellow { + get { + object obj = ResourceManager.GetObject("notification_yellow", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Looks up a localized string similar to Another instance is already running.. /// @@ -557,6 +597,33 @@ internal static string Program_Name { } } + /// + /// Looks up a localized string similar to Started blocking. + /// + internal static string ProgramStatus_GetStatus_Blocking_started { + get { + return ResourceManager.GetString("ProgramStatus_GetStatus_Blocking_started", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stopped blocking. + /// + internal static string ProgramStatus_GetStatus_Blocking_stopped { + get { + return ResourceManager.GetString("ProgramStatus_GetStatus_Blocking_stopped", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exception was thrown!. + /// + internal static string ProgramStatus_GetStatus_Exception_was_thrown_ { + get { + return ResourceManager.GetString("ProgramStatus_GetStatus_Exception_was_thrown_", resourceCulture); + } + } + /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// diff --git a/Properties/Resources.resx b/Properties/Resources.resx index e63121f..a631f74 100644 --- a/Properties/Resources.resx +++ b/Properties/Resources.resx @@ -313,4 +313,25 @@ Do you like to download latest version ({1})? ..\Icons\app_icon_turned-off.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\notification images\close.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Notification Images\notification-green.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Notification Images\notification-red.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Notification Images\notification-yellow.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + Exception was thrown! + + + Started blocking + + + Stopped blocking + \ No newline at end of file diff --git a/TeamViewerPopupBlocker.csproj b/TeamViewerPopupBlocker.csproj index 1f835b2..fc6e729 100644 --- a/TeamViewerPopupBlocker.csproj +++ b/TeamViewerPopupBlocker.csproj @@ -60,7 +60,7 @@ Icons\app_icon_default.ico - false + true Always @@ -71,6 +71,10 @@ TeamViewerPopupBlocker.Startup + + + false + @@ -80,6 +84,12 @@ + + + + + Form + Component @@ -146,6 +156,7 @@ Resources.resx + @@ -184,6 +195,10 @@ + + + +