using System; using System.Windows.Forms; using CefSharp; using CefSharp.WinForms; using TweetDck.Configuration; using TweetDck.Core.Handling; using TweetDck.Core.Other; using TweetDck.Resources; using TweetDck.Core.Controls; using System.Drawing; using TweetDck.Core.Utils; using TweetDck.Core.Utils.Notification; using TweetDck.Updates; using TweetDck.Plugins; using TweetDck.Plugins.Enums; using TweetDck.Plugins.Events; namespace TweetDck.Core{ sealed partial class FormBrowser : Form{ private static UserConfig Config{ get{ return Program.UserConfig; } } public string UpdateInstallerPath { get; private set; } private readonly ChromiumWebBrowser browser; private readonly PluginManager plugins; private readonly UpdateHandler updates; private readonly FormNotification notification; private FormSettings currentFormSettings; private FormAbout currentFormAbout; private FormPlugins currentFormPlugins; private bool isLoaded; private FormWindowState prevState; public FormBrowser(PluginManager pluginManager, UpdaterSettings updaterSettings){ InitializeComponent(); Text = Program.BrandName; this.plugins = pluginManager; this.plugins.Reloaded += plugins_Reloaded; this.plugins.PluginChangedState += plugins_PluginChangedState; this.notification = CreateNotificationForm(NotificationFlags.AutoHide | NotificationFlags.TopMost); this.notification.CanMoveWindow = () => false; this.notification.Show(); this.browser = new ChromiumWebBrowser("https://tweetdeck.twitter.com/"){ MenuHandler = new ContextMenuBrowser(this), DialogHandler = new DialogHandlerBrowser(this), LifeSpanHandler = new LifeSpanHandler() }; #if DEBUG this.browser.ConsoleMessage += BrowserUtils.HandleConsoleMessage; #endif this.browser.LoadingStateChanged += Browser_LoadingStateChanged; this.browser.FrameLoadEnd += Browser_FrameLoadEnd; this.browser.RegisterJsObject("$TD", new TweetDeckBridge(this, notification)); this.browser.RegisterAsyncJsObject("$TDP", plugins.Bridge); Controls.Add(browser); Disposed += (sender, args) => browser.Dispose(); this.trayIcon.ClickRestore += trayIcon_ClickRestore; this.trayIcon.ClickClose += trayIcon_ClickClose; Config.TrayBehaviorChanged += Config_TrayBehaviorChanged; UpdateTrayIcon(); this.updates = new UpdateHandler(browser, this, updaterSettings); this.updates.UpdateAccepted += updates_UpdateAccepted; } private void ShowChildForm(Form form){ form.Show(this); form.Shown += (sender, args) => form.MoveToCenter(this); } public void ForceClose(){ trayIcon.Visible = false; // checked in FormClosing event Close(); } public FormNotification CreateNotificationForm(NotificationFlags flags){ return new FormNotification(this, plugins, flags); } // window setup private void SetupWindow(){ Config.BrowserWindow.Restore(this, true); prevState = WindowState; isLoaded = true; } private void UpdateTrayIcon(){ trayIcon.Visible = Config.TrayBehavior.ShouldDisplayIcon(); } // active event handlers private void Browser_LoadingStateChanged(object sender, LoadingStateChangedEventArgs e){ if (!e.IsLoading){ browser.AddWordToDictionary("tweetdeck"); browser.AddWordToDictionary("TweetDeck"); browser.AddWordToDictionary("tweetduck"); browser.AddWordToDictionary("TweetDuck"); browser.AddWordToDictionary("TD"); Invoke(new Action(SetupWindow)); browser.LoadingStateChanged -= Browser_LoadingStateChanged; } } private void Browser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e){ if (e.Frame.IsMain && BrowserUtils.IsTweetDeckWebsite(e.Frame)){ ScriptLoader.ExecuteFile(e.Frame, "code.js"); if (plugins.HasAnyPlugin(PluginEnvironment.Browser)){ ScriptLoader.ExecuteFile(e.Frame, PluginManager.PluginBrowserScriptFile); ScriptLoader.ExecuteFile(e.Frame, PluginManager.PluginGlobalScriptFile); plugins.ExecutePlugins(e.Frame, PluginEnvironment.Browser, true); } } } private void FormBrowser_Activated(object sender, EventArgs e){ if (!isLoaded)return; trayIcon.HasNotifications = false; } private void FormBrowser_Resize(object sender, EventArgs e){ if (!isLoaded)return; if (WindowState != prevState){ prevState = WindowState; if (WindowState == FormWindowState.Minimized){ if (Config.TrayBehavior.ShouldHideOnMinimize()){ Hide(); // hides taskbar too?! welp that works I guess } } else{ FormBrowser_ResizeEnd(sender, e); } } } private void FormBrowser_ResizeEnd(object sender, EventArgs e){ // also triggers when the window moves if (!isLoaded)return; if (Location.X != -32000){ Config.BrowserWindow.Save(this); Config.Save(); } } private void FormBrowser_FormClosing(object sender, FormClosingEventArgs e){ if (!isLoaded)return; if (Config.TrayBehavior.ShouldHideOnClose() && trayIcon.Visible && e.CloseReason == CloseReason.UserClosing){ Hide(); // hides taskbar too?! welp that works I guess e.Cancel = true; } } private void Config_TrayBehaviorChanged(object sender, EventArgs e){ if (!isLoaded)return; UpdateTrayIcon(); } private void trayIcon_ClickRestore(object sender, EventArgs e){ if (!isLoaded)return; isLoaded = false; Show(); SetupWindow(); Activate(); UpdateTrayIcon(); } private void trayIcon_ClickClose(object sender, EventArgs e){ if (!isLoaded)return; ForceClose(); } private void plugins_Reloaded(object sender, PluginLoadEventArgs e){ ReloadBrowser(); } private void plugins_PluginChangedState(object sender, PluginChangedStateEventArgs e){ browser.ExecuteScriptAsync("window.TDPF_setPluginState", e.Plugin, e.IsEnabled ? 1 : 0); // ExecuteScriptAsync cannot handle boolean values as of yet } private void updates_UpdateAccepted(object sender, UpdateAcceptedEventArgs e){ Hide(); FormUpdateDownload downloadForm = new FormUpdateDownload(e.UpdateInfo); downloadForm.MoveToCenter(this); downloadForm.ShowDialog(); if (downloadForm.UpdateStatus == FormUpdateDownload.Status.Succeeded){ UpdateInstallerPath = downloadForm.InstallerPath; ForceClose(); } else if (downloadForm.UpdateStatus == FormUpdateDownload.Status.Manual){ ForceClose(); } else{ Show(); } } protected override void WndProc(ref Message m){ if (isLoaded && m.Msg == Program.WindowRestoreMessage){ trayIcon_ClickRestore(trayIcon, new EventArgs()); return; } if (isLoaded && m.Msg == 0x210 && (m.WParam.ToInt32() & 0xFFFF) == 0x020B){ // WM_PARENTNOTIFY, WM_XBUTTONDOWN browser.ExecuteScriptAsync("TDGF_onMouseClickExtra", (m.WParam.ToInt32() >> 16) & 0xFFFF); return; } base.WndProc(ref m); } // callback handlers public void OpenSettings(){ if (currentFormSettings != null){ currentFormSettings.BringToFront(); } else{ bool prevEnableUpdateCheck = Config.EnableUpdateCheck; currentFormSettings = new FormSettings(this, plugins, updates); currentFormSettings.FormClosed += (sender, args) => { currentFormSettings = null; if (!prevEnableUpdateCheck && Config.EnableUpdateCheck){ Config.DismissedUpdate = string.Empty; Config.Save(); updates.Check(false); } if (!Config.EnableTrayHighlight){ trayIcon.HasNotifications = false; } }; ShowChildForm(currentFormSettings); } } public void OpenAbout(){ if (currentFormAbout != null){ currentFormAbout.BringToFront(); } else{ currentFormAbout = new FormAbout(); currentFormAbout.FormClosed += (sender, args) => currentFormAbout = null; ShowChildForm(currentFormAbout); } } public void OpenPlugins(){ if (currentFormPlugins != null){ currentFormPlugins.BringToFront(); } else{ currentFormPlugins = new FormPlugins(plugins); currentFormPlugins.FormClosed += (sender, args) => currentFormPlugins = null; ShowChildForm(currentFormPlugins); } } public void OnTweetNotification(){ if (Config.EnableTrayHighlight && !ContainsFocus){ trayIcon.HasNotifications = true; } } public void OnTweetScreenshotReady(string html, int width, int height){ FormNotification dummyWindow = CreateNotificationForm(NotificationFlags.DisableScripts | NotificationFlags.DisableContextMenu | NotificationFlags.TopMost); dummyWindow.ShowNotificationForScreenshot(new TweetNotification(html, string.Empty, 0), width, height, () => { Point? prevNotificationLocation = null; bool prevFreezeTimer = false; if (notification.IsNotificationVisible){ prevNotificationLocation = notification.Location; prevFreezeTimer = notification.FreezeTimer; notification.Location = new Point(-32000, -32000); notification.FreezeTimer = true; } dummyWindow.TakeScreenshot(); dummyWindow.Hide(); dummyWindow.Close(); // dummyWindow.Dispose(); // TODO something freezes the program sometimes if (prevNotificationLocation.HasValue){ notification.Location = prevNotificationLocation.Value; notification.FreezeTimer = prevFreezeTimer; } }); dummyWindow.CanMoveWindow = () => false; dummyWindow.Show(); } public void DisplayTooltip(string text){ if (string.IsNullOrEmpty(text)){ toolTip.Hide(this); } else{ Point position = PointToClient(Cursor.Position); position.Offset(20, 10); toolTip.Show(text, this, position); } } public void OnImagePasted(){ browser.ExecuteScriptAsync("TDGF_tryPasteImage()"); } public void OnImagePastedFinish(){ browser.ExecuteScriptAsync("TDGF_tryPasteImageFinish()"); } public void TriggerTweetScreenshot(){ browser.ExecuteScriptAsync("TDGF_triggerScreenshot()"); } public void ReloadBrowser(){ browser.ExecuteScriptAsync("window.location.reload()"); } } }