using System; using System.Collections.Generic; using System.Drawing; using System.Windows.Forms; using CefSharp; using CefSharp.WinForms; using TweetDck.Configuration; using TweetDck.Core.Handling; using TweetDck.Resources; namespace TweetDck.Core{ sealed partial class FormNotification : Form{ public Func<bool> CanMoveWindow = () => true; private readonly Form owner; private readonly ChromiumWebBrowser browser; private readonly Queue<TweetNotification> tweetQueue = new Queue<TweetNotification>(4); private readonly bool autoHide; private int timeLeft, totalTime; private readonly string notificationJS; public FormNotification(Form owner, TweetDeckBridge bridge, bool autoHide){ InitializeComponent(); Text = Program.BrandName; this.owner = owner; this.autoHide = autoHide; owner.FormClosed += (sender, args) => Close(); notificationJS = ScriptLoader.LoadResource("notification.js"); browser = new ChromiumWebBrowser("about:blank"){ MenuHandler = new MenuHandlerEmpty() }; browser.FrameLoadEnd += Browser_FrameLoadEnd; if (bridge != null){ browser.RegisterJsObject("$TD",bridge); } panelBrowser.Controls.Add(browser); Disposed += (sender, args) => browser.Dispose(); } public FormNotification(Form owner, bool autoHide) : this(owner,null,autoHide){} private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){ if (e.Frame.IsMain && notificationJS != null){ browser.ExecuteScriptAsync(notificationJS); } } protected override void WndProc(ref Message m){ if (m.Msg == 0x0112 && (m.WParam.ToInt32() & 0xFFF0) == 0xF010 && !CanMoveWindow()){ // WM_SYSCOMMAND, SC_MOVE return; } base.WndProc(ref m); } public void ShowNotification(TweetNotification notification){ MoveToVisibleLocation(); tweetQueue.Enqueue(notification); if (!timerProgress.Enabled){ LoadNextNotification(); } } public void ShowNotificationForSettings(bool resetAnimation){ if (browser.Address == "about:blank"){ browser.Load("about:blank"); // required, otherwise shit breaks browser.LoadHtml(TweetNotification.ExampleTweet.GenerateHtml(),"http://tweetdeck.twitter.com/"); resetAnimation = true; } if (resetAnimation){ totalTime = timeLeft = TweetNotification.ExampleTweet.GetDisplayDuration(Program.UserConfig.NotificationDuration); timerProgress.Start(); } MoveToVisibleLocation(); } public void HideNotification(){ browser.LoadHtml("","about:blank"); Location = new Point(-32000,-32000); TopMost = false; timerProgress.Stop(); } private void LoadNextNotification(){ TweetNotification tweet = tweetQueue.Dequeue(); if (browser.Address == "about:blank"){ browser.Load("about:blank"); // required, otherwise shit breaks } browser.LoadHtml(tweet.GenerateHtml(),"http://tweetdeck.twitter.com/"); totalTime = timeLeft = tweet.GetDisplayDuration(Program.UserConfig.NotificationDuration); timerProgress.Stop(); timerProgress.Start(); } private void MoveToVisibleLocation(){ UserConfig config = Program.UserConfig; Screen screen = Screen.FromControl(owner); if (config.NotificationDisplay > 0 && config.NotificationDisplay <= Screen.AllScreens.Length){ screen = Screen.AllScreens[config.NotificationDisplay-1]; } int edgeDist = config.NotificationEdgeDistance; switch(config.NotificationPosition){ case TweetNotification.Position.TopLeft: Location = new Point(screen.WorkingArea.X+edgeDist,screen.WorkingArea.Y+edgeDist); break; case TweetNotification.Position.TopRight: Location = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width,screen.WorkingArea.Y+edgeDist); break; case TweetNotification.Position.BottomLeft: Location = new Point(screen.WorkingArea.X+edgeDist,screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height); break; case TweetNotification.Position.BottomRight: Location = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width,screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height); break; case TweetNotification.Position.Custom: if (!config.IsCustomNotificationPositionSet){ config.CustomNotificationPosition = new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width,screen.WorkingArea.Y+edgeDist); config.Save(); } Location = config.CustomNotificationPosition; break; } TopMost = true; } private void timerHideProgress_Tick(object sender, EventArgs e){ if (Bounds.Contains(Cursor.Position))return; timeLeft -= timerProgress.Interval; progressBarTimer.SetValueInstant((int)Math.Min(1000,Math.Round(1050.0*(totalTime-timeLeft)/totalTime))); if (timeLeft <= 0){ if (tweetQueue.Count > 0){ LoadNextNotification(); } else if (autoHide){ HideNotification(); } } } private void FormNotification_FormClosing(object sender, FormClosingEventArgs e){ if (e.CloseReason == CloseReason.UserClosing){ HideNotification(); tweetQueue.Clear(); e.Cancel = true; } } private class MenuHandlerEmpty : IContextMenuHandler{ public void OnBeforeContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model){ model.Clear(); } public bool OnContextMenuCommand(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, CefMenuCommand commandId, CefEventFlags eventFlags){ return false; } public void OnContextMenuDismissed(IWebBrowser browserControl, IBrowser browser, IFrame frame){} public bool RunContextMenu(IWebBrowser browserControl, IBrowser browser, IFrame frame, IContextMenuParams parameters, IMenuModel model, IRunContextMenuCallback callback){ return false; } } } }