private static void Main() { Trace.Listeners.Add(new ReportListener()); Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; Application.ThreadException += Application_ThreadException; //todo: It's reccomended that this be set in the manifest, but I can't figure out how to do that successfully with clickonce Windowing.SetProcessDPIAware(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); System.Threading.Thread.CurrentThread.Name = "Main UI " + System.Threading.Thread.CurrentThread.ManagedThreadId; Update.CheckForUpdate(); History = new List <ExtendedScreenshot>(); Preview = new PeekPreview(); Selector = new RegionSelector(); Trace.WriteLine(string.Format("Forcing the creation of windows by accessing their handles on the Main UI thread: {0}, {1}", Preview.Handle, Selector.Handle), string.Format("Program [{0}]", System.Threading.Thread.CurrentThread.Name)); KeyboardHook = new Hook("Global Action Hook"); KeyboardHook.KeyDownEvent += KeyDown; KeyboardHook.KeyUpEvent += KeyUp; TrayIcon = new NotifyIcon() { Icon = ProSnap.Properties.Resources.camera_36x36_icon, Text = "ProSnap", Visible = true, ContextMenuStrip = new ContextMenuStrip() }; //TrayIcon.ContextMenuStrip.Items.Add("Take Screenshot", null, new EventHandler((o, e) => { Thread.Sleep(3000); SpawnActionChain(ActiveShortcutProfile.Shortcuts.FirstOrDefault(s => s.Actions.ActionItems.FirstOrDefault().ActionType == ActionTypes.TakeForegroundScreenshot)); })); TrayIcon.ContextMenuStrip.Items.Add(new ToolStripMenuItem("History", null, (o, e) => (o as ToolStripMenuItem).ShowDropDown()) { Name = "tsmiHistory" }); TrayIcon.ContextMenuStrip.Items.Add("Options", null, (o, e) => Options.Options.ShowOrActivate()); TrayIcon.ContextMenuStrip.Items.Add("Exit", null, (o, e) => { Application.Exit(); DumpTraceReport(); }); TrayIcon.MouseDown += TrayIcon_MouseDown; IconAnimation.WorkerSupportsCancellation = true; IconAnimation.DoWork += IconAnimation_DoWork; Application.Run(); KeyboardHook.isPaused = true; TrayIcon.Visible = false; }
private static void Main() { Trace.Listeners.Add(new ReportListener()); Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; Application.ThreadException += Application_ThreadException; //todo: It's reccomended that this be set in the manifest, but I can't figure out how to do that successfully with clickonce Windowing.SetProcessDPIAware(); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); System.Threading.Thread.CurrentThread.Name = "Main UI " + System.Threading.Thread.CurrentThread.ManagedThreadId; Update.CheckForUpdate(); History = new List<ExtendedScreenshot>(); Preview = new PeekPreview(); Selector = new RegionSelector(); Trace.WriteLine(string.Format("Forcing the creation of windows by accessing their handles on the Main UI thread: {0}, {1}", Preview.Handle, Selector.Handle), string.Format("Program [{0}]", System.Threading.Thread.CurrentThread.Name)); KeyboardHook = new Hook("Global Action Hook"); KeyboardHook.KeyDownEvent += KeyDown; KeyboardHook.KeyUpEvent += KeyUp; TrayIcon = new NotifyIcon() { Icon = ProSnap.Properties.Resources.camera_36x36_icon, Text = "ProSnap", Visible = true, ContextMenuStrip = new ContextMenuStrip() }; //TrayIcon.ContextMenuStrip.Items.Add("Take Screenshot", null, new EventHandler((o, e) => { Thread.Sleep(3000); SpawnActionChain(ActiveShortcutProfile.Shortcuts.FirstOrDefault(s => s.Actions.ActionItems.FirstOrDefault().ActionType == ActionTypes.TakeForegroundScreenshot)); })); TrayIcon.ContextMenuStrip.Items.Add(new ToolStripMenuItem("History", null, (o, e) => (o as ToolStripMenuItem).ShowDropDown()) { Name = "tsmiHistory" }); TrayIcon.ContextMenuStrip.Items.Add("Options", null, (o, e) => Options.Options.ShowOrActivate()); TrayIcon.ContextMenuStrip.Items.Add("Exit", null, (o, e) => { Application.Exit(); DumpTraceReport(); }); TrayIcon.MouseDown += TrayIcon_MouseDown; IconAnimation.WorkerSupportsCancellation = true; IconAnimation.DoWork += IconAnimation_DoWork; Application.Run(); KeyboardHook.isPaused = true; TrayIcon.Visible = false; }
private static void Program_ShowPreviewEvent(ExtendedScreenshot s, PreviewEventArgs e) { if (Preview.InvokeRequired) { Trace.WriteLine("Self invoking...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); Preview.BeginInvoke(new MethodInvoker(() => Program_ShowPreviewEvent(s, e))); return; } //It is much easier to simply invoke onto the preview thread for actions which have UI ramification, rather than managing cross thread status updates //Currently there are only a couple actions this really makes sense for: Heart, Save, Upload, Delete (because it potentially also hides the form) //Save doesn't really have a UI change, but doing it on the UI thread means the SFD is positioned correctly //The locking scheme is so that dispatched operations block the action thread until complete //So for example, an action chain with Upload followed by Run can use the uploaded image url as a parameter for itself if (s != null) { Trace.WriteLine("Loading preview screenshot...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); Preview.LoadScreenshot(s); } if (e.ActionItem == null) { Trace.WriteLine("Showing preview...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); Preview.Show(); } if (e.ActionItem is HeartAction) { Trace.WriteLine("Applying HeartAction...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); lock (_actionlock) { switch ((e.ActionItem as HeartAction).HeartMode) { case HeartAction.Modes.Toggle: s.isFlagged = !s.isFlagged; break; case HeartAction.Modes.On: s.isFlagged = true; break; case HeartAction.Modes.Off: s.isFlagged = false; break; } Preview.UpdateHeart(); Monitor.Pulse(_actionlock); } } if (e.ActionItem is SaveAction) { Trace.WriteLine("Applying SaveAction...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); Preview.SaveComplete += (ss, se) => { lock (_actionlock) Monitor.Pulse(_actionlock); }; lock (_actionlock) Preview.Save(); } if (e.ActionItem is UploadAction) { Trace.WriteLine("Applying UploadAction...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); Preview.UploadComplete += (us, ue) => { lock (_actionlock) Monitor.Pulse(_actionlock); }; lock (_actionlock) Preview.Upload(); } if (e.ActionItem is DeleteAction) { Trace.WriteLine("Applying DeleteAction...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); lock (_actionlock) { Preview.Delete(); Monitor.Pulse(_actionlock); } } if (e.ActionItem is HidePreviewAction) { Trace.WriteLine("Applying HidePreviewAction...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); lock (_actionlock) { Preview.FadeClose(); Monitor.Pulse(_actionlock); } } if (e.ActionItem is TakeRegionScreenshotAction) { Trace.WriteLine("Opening region selector...", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); var rs = new RegionSelector(); rs.FormClosed += (ss, se) => { Trace.WriteLine("Closed region selector.", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); lock (_actionlock) { e.Result = rs.DialogResult == DialogResult.OK ? rs.SnapshotRectangle : Rectangle.Empty; Monitor.Pulse(_actionlock); } }; lock (_actionlock) rs.Show(); } Trace.WriteLine("Done.", string.Format("Program.Program_ShowPreviewEvent [{0}]", Thread.CurrentThread.Name)); }