using CefSharp; using CefSharp.WinForms; using System; using System.Drawing; using System.Windows.Forms; using TweetDuck.Configuration; using TweetDuck.Core.Bridge; using TweetDuck.Core.Controls; using TweetDuck.Core.Handling; using TweetDuck.Core.Handling.General; using TweetDuck.Core.Other.Analytics; using TweetDuck.Core.Utils; namespace TweetDuck.Core.Notification{ partial class FormNotificationBase : Form{ protected static int FontSizeLevel{ get{ switch(TweetDeckBridge.FontSize){ case "largest": return 4; case "large": return 3; case "small": return 1; case "smallest": return 0; default: return 2; } } } protected virtual Point PrimaryLocation{ get{ UserConfig config = Program.UserConfig; Screen screen; if (config.NotificationDisplay > 0 && config.NotificationDisplay <= Screen.AllScreens.Length){ screen = Screen.AllScreens[config.NotificationDisplay-1]; } else{ screen = Screen.FromControl(owner); } int edgeDist = config.NotificationEdgeDistance; switch(config.NotificationPosition){ case TweetNotification.Position.TopLeft: return new Point(screen.WorkingArea.X+edgeDist, screen.WorkingArea.Y+edgeDist); case TweetNotification.Position.TopRight: return new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width, screen.WorkingArea.Y+edgeDist); case TweetNotification.Position.BottomLeft: return new Point(screen.WorkingArea.X+edgeDist, screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height); case TweetNotification.Position.BottomRight: return new Point(screen.WorkingArea.X+screen.WorkingArea.Width-edgeDist-Width, screen.WorkingArea.Y+screen.WorkingArea.Height-edgeDist-Height); 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(); } return config.CustomNotificationPosition; } return Location; } } public bool IsNotificationVisible => Location != ControlExtensions.InvisibleLocation; protected virtual bool CanDragWindow => true; public new Point Location{ get{ return base.Location; } set{ Visible = (base.Location = value) != ControlExtensions.InvisibleLocation; FormBorderStyle = NotificationBorderStyle; } } protected virtual FormBorderStyle NotificationBorderStyle{ get{ if (WindowsUtils.ShouldAvoidToolWindow && Visible){ // Visible = workaround for alt+tab return FormBorderStyle.FixedSingle; } else{ return FormBorderStyle.FixedToolWindow; } } } protected override bool ShowWithoutActivation => true; protected float DpiScale { get; } protected double SizeScale => DpiScale*Program.UserConfig.ZoomLevel/100.0; protected readonly FormBrowser owner; protected readonly ChromiumWebBrowser browser; private readonly ResourceHandlerNotification resourceHandler = new ResourceHandlerNotification(); private TweetNotification currentNotification; private int pauseCounter; public string CurrentTweetUrl => currentNotification?.TweetUrl; public string CurrentQuoteUrl => currentNotification?.QuoteUrl; public bool CanViewDetail => currentNotification != null && !string.IsNullOrEmpty(currentNotification.ColumnId) && !string.IsNullOrEmpty(currentNotification.ChirpId); public bool IsPaused => pauseCounter > 0; protected bool IsCursorOverBrowser => browser.Bounds.Contains(PointToClient(Cursor.Position)); public bool FreezeTimer { get; set; } public bool ContextMenuOpen { get; set; } public event EventHandler Initialized; protected FormNotificationBase(FormBrowser owner, bool enableContextMenu){ InitializeComponent(); this.owner = owner; this.owner.FormClosed += owner_FormClosed; this.browser = new ChromiumWebBrowser("about:blank"){ MenuHandler = new ContextMenuNotification(this, enableContextMenu), JsDialogHandler = new JavaScriptDialogHandler(), LifeSpanHandler = new LifeSpanHandler(), RequestHandler = new RequestHandlerBase() }; this.browser.Dock = DockStyle.None; this.browser.ClientSize = ClientSize; this.browser.IsBrowserInitializedChanged += browser_IsBrowserInitializedChanged; #if DEBUG this.browser.ConsoleMessage += BrowserUtils.HandleConsoleMessage; #endif DpiScale = this.GetDPIScale(); DefaultResourceHandlerFactory handlerFactory = (DefaultResourceHandlerFactory)browser.ResourceHandlerFactory; handlerFactory.RegisterHandler(TwitterUtils.TweetDeckURL, this.resourceHandler); Controls.Add(browser); Disposed += (sender, args) => { this.browser.Dispose(); this.owner.FormClosed -= owner_FormClosed; }; // ReSharper disable once VirtualMemberCallInContructor UpdateTitle(); } protected override void WndProc(ref Message m){ if (m.Msg == 0x0112 && (m.WParam.ToInt32() & 0xFFF0) == 0xF010 && !CanDragWindow){ // WM_SYSCOMMAND, SC_MOVE return; } base.WndProc(ref m); } public void TriggerAnalyticsEvent(AnalyticsFile.Event e){ owner.TriggerAnalyticsEvent(e); } // event handlers private void owner_FormClosed(object sender, FormClosedEventArgs e){ Close(); } private void browser_IsBrowserInitializedChanged(object sender, IsBrowserInitializedChangedEventArgs e){ if (e.IsBrowserInitialized){ Initialized?.Invoke(this, EventArgs.Empty); } } // notification methods public virtual void HideNotification(){ browser.Load("about:blank"); Location = ControlExtensions.InvisibleLocation; currentNotification = null; } public virtual void FinishCurrentNotification(){} public virtual void PauseNotification(){ if (pauseCounter++ == 0 && IsNotificationVisible){ Location = ControlExtensions.InvisibleLocation; } } public virtual void ResumeNotification(){ if (pauseCounter > 0){ --pauseCounter; } } protected virtual string GetTweetHTML(TweetNotification tweet){ return tweet.GenerateHtml(IsCursorOverBrowser ? "td-hover" : string.Empty); } protected virtual void LoadTweet(TweetNotification tweet){ currentNotification = tweet; resourceHandler.SetHTML(GetTweetHTML(tweet)); browser.Load(TwitterUtils.TweetDeckURL); } protected virtual void SetNotificationSize(int width, int height){ browser.ClientSize = ClientSize = new Size(BrowserUtils.Scale(width, SizeScale), BrowserUtils.Scale(height, SizeScale)); } protected virtual void UpdateTitle(){ string title = currentNotification?.ColumnTitle; Text = string.IsNullOrEmpty(title) || !Program.UserConfig.DisplayNotificationColumn ? Program.BrandName : Program.BrandName+" - "+title; } public void ShowTweetDetail(){ owner.ShowTweetDetail(currentNotification.ColumnId, currentNotification.ChirpId, currentNotification.TweetUrl); } public void MoveToVisibleLocation(){ bool needsReactivating = Location == ControlExtensions.InvisibleLocation; Location = PrimaryLocation; if (needsReactivating){ NativeMethods.SetFormPos(this, NativeMethods.HWND_TOPMOST, NativeMethods.SWP_NOACTIVATE); } } public void DisplayTooltip(string text){ if (string.IsNullOrEmpty(text)){ toolTip.Hide(this); } else{ Point position = PointToClient(Cursor.Position); position.Offset(20, 5); toolTip.Show(text, this, position); } } } }